Merge branch 'use_libosmium_2_5_4' into develop
This commit is contained in:
		
						commit
						5341cb5ff9
					
				| @ -36,7 +36,6 @@ option(BUILD_TOOLS "Build OSRM tools" OFF) | |||||||
| include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR}/include/) | include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR}/include/) | ||||||
| include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/include/) | include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/include/) | ||||||
| include_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/third_party/) | include_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/third_party/) | ||||||
| include_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/third_party/libosmium/include/) |  | ||||||
| 
 | 
 | ||||||
| add_custom_target(FingerPrintConfigure ALL ${CMAKE_COMMAND} | add_custom_target(FingerPrintConfigure ALL ${CMAKE_COMMAND} | ||||||
|   "-DOUTPUT_DIR=${CMAKE_CURRENT_BINARY_DIR}" |   "-DOUTPUT_DIR=${CMAKE_CURRENT_BINARY_DIR}" | ||||||
| @ -226,7 +225,14 @@ if(UNIX AND NOT APPLE) | |||||||
|   target_link_libraries(engine-tests rt) |   target_link_libraries(engine-tests rt) | ||||||
| endif() | endif() | ||||||
| 
 | 
 | ||||||
| #Check Boost | list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/third_party/libosmium/cmake") | ||||||
|  | set(OSMIUM_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/libosmium/include") | ||||||
|  | find_package(Osmium REQUIRED COMPONENTS io) | ||||||
|  | include_directories(SYSTEM ${OSMIUM_INCLUDE_DIRS}) | ||||||
|  | 
 | ||||||
|  | target_link_libraries(osrm-extract ${OSMIUM_LIBRARIES}) | ||||||
|  | target_link_libraries(extractor-tests ${OSMIUM_LIBRARIES}) | ||||||
|  | 
 | ||||||
| find_package(Boost 1.49.0 COMPONENTS ${BOOST_COMPONENTS} REQUIRED) | find_package(Boost 1.49.0 COMPONENTS ${BOOST_COMPONENTS} REQUIRED) | ||||||
| if(NOT Boost_FOUND) | if(NOT Boost_FOUND) | ||||||
|   message(FATAL_ERROR "Fatal error: Boost (version >= 1.49.0) required.\n") |   message(FATAL_ERROR "Fatal error: Boost (version >= 1.49.0) required.\n") | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| #!/usr/bin/env bash | #!/usr/bin/env bash | ||||||
| 
 | 
 | ||||||
| OSMIUM_REPO=https://github.com/osmcode/libosmium.git | OSMIUM_REPO=https://github.com/osmcode/libosmium.git | ||||||
| OSMIUM_TAG=v2.3.0 | OSMIUM_TAG=v2.5.4 | ||||||
| 
 | 
 | ||||||
| VARIANT_REPO=https://github.com/mapbox/variant.git | VARIANT_REPO=https://github.com/mapbox/variant.git | ||||||
| VARIANT_TAG=v1.0 | VARIANT_TAG=v1.0 | ||||||
|  | |||||||
							
								
								
									
										179
									
								
								third_party/libosmium/.travis.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										179
									
								
								third_party/libosmium/.travis.yml
									
									
									
									
										vendored
									
									
								
							| @ -9,46 +9,151 @@ language: cpp | |||||||
| sudo: false | sudo: false | ||||||
| 
 | 
 | ||||||
| matrix: | matrix: | ||||||
|     include: |   include: | ||||||
|         - os: linux | 
 | ||||||
|           compiler: clang |     # 1/ Linux Clang Builds | ||||||
|           env: BUILD_TYPE=Dev |     - os: linux | ||||||
|         - os: linux |       compiler: clang | ||||||
|           compiler: clang |       addons: | ||||||
|           env: BUILD_TYPE=Release |         apt: | ||||||
|         - os: linux |           sources: ['llvm-toolchain-precise-3.5', 'ubuntu-toolchain-r-test', 'boost-latest'] | ||||||
|           compiler: gcc |           packages: ['clang-3.5', 'libboost1.55-all-dev', 'libgdal-dev', 'libgeos++-dev', 'libproj-dev', 'libsparsehash-dev', 'spatialite-bin'] | ||||||
|           env: BUILD_TYPE=Dev |       env: COMPILER='clang++-3.5' BUILD_TYPE='Release' | ||||||
|         - os: linux | 
 | ||||||
|           compiler: gcc |     - os: linux | ||||||
|           env: BUILD_TYPE=Release |       compiler: clang | ||||||
|         - os: osx |       addons: | ||||||
|           compiler: clang |         apt: | ||||||
|           env: BUILD_TYPE=Dev |           sources: ['llvm-toolchain-precise-3.5', 'ubuntu-toolchain-r-test', 'boost-latest'] | ||||||
|         - os: osx |           packages: ['clang-3.5', 'libboost1.55-all-dev', 'libgdal-dev', 'libgeos++-dev', 'libproj-dev', 'libsparsehash-dev', 'spatialite-bin'] | ||||||
|           compiler: clang |       env: COMPILER='clang++-3.5' BUILD_TYPE='Dev' | ||||||
|           env: BUILD_TYPE=Release | 
 | ||||||
|  | 
 | ||||||
|  |     - os: linux | ||||||
|  |       compiler: clang | ||||||
|  |       addons: | ||||||
|  |         apt: | ||||||
|  |           sources: ['llvm-toolchain-precise-3.6', 'ubuntu-toolchain-r-test', 'boost-latest'] | ||||||
|  |           packages: ['clang-3.6', 'libboost1.55-all-dev', 'libgdal-dev', 'libgeos++-dev', 'libproj-dev', 'libsparsehash-dev', 'spatialite-bin'] | ||||||
|  |       env: COMPILER='clang++-3.6' BUILD_TYPE='Release' | ||||||
|  | 
 | ||||||
|  |     - os: linux | ||||||
|  |       compiler: clang | ||||||
|  |       addons: | ||||||
|  |         apt: | ||||||
|  |           sources: ['llvm-toolchain-precise-3.6', 'ubuntu-toolchain-r-test', 'boost-latest'] | ||||||
|  |           packages: ['clang-3.6', 'libboost1.55-all-dev', 'libgdal-dev', 'libgeos++-dev', 'libproj-dev', 'libsparsehash-dev', 'spatialite-bin'] | ||||||
|  |       env: COMPILER='clang++-3.6' BUILD_TYPE='Dev' | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     - os: linux | ||||||
|  |       compiler: clang | ||||||
|  |       addons: | ||||||
|  |         apt: | ||||||
|  |           sources: ['llvm-toolchain-precise-3.7', 'ubuntu-toolchain-r-test', 'boost-latest'] | ||||||
|  |           packages: ['clang-3.7', 'libboost1.55-all-dev', 'libgdal-dev', 'libgeos++-dev', 'libproj-dev', 'libsparsehash-dev', 'spatialite-bin'] | ||||||
|  |       env: COMPILER='clang++-3.7' BUILD_TYPE='Release' | ||||||
|  | 
 | ||||||
|  |     - os: linux | ||||||
|  |       compiler: clang | ||||||
|  |       addons: | ||||||
|  |         apt: | ||||||
|  |           sources: ['llvm-toolchain-precise-3.7', 'ubuntu-toolchain-r-test', 'boost-latest'] | ||||||
|  |           packages: ['clang-3.7', 'libboost1.55-all-dev', 'libgdal-dev', 'libgeos++-dev', 'libproj-dev', 'libsparsehash-dev', 'spatialite-bin'] | ||||||
|  |       env: COMPILER='clang++-3.7' BUILD_TYPE='Dev' | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     # 2/ Linux GCC Builds | ||||||
|  |     - os: linux | ||||||
|  |       compiler: gcc | ||||||
|  |       addons: | ||||||
|  |         apt: | ||||||
|  |           sources: ['ubuntu-toolchain-r-test', 'boost-latest'] | ||||||
|  |           packages: ['g++-4.8', 'libboost1.55-all-dev', 'libgdal-dev', 'libgeos++-dev', 'libproj-dev', 'libsparsehash-dev', 'spatialite-bin'] | ||||||
|  |       env: COMPILER='g++-4.8' COMPILER_FLAGS='-Wno-return-type' BUILD_TYPE='Release' | ||||||
|  | 
 | ||||||
|  |     - os: linux | ||||||
|  |       compiler: gcc | ||||||
|  |       addons: | ||||||
|  |         apt: | ||||||
|  |           sources: ['ubuntu-toolchain-r-test', 'boost-latest'] | ||||||
|  |           packages: ['g++-4.8', 'libboost1.55-all-dev', 'libgdal-dev', 'libgeos++-dev', 'libproj-dev', 'libsparsehash-dev', 'spatialite-bin'] | ||||||
|  |       env: COMPILER='g++-4.8' COMPILER_FLAGS='-Wno-return-type' BUILD_TYPE='Dev' | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     - os: linux | ||||||
|  |       compiler: gcc | ||||||
|  |       addons: | ||||||
|  |         apt: | ||||||
|  |           sources: ['ubuntu-toolchain-r-test', 'boost-latest'] | ||||||
|  |           packages: ['g++-4.9', 'libboost1.55-all-dev', 'libgdal-dev', 'libgeos++-dev', 'libproj-dev', 'libsparsehash-dev', 'spatialite-bin'] | ||||||
|  |       env: COMPILER='g++-4.9' BUILD_TYPE='Release' | ||||||
|  | 
 | ||||||
|  |     - os: linux | ||||||
|  |       compiler: gcc | ||||||
|  |       addons: | ||||||
|  |         apt: | ||||||
|  |           sources: ['ubuntu-toolchain-r-test', 'boost-latest'] | ||||||
|  |           packages: ['g++-4.9', 'libboost1.55-all-dev', 'libgdal-dev', 'libgeos++-dev', 'libproj-dev', 'libsparsehash-dev', 'spatialite-bin'] | ||||||
|  |       env: COMPILER='g++-4.9' BUILD_TYPE='Dev' | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     - os: linux | ||||||
|  |       compiler: gcc | ||||||
|  |       addons: | ||||||
|  |         apt: | ||||||
|  |           sources: ['ubuntu-toolchain-r-test', 'boost-latest'] | ||||||
|  |           packages: ['g++-5', 'libboost1.55-all-dev', 'libgdal-dev', 'libgeos++-dev', 'libproj-dev', 'libsparsehash-dev', 'spatialite-bin'] | ||||||
|  |       env: COMPILER='g++-5' BUILD_TYPE='Release' | ||||||
|  | 
 | ||||||
|  |     - os: linux | ||||||
|  |       compiler: gcc | ||||||
|  |       addons: | ||||||
|  |         apt: | ||||||
|  |           sources: ['ubuntu-toolchain-r-test', 'boost-latest'] | ||||||
|  |           packages: ['g++-5', 'libboost1.55-all-dev', 'libgdal-dev', 'libgeos++-dev', 'libproj-dev', 'libsparsehash-dev', 'spatialite-bin'] | ||||||
|  |       env: COMPILER='g++-5' BUILD_TYPE='Dev' | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     # 3/ OSX Clang Builds | ||||||
|  |     - os: osx | ||||||
|  |       osx_image: xcode6.4 | ||||||
|  |       compiler: clang | ||||||
|  |       env: COMPILER='clang++' BUILD_TYPE='Dev' | ||||||
|  | 
 | ||||||
|  |     - os: osx | ||||||
|  |       osx_image: xcode6.4 | ||||||
|  |       compiler: clang | ||||||
|  |       env: COMPILER='clang++' BUILD_TYPE='Release' | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     - os: osx | ||||||
|  |       osx_image: xcode7 | ||||||
|  |       compiler: clang | ||||||
|  |       env: COMPILER='clang++' BUILD_TYPE='Dev' | ||||||
|  | 
 | ||||||
|  |     - os: osx | ||||||
|  |       osx_image: xcode7 | ||||||
|  |       compiler: clang | ||||||
|  |       env: COMPILER='clang++' BUILD_TYPE='Release' | ||||||
| 
 | 
 | ||||||
| # http://docs.travis-ci.com/user/apt/ |  | ||||||
| addons: |  | ||||||
|     apt: |  | ||||||
|         sources: |  | ||||||
|             - boost-latest |  | ||||||
|             - ubuntu-toolchain-r-test |  | ||||||
|         packages: |  | ||||||
|             - g++-4.8 |  | ||||||
|             - gcc-4.8 |  | ||||||
|             - libboost1.55-dev |  | ||||||
|             - libboost-program-options1.55-dev |  | ||||||
|             - libgdal-dev |  | ||||||
|             - libgeos++-dev |  | ||||||
|             - libproj-dev |  | ||||||
|             - libsparsehash-dev |  | ||||||
|             - spatialite-bin |  | ||||||
| 
 | 
 | ||||||
| install: | install: | ||||||
|     - scripts/travis_install.sh |   - DEPS_DIR="${TRAVIS_BUILD_DIR}/deps" | ||||||
|  |   - mkdir -p ${DEPS_DIR} && cd ${DEPS_DIR} | ||||||
|  |   - git clone --quiet --depth 1 https://github.com/osmcode/osm-testdata.git | ||||||
|  |   - | | ||||||
|  |     if [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then | ||||||
|  |       brew remove gdal | ||||||
|  |       brew install cmake boost google-sparsehash gdal | ||||||
|  |     fi | ||||||
|  | 
 | ||||||
|  | before_script: | ||||||
|  |   - cd ${TRAVIS_BUILD_DIR} | ||||||
|  |   - mkdir build && cd build | ||||||
|  |   - CXX=${COMPILER} CXXFLAGS=${COMPILER_FLAGS} cmake -LA .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DOSM_TESTDATA="${TRAVIS_BUILD_DIR}/deps/osm-testdata" | ||||||
| 
 | 
 | ||||||
| script: | script: | ||||||
|     - scripts/travis_script.sh |   - make VERBOSE=1 | ||||||
|  |   - ctest --output-on-failure | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										137
									
								
								third_party/libosmium/CHANGELOG.md
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										137
									
								
								third_party/libosmium/CHANGELOG.md
									
									
									
									
										vendored
									
									
								
							| @ -12,6 +12,132 @@ This project adheres to [Semantic Versioning](http://semver.org/). | |||||||
| 
 | 
 | ||||||
| ### Fixed | ### Fixed | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | ## [2.5.4] - 2015-12-03 | ||||||
|  | 
 | ||||||
|  | ### Changed | ||||||
|  | 
 | ||||||
|  | - Included gdalcpp.hpp header was updated to version 1.1.1. | ||||||
|  | - Included protozero library was updated to version 1.2.3. | ||||||
|  | - Workarounds for missing constexpr support in Visual Studio removed. All | ||||||
|  |   constexpr features we need are supported now. | ||||||
|  | - Some code cleanup after running clang-tidy on the code. | ||||||
|  | - Re-added `Buffer::value_type` typedef. Turns out it is needed when using | ||||||
|  |   `std::back_inserter` on the Buffer. | ||||||
|  | 
 | ||||||
|  | ### Fixed | ||||||
|  | 
 | ||||||
|  | - Bugs with Timestamp code on 32 bit platforms. This necessitated | ||||||
|  |   some changes in Timestamp which might lead to changes in user | ||||||
|  |   code. | ||||||
|  | - Bug in segment intersection code (which appeared on i686 platform). | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ## [2.5.3] - 2015-11-17 | ||||||
|  | 
 | ||||||
|  | ### Added | ||||||
|  | 
 | ||||||
|  | - `osmium::make_diff_iterator()` helper function. | ||||||
|  | 
 | ||||||
|  | ### Changed | ||||||
|  | 
 | ||||||
|  | - Deprecated `osmium::Buffer::set_full_callback()`. | ||||||
|  | - Removed DataFile class which was never used anywhere. | ||||||
|  | - Removed unused and obscure `Buffer::value_type` typedef. | ||||||
|  | 
 | ||||||
|  | ### Fixed | ||||||
|  | 
 | ||||||
|  | - Possible overrun in Buffer when using the full-callback. | ||||||
|  | - Incorrect swapping of Buffer. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ## [2.5.2] - 2015-11-06 | ||||||
|  | 
 | ||||||
|  | # Fixed | ||||||
|  | 
 | ||||||
|  | - Writing data through an OutputIterator was extremly slow due to | ||||||
|  |   lock contention. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ## [2.5.1] - 2015-11-05 | ||||||
|  | 
 | ||||||
|  | ### Added | ||||||
|  | 
 | ||||||
|  | - Header `osmium/fwd.hpp` with forward declarations of the most commonly | ||||||
|  |   used Osmium classes. | ||||||
|  | 
 | ||||||
|  | ### Changed | ||||||
|  | 
 | ||||||
|  | - Moved `osmium/io/overwrite.hpp` to `osmium/io/writer_options.hpp` | ||||||
|  |   If you still include the old file, you'll get a warning. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ## [2.5.0] - 2015-11-04 | ||||||
|  | 
 | ||||||
|  | ### Added | ||||||
|  | 
 | ||||||
|  | - Helper functions to make input iterator ranges and output iterators. | ||||||
|  | - Add support for reading o5m and o5c files. | ||||||
|  | - Option for osmium::io::Writer to fsync file after writing. | ||||||
|  | - Lots of internal asserts() and other robustness checks. | ||||||
|  | 
 | ||||||
|  | ### Changed | ||||||
|  | 
 | ||||||
|  | - Updated included protozero library to version 1.2.0. | ||||||
|  | - Complete overhaul of the I/O system making it much more robust against | ||||||
|  |   wrong data and failures during I/O operations. | ||||||
|  | - Speed up PBF writing by running parts of it in parallel. | ||||||
|  | - OutputIterator doesn't hold an internal buffer any more, but it uses | ||||||
|  |   one in Writer. Calling flush() on the OutputIterator isn't needed any | ||||||
|  |   more. | ||||||
|  | - Reader now throws when trying to read after eof or an error. | ||||||
|  | - I/O functions that used to throw std::runtime_error now throw | ||||||
|  |   osmium::io_error or derived. | ||||||
|  | - Optional parameters on osmium::io::Writer now work in any order. | ||||||
|  | 
 | ||||||
|  | ### Fixed | ||||||
|  | 
 | ||||||
|  | - PBF reader now decodes locations of invisible nodes properly. | ||||||
|  | - Invalid Delta encode iterator dereference. | ||||||
|  | - Lots of includes fixed to include (only) what's used. | ||||||
|  | - Dangling reference in area assembly code. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ## [2.4.1] - 2015-08-29 | ||||||
|  | 
 | ||||||
|  | ### Fixed | ||||||
|  | 
 | ||||||
|  | - CRC calculation of tags and changesets. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ## [2.4.0] - 2015-08-29 | ||||||
|  | 
 | ||||||
|  | ### Added | ||||||
|  | 
 | ||||||
|  | - Checks that user names, member roles and tag keys and values are not longer | ||||||
|  |   than 256 * 4 bytes. That is the maximum length 256 Unicode characters | ||||||
|  |   can have in UTF-8 encoding. | ||||||
|  | - Support for GDAL 2. GDAL 1 still works. | ||||||
|  | 
 | ||||||
|  | ### Changed | ||||||
|  | 
 | ||||||
|  | - Improved CMake build scripts. | ||||||
|  | - Updated internal version of Protozero to 1.1.0. | ||||||
|  | - Removed `toogr*` examples. They are in their own repository now. | ||||||
|  |   See https://github.com/osmcode/osm-gis-export. | ||||||
|  | - Files about to be memory-mapped (for instance index files) are now set | ||||||
|  |   to binary mode on Windows so the application doesn't have to do this. | ||||||
|  | 
 | ||||||
|  | ### Fixed | ||||||
|  | 
 | ||||||
|  | - Hanging program when trying to open file with an unknown file format. | ||||||
|  | - Building problems with old boost versions. | ||||||
|  | - Initialization errors in PBF writer. | ||||||
|  | - Bug in byte swap code. | ||||||
|  | - Output on Windows now always uses binary mode, even when writing to | ||||||
|  |   stdout, so OSM xml and opl files always use LF line endings. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| ## [2.3.0] - 2015-08-18 | ## [2.3.0] - 2015-08-18 | ||||||
| 
 | 
 | ||||||
| ### Added | ### Added | ||||||
| @ -108,8 +234,15 @@ This project adheres to [Semantic Versioning](http://semver.org/). | |||||||
|   Doxygen (up to version 1.8.8). This version contains a workaround to fix |   Doxygen (up to version 1.8.8). This version contains a workaround to fix | ||||||
|   this. |   this. | ||||||
| 
 | 
 | ||||||
| [unreleased]: https://github.com/osmcode/libosmium/compare/v2.3.0...HEAD | [unreleased]: https://github.com/osmcode/libosmium/compare/v2.5.4...HEAD | ||||||
| [2.3.0]: https://github.com/osmcode/libosmium/compare/v2.3.0...v2.3.0 | [2.5.4]: https://github.com/osmcode/libosmium/compare/v2.5.3...v2.5.4 | ||||||
|  | [2.5.3]: https://github.com/osmcode/libosmium/compare/v2.5.2...v2.5.3 | ||||||
|  | [2.5.2]: https://github.com/osmcode/libosmium/compare/v2.5.1...v2.5.2 | ||||||
|  | [2.5.1]: https://github.com/osmcode/libosmium/compare/v2.5.0...v2.5.1 | ||||||
|  | [2.5.0]: https://github.com/osmcode/libosmium/compare/v2.4.1...v2.5.0 | ||||||
|  | [2.4.1]: https://github.com/osmcode/libosmium/compare/v2.4.0...v2.4.1 | ||||||
|  | [2.4.0]: https://github.com/osmcode/libosmium/compare/v2.3.0...v2.4.0 | ||||||
|  | [2.3.0]: https://github.com/osmcode/libosmium/compare/v2.2.0...v2.3.0 | ||||||
| [2.2.0]: https://github.com/osmcode/libosmium/compare/v2.1.0...v2.2.0 | [2.2.0]: https://github.com/osmcode/libosmium/compare/v2.1.0...v2.2.0 | ||||||
| [2.1.0]: https://github.com/osmcode/libosmium/compare/v2.0.0...v2.1.0 | [2.1.0]: https://github.com/osmcode/libosmium/compare/v2.0.0...v2.1.0 | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										156
									
								
								third_party/libosmium/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										156
									
								
								third_party/libosmium/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							| @ -9,8 +9,6 @@ | |||||||
| cmake_minimum_required(VERSION 2.8 FATAL_ERROR) | cmake_minimum_required(VERSION 2.8 FATAL_ERROR) | ||||||
| list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") | list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") | ||||||
| 
 | 
 | ||||||
| set(CMAKE_EXPORT_COMPILE_COMMANDS ON) |  | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| #----------------------------------------------------------------------------- | #----------------------------------------------------------------------------- | ||||||
| # | # | ||||||
| @ -26,13 +24,13 @@ set(CMAKE_CONFIGURATION_TYPES "Debug;Release;RelWithDebInfo;MinSizeRel;Dev;Cover | |||||||
| project(libosmium) | project(libosmium) | ||||||
| 
 | 
 | ||||||
| set(LIBOSMIUM_VERSION_MAJOR 2) | set(LIBOSMIUM_VERSION_MAJOR 2) | ||||||
| set(LIBOSMIUM_VERSION_MINOR 3) | set(LIBOSMIUM_VERSION_MINOR 5) | ||||||
| set(LIBOSMIUM_VERSION_PATCH 0) | set(LIBOSMIUM_VERSION_PATCH 4) | ||||||
| 
 | 
 | ||||||
| set(LIBOSMIUM_VERSION | set(LIBOSMIUM_VERSION | ||||||
|     "${LIBOSMIUM_VERSION_MAJOR}.${LIBOSMIUM_VERSION_MINOR}.${LIBOSMIUM_VERSION_PATCH}" |     "${LIBOSMIUM_VERSION_MAJOR}.${LIBOSMIUM_VERSION_MINOR}.${LIBOSMIUM_VERSION_PATCH}") | ||||||
|     CACHE STRING | 
 | ||||||
|     "Libosmium version") | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| #----------------------------------------------------------------------------- | #----------------------------------------------------------------------------- | ||||||
| @ -56,6 +54,10 @@ option(BUILD_HEADERS    "compile every header file on its own" ${dev_build}) | |||||||
| option(BUILD_BENCHMARKS "compile benchmark programs" ${dev_build}) | option(BUILD_BENCHMARKS "compile benchmark programs" ${dev_build}) | ||||||
| option(BUILD_DATA_TESTS "compile data tests, please run them with ctest" ${dev_build}) | option(BUILD_DATA_TESTS "compile data tests, please run them with ctest" ${dev_build}) | ||||||
| 
 | 
 | ||||||
|  | option(INSTALL_GDALCPP   "also install gdalcpp headers" OFF) | ||||||
|  | option(INSTALL_PROTOZERO "also install protozero headers" OFF) | ||||||
|  | option(INSTALL_UTFCPP    "also install utfcpp headers" OFF) | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| #----------------------------------------------------------------------------- | #----------------------------------------------------------------------------- | ||||||
| # | # | ||||||
| @ -118,29 +120,39 @@ find_package(Boost 1.38) | |||||||
| mark_as_advanced(CLEAR BOOST_ROOT) | mark_as_advanced(CLEAR BOOST_ROOT) | ||||||
| 
 | 
 | ||||||
| if(Boost_FOUND) | if(Boost_FOUND) | ||||||
|     include_directories(${Boost_INCLUDE_DIRS}) |     include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) | ||||||
| else() | else() | ||||||
|     set(BOOST_ROOT "NOT FOUND: please choose" CACHE PATH "") |     set(BOOST_ROOT "NOT FOUND: please choose" CACHE PATH "") | ||||||
|     message(FATAL_ERROR "PLEASE, specify the directory where the Boost library is installed in BOOST_ROOT") |     message(FATAL_ERROR "PLEASE, specify the directory where the Boost library is installed in BOOST_ROOT") | ||||||
| endif() | endif() | ||||||
| 
 | 
 | ||||||
| set(OSMIUM_INCLUDE_DIR include) | # set OSMIUM_INCLUDE_DIR so FindOsmium will not set anything different | ||||||
|  | set(OSMIUM_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include") | ||||||
|  | 
 | ||||||
|  | include_directories(${OSMIUM_INCLUDE_DIR}) | ||||||
|  | 
 | ||||||
| find_package(Osmium COMPONENTS io gdal geos proj sparsehash) | find_package(Osmium COMPONENTS io gdal geos proj sparsehash) | ||||||
| include_directories(${OSMIUM_INCLUDE_DIRS}) | 
 | ||||||
|  | # The find_package put the directory where it found the libosmium includes | ||||||
|  | # into OSMIUM_INCLUDE_DIRS. We remove it again, because we want to make | ||||||
|  | # sure to use our own include directory already set up above. | ||||||
|  | list(FIND OSMIUM_INCLUDE_DIRS "${OSMIUM_INCLUDE_DIR}" _own_index) | ||||||
|  | list(REMOVE_AT OSMIUM_INCLUDE_DIRS ${_own_index}) | ||||||
|  | set(_own_index) | ||||||
|  | 
 | ||||||
|  | include_directories(SYSTEM ${OSMIUM_INCLUDE_DIRS}) | ||||||
| 
 | 
 | ||||||
| if(MSVC) | if(MSVC) | ||||||
|     find_path(GETOPT_INCLUDE_DIR getopt.h) |     find_path(GETOPT_INCLUDE_DIR getopt.h) | ||||||
|     find_library(GETOPT_LIBRARY NAMES wingetopt) |     find_library(GETOPT_LIBRARY NAMES wingetopt) | ||||||
|     if(GETOPT_INCLUDE_DIR AND GETOPT_LIBRARY) |     if(GETOPT_INCLUDE_DIR AND GETOPT_LIBRARY) | ||||||
|         include_directories(${GETOPT_INCLUDE_DIR}) |         include_directories(SYSTEM ${GETOPT_INCLUDE_DIR}) | ||||||
|         list(APPEND OSMIUM_LIBRARIES ${GETOPT_LIBRARY}) |         list(APPEND OSMIUM_LIBRARIES ${GETOPT_LIBRARY}) | ||||||
|     else() |     else() | ||||||
|         set(GETOPT_MISSING 1) |         set(GETOPT_MISSING 1) | ||||||
|     endif() |     endif() | ||||||
| endif() | endif() | ||||||
| 
 | 
 | ||||||
| include_directories(include) |  | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| #----------------------------------------------------------------------------- | #----------------------------------------------------------------------------- | ||||||
| # | # | ||||||
| @ -205,6 +217,7 @@ if(CMAKE_BUILD_TYPE STREQUAL "Dev") | |||||||
|         add_definitions(-Werror) |         add_definitions(-Werror) | ||||||
|     endif() |     endif() | ||||||
|     add_definitions(${OSMIUM_WARNING_OPTIONS}) |     add_definitions(${OSMIUM_WARNING_OPTIONS}) | ||||||
|  | #    add_definitions(${OSMIUM_WARNING_OPTIONS} ${OSMIUM_DRACONIC_CLANG_OPTIONS} -Wno-documentation -Wno-format-nonliteral -Wno-deprecated -Wno-covered-switch-default -Wno-shadow) | ||||||
| endif() | endif() | ||||||
| 
 | 
 | ||||||
| # Force RelWithDebInfo build type if none was given | # Force RelWithDebInfo build type if none was given | ||||||
| @ -256,19 +269,21 @@ find_program(CPPCHECK cppcheck) | |||||||
| if(CPPCHECK) | if(CPPCHECK) | ||||||
|     message(STATUS "Looking for cppcheck - found") |     message(STATUS "Looking for cppcheck - found") | ||||||
|     set(CPPCHECK_OPTIONS |     set(CPPCHECK_OPTIONS | ||||||
|         --enable=warning,style,performance,portability,information,missingInclude) |         --enable=warning,style,performance,portability,information,missingInclude --force -Uassert) | ||||||
| 
 | 
 | ||||||
|     # cpp doesn't find system includes for some reason, suppress that report |     # cpp doesn't find system includes for some reason, suppress that report | ||||||
|     set(CPPCHECK_OPTIONS ${CPPCHECK_OPTIONS} --suppress=missingIncludeSystem) |     set(CPPCHECK_OPTIONS ${CPPCHECK_OPTIONS} --suppress=missingIncludeSystem) | ||||||
| 
 | 
 | ||||||
|     file(GLOB_RECURSE ALL_INCLUDES   include/osmium/*.hpp) |     file(GLOB_RECURSE ALL_INCLUDES   include/osmium/*.hpp) | ||||||
|     file(GLOB         ALL_EXAMPLES   examples/*.cpp) |     file(GLOB         ALL_EXAMPLES   examples/*.cpp) | ||||||
|  |     file(GLOB         ALL_BENCHMARKS benchmarks/*.cpp) | ||||||
|     file(GLOB         ALL_UNIT_TESTS test/t/*/test_*.cpp) |     file(GLOB         ALL_UNIT_TESTS test/t/*/test_*.cpp) | ||||||
|     file(GLOB         ALL_DATA_TESTS test/data-tests/*.cpp) |     file(GLOB         ALL_DATA_TESTS test/data-tests/*.cpp) | ||||||
| 
 | 
 | ||||||
|     if(Osmium_DEBUG) |     if(Osmium_DEBUG) | ||||||
|         message(STATUS "Checking includes      : ${ALL_INCLUDES}") |         message(STATUS "Checking includes      : ${ALL_INCLUDES}") | ||||||
|         message(STATUS "Checking example code  : ${ALL_EXAMPLES}") |         message(STATUS "Checking example code  : ${ALL_EXAMPLES}") | ||||||
|  |         message(STATUS "Checking benchmarks    : ${ALL_BENCHMARKS}") | ||||||
|         message(STATUS "Checking unit test code: ${ALL_UNIT_TESTS}") |         message(STATUS "Checking unit test code: ${ALL_UNIT_TESTS}") | ||||||
|         message(STATUS "Checking data test code: ${ALL_DATA_TESTS}") |         message(STATUS "Checking data test code: ${ALL_DATA_TESTS}") | ||||||
|     endif() |     endif() | ||||||
| @ -276,6 +291,7 @@ if(CPPCHECK) | |||||||
|     set(CPPCHECK_FILES |     set(CPPCHECK_FILES | ||||||
|         ${ALL_INCLUDES} |         ${ALL_INCLUDES} | ||||||
|         ${ALL_EXAMPLES} |         ${ALL_EXAMPLES} | ||||||
|  |         ${ALL_BENCHMARKS} | ||||||
|         ${ALL_UNIT_TESTS} |         ${ALL_UNIT_TESTS} | ||||||
|         ${ALL_DATA_TESTS}) |         ${ALL_DATA_TESTS}) | ||||||
| 
 | 
 | ||||||
| @ -288,7 +304,7 @@ if(CPPCHECK) | |||||||
| else() | else() | ||||||
|     message(STATUS "Looking for cppcheck - not found") |     message(STATUS "Looking for cppcheck - not found") | ||||||
|     message(STATUS "  Build target 'cppcheck' will not be available.") |     message(STATUS "  Build target 'cppcheck' will not be available.") | ||||||
| endif(CPPCHECK) | endif() | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| #----------------------------------------------------------------------------- | #----------------------------------------------------------------------------- | ||||||
| @ -345,11 +361,115 @@ if(BUILD_HEADERS) | |||||||
|     endforeach() |     endforeach() | ||||||
| endif() | endif() | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | #----------------------------------------------------------------------------- | ||||||
|  | # | ||||||
|  | #  Optional "clang-tidy" target | ||||||
|  | # | ||||||
|  | #----------------------------------------------------------------------------- | ||||||
|  | message(STATUS "Looking for clang-tidy") | ||||||
|  | find_program(CLANG_TIDY NAMES clang-tidy clang-tidy-3.9 clang-tidy-3.8 clang-tidy-3.7 clang-tidy-3.6 clang-tidy-3.5) | ||||||
|  | 
 | ||||||
|  | if(CLANG_TIDY) | ||||||
|  |     message(STATUS "Looking for clang-tidy - found") | ||||||
|  | 
 | ||||||
|  |     if(BUILD_EXAMPLES) | ||||||
|  |         file(GLOB CT_ALL_EXAMPLES examples/*.cpp) | ||||||
|  |     endif() | ||||||
|  | 
 | ||||||
|  |     if(BUILD_TESTING) | ||||||
|  |         file(GLOB CT_ALL_UNIT_TESTS test/t/*/test_*.cpp) | ||||||
|  |     endif() | ||||||
|  | 
 | ||||||
|  |     if(BUILD_HEADERS) | ||||||
|  |         file(GLOB_RECURSE CT_ALL_INCLUDES ${CMAKE_BINARY_DIR}/header_check/osmium__*.cpp) | ||||||
|  |     endif() | ||||||
|  | 
 | ||||||
|  |     if(BUILD_BENCHMARKS) | ||||||
|  |         file(GLOB CT_ALL_BENCHMARKS benchmarks/*.cpp) | ||||||
|  |     endif() | ||||||
|  | 
 | ||||||
|  |     if(BUILD_DATA_TESTS) | ||||||
|  |         file(GLOB CT_ALL_DATA_TESTS test/data-tests/*.cpp) | ||||||
|  |     endif() | ||||||
|  | 
 | ||||||
|  |     if(Osmium_DEBUG) | ||||||
|  |         message(STATUS "Checking example code  : ${CT_ALL_EXAMPLES}") | ||||||
|  |         message(STATUS "Checking unit test code: ${CT_ALL_UNIT_TESTS}") | ||||||
|  |         message(STATUS "Checking includes      : ${CT_ALL_INCLUDES}") | ||||||
|  |         message(STATUS "Checking benchmarks    : ${CT_ALL_BENCHMARKS}") | ||||||
|  |         message(STATUS "Checking data test code: ${CT_ALL_DATA_TESTS}") | ||||||
|  |     endif() | ||||||
|  | 
 | ||||||
|  |     set(CT_CHECK_FILES | ||||||
|  |         ${CT_ALL_EXAMPLES} | ||||||
|  |         ${CT_ALL_UNIT_TESTS} | ||||||
|  |         ${CT_ALL_INCLUDES} | ||||||
|  |         ${CT_ALL_BENCHMARKS} | ||||||
|  |         ${CT_ALL_DATA_TESTS}) | ||||||
|  | 
 | ||||||
|  |     # For a list of check options, see: | ||||||
|  |     # http://clang.llvm.org/extra/clang-tidy/checks/list.html | ||||||
|  | 
 | ||||||
|  |     list(APPEND CT_CHECKS "cert-*" | ||||||
|  |                          "-cert-err60-cpp") # even the std lib doesn't do this | ||||||
|  | 
 | ||||||
|  |     # disabled, because it is slow | ||||||
|  | #    list(APPEND CT_CHECKS "clang-analyzer-*") | ||||||
|  | 
 | ||||||
|  |     list(APPEND CT_CHECKS "google-*" | ||||||
|  |                          "-google-explicit-constructor" | ||||||
|  |                          "-google-readability-casting" | ||||||
|  |                          "-google-readability-function") | ||||||
|  | 
 | ||||||
|  |     list(APPEND CT_CHECKS "llvm-*" | ||||||
|  |                          "-llvm-include-order") | ||||||
|  | 
 | ||||||
|  |     list(APPEND CT_CHECKS "misc-*" | ||||||
|  |                          "-misc-argument-comment") | ||||||
|  | 
 | ||||||
|  |     list(APPEND CT_CHECKS "modernize-*") | ||||||
|  | 
 | ||||||
|  |     list(APPEND CT_CHECKS "readability-*" | ||||||
|  |                          "-readability-identifier-naming" | ||||||
|  |                          "-readability-named-parameter") | ||||||
|  | 
 | ||||||
|  |     string(REPLACE ";" "," ALL_CHECKS "${CT_CHECKS}") | ||||||
|  | 
 | ||||||
|  |     add_custom_target(clang-tidy | ||||||
|  |         ${CLANG_TIDY} | ||||||
|  |         -p ${CMAKE_BINARY_DIR} | ||||||
|  |         -header-filter='include/osmium/.*' | ||||||
|  |         -checks="${ALL_CHECKS}" | ||||||
|  |         ${CT_CHECK_FILES} | ||||||
|  |     ) | ||||||
|  | else() | ||||||
|  |     message(STATUS "Looking for clang-tidy - not found") | ||||||
|  |     message(STATUS "  Build target 'clang-tidy' will not be available.") | ||||||
|  | endif() | ||||||
|  | 
 | ||||||
|  | #----------------------------------------------------------------------------- | ||||||
|  | # | ||||||
|  | #  Installation | ||||||
|  | # | ||||||
|  | #  External libraries are only installed if the options are set in case they | ||||||
|  | #  are installed from somewhere else. | ||||||
|  | # | ||||||
|  | #----------------------------------------------------------------------------- | ||||||
| install(DIRECTORY include/osmium DESTINATION include) | install(DIRECTORY include/osmium DESTINATION include) | ||||||
| 
 | 
 | ||||||
| # We only have a copy of this file so we can use older boost versions which | if(INSTALL_GDALCPP) | ||||||
| # don't have it. We probably don't want to install it. |     install(include/gdalcpp.hpp DESTINATION include) | ||||||
| #install(FILES include/boost_unicode_iterator.hpp DESTINATION include) | endif() | ||||||
|  | 
 | ||||||
|  | if(INSTALL_PROTOZERO) | ||||||
|  |     install(DIRECTORY include/protozero DESTINATION include) | ||||||
|  | endif() | ||||||
|  | 
 | ||||||
|  | if(INSTALL_UTFCPP) | ||||||
|  |     install(include/utf8.hpp DESTINATION include) | ||||||
|  |     install(DIRECTORY include/utf8 DESTINATION include) | ||||||
|  | endif() | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| #----------------------------------------------------------------------------- | #----------------------------------------------------------------------------- | ||||||
|  | |||||||
							
								
								
									
										45
									
								
								third_party/libosmium/CONTRIBUTING.md
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										45
									
								
								third_party/libosmium/CONTRIBUTING.md
									
									
									
									
										vendored
									
									
								
							| @ -36,22 +36,21 @@ different. | |||||||
| * Class names begin with uppercase chars and use CamelCase. Smaller helper | * Class names begin with uppercase chars and use CamelCase. Smaller helper | ||||||
|   classes are usually defined as struct and have lowercase names. |   classes are usually defined as struct and have lowercase names. | ||||||
| * Macros (and only macros) are all uppercase. Use macros sparingly, usually | * Macros (and only macros) are all uppercase. Use macros sparingly, usually | ||||||
|   a constexpr is better. |   a simple (maybe constexpr) inline function is better. Undef macros after use | ||||||
|  |   if possible. | ||||||
|  | * Macros should only be used for controlling which parts of the code should be | ||||||
|  |   included when compiling or to avoid major code repetitions. | ||||||
| * Variables, attributes, and function names are lowercase with | * Variables, attributes, and function names are lowercase with | ||||||
|   `underscores_between_words`. |   `underscores_between_words`. | ||||||
| * Class attribute names start with `m_` (member). | * Class attribute names start with `m_` (member). | ||||||
| * Template parameters are single uppercase letters or start with uppercase `T` |  | ||||||
|   and use CamelCase. |  | ||||||
| * Typedefs have `names_like_this_type` which end in `_type`. |  | ||||||
| * Macros should only be used for controlling which parts of the code should be |  | ||||||
|   included when compiling. |  | ||||||
| * Use `descriptive_variable_names`, exceptions are well-established conventions | * Use `descriptive_variable_names`, exceptions are well-established conventions | ||||||
|   like `i` for a loop variable. Iterators are usually called `it`. |   like `i` for a loop variable. Iterators are usually called `it`. | ||||||
| * Declare variables where they are first used (C++ style), not at the beginning | * Declare variables where they are first used (C++ style), not at the beginning | ||||||
|   of a function (old C style). |   of a function (old C style). | ||||||
| * Names from external namespaces (even `std`) are always mentioned explicitly. | * Names from external namespaces (even `std`) are always mentioned explicitly. | ||||||
|   Do not use `using` (except for `std::swap`). This way we can't even by |   Do not use `using` (except for `std::swap`). This way we can't even by | ||||||
|   accident pollute the namespace of the code including Osmium. |   accident pollute the namespace of the code using Osmium. | ||||||
|  | * Always use the standard swap idiom: `using std::swap; swap(foo, bar);`. | ||||||
| * `#include` directives appear in three "blocks" after the copyright notice. | * `#include` directives appear in three "blocks" after the copyright notice. | ||||||
|   The blocks are separated by blank lines. First block contains `#include`s for |   The blocks are separated by blank lines. First block contains `#include`s for | ||||||
|   standard C/C++ includes, second block for any external libs used, third |   standard C/C++ includes, second block for any external libs used, third | ||||||
| @ -64,8 +63,20 @@ different. | |||||||
| * All files have suffix `.hpp`. | * All files have suffix `.hpp`. | ||||||
| * Closing } of all classes and namespaces should have a trailing comment | * Closing } of all classes and namespaces should have a trailing comment | ||||||
|   with the name of the class/namespace. |   with the name of the class/namespace. | ||||||
| * All constructors with one or more arguments should be declared "explicit" | * All constructors with one (or more arguments if they have a default) should | ||||||
|   unless there is a reason for them not to be. Document that reason. |   be declared "explicit" unless there is a reason for them not to be. Document | ||||||
|  |   that reason. | ||||||
|  | * If a class has any of the special methods (copy/move constructor/assigment, | ||||||
|  |   destructor) it should have all of them, possibly marking them as default or | ||||||
|  |   deleted. | ||||||
|  | * Typedefs have `names_like_this_type` which end in `_type`. Typedefs should | ||||||
|  |   use the new `using foo_type = bar` syntax instead of the old | ||||||
|  |   `typedef bar foo_type`. | ||||||
|  | * Template parameters are single uppercase letters or start with uppercase `T` | ||||||
|  |   and use CamelCase. | ||||||
|  | * Always use `typename` in templates, not `class`: `template <typename T>`. | ||||||
|  | * The ellipsis in variadic template never has a space to the left of it and | ||||||
|  |   always has a space to the right: `template <typename... TArgs>` etc. | ||||||
| 
 | 
 | ||||||
| Keep to the indentation and other styles used in the code. Use `make indent` | Keep to the indentation and other styles used in the code. Use `make indent` | ||||||
| in the toplevel directory to fix indentation and styling. It calls `astyle` | in the toplevel directory to fix indentation and styling. It calls `astyle` | ||||||
| @ -81,15 +92,15 @@ about which compilers support which feature and what operating system versions | |||||||
| or distributions have which versions of these compilers installed. | or distributions have which versions of these compilers installed. | ||||||
| 
 | 
 | ||||||
| GCC 4.6   - too old, not supported (Ubuntu 12.04 LTS) | GCC 4.6   - too old, not supported (Ubuntu 12.04 LTS) | ||||||
| GCC 4.7.2 - can probably not be supported (Debian wheezy/stable) | GCC 4.7.2 - can probably not be supported (Debian wheezy) | ||||||
| GCC 4.7.3 - works | GCC 4.7.3 - probably works | ||||||
| GCC 4.8   - works | GCC 4.8   - works and is supported from here on | ||||||
| clang 3.0 - too old, not supported (Debian wheezy/stable, Ubuntu 12.04 LTS) | clang 3.0 - too old, not supported (Debian wheezy, Ubuntu 12.04 LTS) | ||||||
| clang 3.2 - works | clang 3.2 - probably works | ||||||
|  | clang 3.5 - works and is supported from here on | ||||||
| 
 | 
 | ||||||
| C++11 features you should not use: | Use `include/osmium/util/compatibility.hpp` if there are compatibility problems | ||||||
| * Inherited Constructors (works only in GCC 4.8+ and clang 3.3+, not in Visual | between compilers due to different C++11 support. | ||||||
|   Studio) |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| ## Checking your code | ## Checking your code | ||||||
|  | |||||||
							
								
								
									
										14
									
								
								third_party/libosmium/README.md
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								third_party/libosmium/README.md
									
									
									
									
										vendored
									
									
								
							| @ -4,7 +4,7 @@ http://osmcode.org/libosmium | |||||||
| 
 | 
 | ||||||
| A fast and flexible C++ library for working with OpenStreetMap data. | A fast and flexible C++ library for working with OpenStreetMap data. | ||||||
| 
 | 
 | ||||||
| [](http://travis-ci.org/osmcode/libosmium) | [](https://travis-ci.org/osmcode/libosmium) | ||||||
| [](https://ci.appveyor.com/project/Mapbox/libosmium) | [](https://ci.appveyor.com/project/Mapbox/libosmium) | ||||||
| 
 | 
 | ||||||
| Libosmium is developed on Linux, but also works on OSX and Windows (with some | Libosmium is developed on Linux, but also works on OSX and Windows (with some | ||||||
| @ -27,9 +27,15 @@ you need for your programs. | |||||||
| For details see the | For details see the | ||||||
| [list of dependencies](https://github.com/osmcode/libosmium/wiki/Libosmium-dependencies). | [list of dependencies](https://github.com/osmcode/libosmium/wiki/Libosmium-dependencies). | ||||||
| 
 | 
 | ||||||
| The [protozero](https://github.com/mapbox/protozero) and | The following external (header-only) libraries are included in the libosmium | ||||||
| [utf8-cpp](http://utfcpp.sourceforge.net/) header-only libraries are included | repository: | ||||||
| in the libosmium repository. | * [gdalcpp](https://github.com/joto/gdalcpp) | ||||||
|  | * [protozero](https://github.com/mapbox/protozero) | ||||||
|  | * [utfcpp](http://utfcpp.sourceforge.net/) | ||||||
|  | 
 | ||||||
|  | If you want (some of) those libraries to be installed along with libosmium | ||||||
|  | itself when calling `make install`, you have to use the CMake options | ||||||
|  | `INSTALL_GDALCPP`, `INSTALL_PROTOZERO`, and/or `INSTALL_UTFCPP`. | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| ## Directories | ## Directories | ||||||
|  | |||||||
							
								
								
									
										31
									
								
								third_party/libosmium/appveyor.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										31
									
								
								third_party/libosmium/appveyor.yml
									
									
									
									
										vendored
									
									
								
							| @ -9,16 +9,10 @@ environment: | |||||||
|   - config: Dev |   - config: Dev | ||||||
|   - config: RelWithDebInfo |   - config: RelWithDebInfo | ||||||
| 
 | 
 | ||||||
| # branches to build |  | ||||||
| branches: |  | ||||||
|   # whitelist |  | ||||||
|   only: |  | ||||||
|     - master |  | ||||||
| 
 |  | ||||||
| shallow_clone: true | shallow_clone: true | ||||||
| 
 | 
 | ||||||
| # Operating system (build VM template) | # Operating system (build VM template) | ||||||
| os: Visual Studio 2014 CTP4 | os: Visual Studio 2015 | ||||||
| 
 | 
 | ||||||
| # scripts that are called at very beginning, before repo cloning | # scripts that are called at very beginning, before repo cloning | ||||||
| init: | init: | ||||||
| @ -46,6 +40,8 @@ install: | |||||||
|   - set PATH=%LODEPSDIR%\expat\lib;%PATH% |   - set PATH=%LODEPSDIR%\expat\lib;%PATH% | ||||||
|   #libtiff.dll |   #libtiff.dll | ||||||
|   - set PATH=%LODEPSDIR%\libtiff\lib;%PATH% |   - set PATH=%LODEPSDIR%\libtiff\lib;%PATH% | ||||||
|  |   #jpeg.dll | ||||||
|  |   - set PATH=%LODEPSDIR%\jpeg\lib;%PATH% | ||||||
|   #zlibwapi.dll |   #zlibwapi.dll | ||||||
|   - set PATH=%LODEPSDIR%\zlib\lib;%PATH% |   - set PATH=%LODEPSDIR%\zlib\lib;%PATH% | ||||||
|   #convert backslashes in bzip2 path to forward slashes |   #convert backslashes in bzip2 path to forward slashes | ||||||
| @ -71,27 +67,16 @@ build_script: | |||||||
|   # This will produce lots of LNK4099 warnings which can be ignored. |   # This will produce lots of LNK4099 warnings which can be ignored. | ||||||
|   # Unfortunately they can't be disabled, see |   # Unfortunately they can't be disabled, see | ||||||
|   # http://stackoverflow.com/questions/661606/visual-c-how-to-disable-specific-linker-warnings |   # http://stackoverflow.com/questions/661606/visual-c-how-to-disable-specific-linker-warnings | ||||||
|   - cmake .. -LA -G "Visual Studio 14 Win64" |   - cmake -LA -G "Visual Studio 14 Win64" | ||||||
|     -DOsmium_DEBUG=TRUE |     -DOsmium_DEBUG=TRUE | ||||||
|     -DCMAKE_BUILD_TYPE=%config% |     -DCMAKE_BUILD_TYPE=%config% | ||||||
|     -DBUILD_HEADERS=OFF |     -DBUILD_HEADERS=OFF | ||||||
|     -DBOOST_ROOT=%LODEPSDIR%\boost |     -DBOOST_ROOT=%LODEPSDIR%\boost | ||||||
|     -DBoost_PROGRAM_OPTIONS_LIBRARY=%LODEPSDIR%\boost\lib\libboost_program_options-vc140-mt-1_57.lib |     -DBoost_PROGRAM_OPTIONS_LIBRARY=%LODEPSDIR%\boost\lib\libboost_program_options-vc140-mt-1_58.lib | ||||||
|     -DZLIB_LIBRARY=%LODEPSDIR%\zlib\lib\zlibwapi.lib |     -DZLIB_LIBRARY=%LODEPSDIR%\zlib\lib\zlibwapi.lib | ||||||
|     -DZLIB_INCLUDE_DIR=%LODEPSDIR%\zlib\include |     -DBZIP2_LIBRARY_RELEASE=%LIBBZIP2% | ||||||
|     -DEXPAT_LIBRARY=%LODEPSDIR%\expat\lib\libexpat.lib |     -DCMAKE_PREFIX_PATH=%LODEPSDIR%\zlib;%LODEPSDIR%\expat;%LODEPSDIR%\bzip2;%LODEPSDIR%\geos;%LODEPSDIR%\gdal;%LODEPSDIR%\proj;%LODEPSDIR%\sparsehash;%LODEPSDIR%\wingetopt | ||||||
|     -DEXPAT_INCLUDE_DIR=%LODEPSDIR%\expat\include |     .. | ||||||
|     -DBZIP2_LIBRARIES=%LIBBZIP2% |  | ||||||
|     -DBZIP2_INCLUDE_DIR=%LODEPSDIR%\bzip2\include |  | ||||||
|     -DGDAL_LIBRARY=%LODEPSDIR%\gdal\lib\gdal_i.lib |  | ||||||
|     -DGDAL_INCLUDE_DIR=%LODEPSDIR%\gdal\include |  | ||||||
|     -DGEOS_LIBRARY=%LODEPSDIR%\geos\lib\geos.lib |  | ||||||
|     -DGEOS_INCLUDE_DIR=%LODEPSDIR%\geos\include |  | ||||||
|     -DPROJ_LIBRARY=%LODEPSDIR%\proj\lib\proj.lib |  | ||||||
|     -DPROJ_INCLUDE_DIR=%LODEPSDIR%\proj\include |  | ||||||
|     -DSPARSEHASH_INCLUDE_DIR=%LODEPSDIR%\sparsehash\include |  | ||||||
|     -DGETOPT_LIBRARY=%LODEPSDIR%\wingetopt\lib\wingetopt.lib |  | ||||||
|     -DGETOPT_INCLUDE_DIR=%LODEPSDIR%\wingetopt\include |  | ||||||
|   - msbuild libosmium.sln /p:Configuration=%config% /toolsversion:14.0 /p:Platform=x64 /p:PlatformToolset=v140 |   - msbuild libosmium.sln /p:Configuration=%config% /toolsversion:14.0 /p:Platform=x64 /p:PlatformToolset=v140 | ||||||
|   #- cmake .. -LA -G "NMake Makefiles" |   #- cmake .. -LA -G "NMake Makefiles" | ||||||
|   #  -DOsmium_DEBUG=TRUE |   #  -DOsmium_DEBUG=TRUE | ||||||
|  | |||||||
							
								
								
									
										64
									
								
								third_party/libosmium/cmake/FindOsmium.cmake
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										64
									
								
								third_party/libosmium/cmake/FindOsmium.cmake
									
									
									
									
										vendored
									
									
								
							| @ -19,7 +19,7 @@ | |||||||
| #    Then add the following in your CMakeLists.txt: | #    Then add the following in your CMakeLists.txt: | ||||||
| # | # | ||||||
| #      find_package(Osmium REQUIRED COMPONENTS <XXX>) | #      find_package(Osmium REQUIRED COMPONENTS <XXX>) | ||||||
| #      include_directories(${OSMIUM_INCLUDE_DIRS}) | #      include_directories(SYSTEM ${OSMIUM_INCLUDE_DIRS}) | ||||||
| # | # | ||||||
| #    For the <XXX> substitute a space separated list of one or more of the | #    For the <XXX> substitute a space separated list of one or more of the | ||||||
| #    following components: | #    following components: | ||||||
| @ -56,31 +56,13 @@ find_path(OSMIUM_INCLUDE_DIR osmium/osm.hpp | |||||||
|     PATH_SUFFIXES include |     PATH_SUFFIXES include | ||||||
|     PATHS |     PATHS | ||||||
|         ../libosmium |         ../libosmium | ||||||
|         ../../libosmium |  | ||||||
|         libosmium |  | ||||||
|         ~/Library/Frameworks |         ~/Library/Frameworks | ||||||
|         /Library/Frameworks |         /Library/Frameworks | ||||||
|         /usr/local |  | ||||||
|         /usr/ |  | ||||||
|         /opt/local # DarwinPorts |         /opt/local # DarwinPorts | ||||||
|         /opt |         /opt | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| # Handle the QUIETLY and REQUIRED arguments and set OSMIUM_FOUND to TRUE if | set(OSMIUM_INCLUDE_DIRS "${OSMIUM_INCLUDE_DIR}") | ||||||
| # all listed variables are TRUE. |  | ||||||
| include(FindPackageHandleStandardArgs) |  | ||||||
| find_package_handle_standard_args(OSMIUM REQUIRED_VARS OSMIUM_INCLUDE_DIR) |  | ||||||
| 
 |  | ||||||
| # Copy the results to the output variables. |  | ||||||
| if(OSMIUM_FOUND) |  | ||||||
|     set(OSMIUM_INCLUDE_DIRS ${OSMIUM_INCLUDE_DIR}) |  | ||||||
| else() |  | ||||||
|     set(OSMIUM_INCLUDE_DIRS "") |  | ||||||
| endif() |  | ||||||
| 
 |  | ||||||
| if(Osmium_FIND_REQUIRED AND NOT OSMIUM_FOUND) |  | ||||||
|     message(FATAL_ERROR "Can not find libosmium headers, please install them or configure the paths") |  | ||||||
| endif() |  | ||||||
| 
 | 
 | ||||||
| #---------------------------------------------------------------------- | #---------------------------------------------------------------------- | ||||||
| # | # | ||||||
| @ -113,6 +95,7 @@ if(Osmium_USE_PBF) | |||||||
|     find_package(ZLIB) |     find_package(ZLIB) | ||||||
|     find_package(Threads) |     find_package(Threads) | ||||||
| 
 | 
 | ||||||
|  |     list(APPEND OSMIUM_EXTRA_FIND_VARS ZLIB_FOUND Threads_FOUND) | ||||||
|     if(ZLIB_FOUND AND Threads_FOUND) |     if(ZLIB_FOUND AND Threads_FOUND) | ||||||
|         list(APPEND OSMIUM_PBF_LIBRARIES |         list(APPEND OSMIUM_PBF_LIBRARIES | ||||||
|             ${ZLIB_LIBRARIES} |             ${ZLIB_LIBRARIES} | ||||||
| @ -125,7 +108,6 @@ if(Osmium_USE_PBF) | |||||||
|             ${ZLIB_INCLUDE_DIR} |             ${ZLIB_INCLUDE_DIR} | ||||||
|         ) |         ) | ||||||
|     else() |     else() | ||||||
|         set(_missing_libraries 1) |  | ||||||
|         message(WARNING "Osmium: Can not find some libraries for PBF input/output, please install them or configure the paths.") |         message(WARNING "Osmium: Can not find some libraries for PBF input/output, please install them or configure the paths.") | ||||||
|     endif() |     endif() | ||||||
| endif() | endif() | ||||||
| @ -138,6 +120,7 @@ if(Osmium_USE_XML) | |||||||
|     find_package(ZLIB) |     find_package(ZLIB) | ||||||
|     find_package(Threads) |     find_package(Threads) | ||||||
| 
 | 
 | ||||||
|  |     list(APPEND OSMIUM_EXTRA_FIND_VARS EXPAT_FOUND BZIP2_FOUND ZLIB_FOUND Threads_FOUND) | ||||||
|     if(EXPAT_FOUND AND BZIP2_FOUND AND ZLIB_FOUND AND Threads_FOUND) |     if(EXPAT_FOUND AND BZIP2_FOUND AND ZLIB_FOUND AND Threads_FOUND) | ||||||
|         list(APPEND OSMIUM_XML_LIBRARIES |         list(APPEND OSMIUM_XML_LIBRARIES | ||||||
|             ${EXPAT_LIBRARIES} |             ${EXPAT_LIBRARIES} | ||||||
| @ -151,7 +134,6 @@ if(Osmium_USE_XML) | |||||||
|             ${ZLIB_INCLUDE_DIR} |             ${ZLIB_INCLUDE_DIR} | ||||||
|         ) |         ) | ||||||
|     else() |     else() | ||||||
|         set(_missing_libraries 1) |  | ||||||
|         message(WARNING "Osmium: Can not find some libraries for XML input/output, please install them or configure the paths.") |         message(WARNING "Osmium: Can not find some libraries for XML input/output, please install them or configure the paths.") | ||||||
|     endif() |     endif() | ||||||
| endif() | endif() | ||||||
| @ -172,12 +154,12 @@ if(Osmium_USE_GEOS) | |||||||
|     find_path(GEOS_INCLUDE_DIR geos/geom.h) |     find_path(GEOS_INCLUDE_DIR geos/geom.h) | ||||||
|     find_library(GEOS_LIBRARY NAMES geos) |     find_library(GEOS_LIBRARY NAMES geos) | ||||||
| 
 | 
 | ||||||
|  |     list(APPEND OSMIUM_EXTRA_FIND_VARS GEOS_INCLUDE_DIR GEOS_LIBRARY) | ||||||
|     if(GEOS_INCLUDE_DIR AND GEOS_LIBRARY) |     if(GEOS_INCLUDE_DIR AND GEOS_LIBRARY) | ||||||
|         SET(GEOS_FOUND 1) |         SET(GEOS_FOUND 1) | ||||||
|         list(APPEND OSMIUM_LIBRARIES ${GEOS_LIBRARY}) |         list(APPEND OSMIUM_LIBRARIES ${GEOS_LIBRARY}) | ||||||
|         list(APPEND OSMIUM_INCLUDE_DIRS ${GEOS_INCLUDE_DIR}) |         list(APPEND OSMIUM_INCLUDE_DIRS ${GEOS_INCLUDE_DIR}) | ||||||
|     else() |     else() | ||||||
|         set(_missing_libraries 1) |  | ||||||
|         message(WARNING "Osmium: GEOS library is required but not found, please install it or configure the paths.") |         message(WARNING "Osmium: GEOS library is required but not found, please install it or configure the paths.") | ||||||
|     endif() |     endif() | ||||||
| endif() | endif() | ||||||
| @ -187,11 +169,11 @@ endif() | |||||||
| if(Osmium_USE_GDAL) | if(Osmium_USE_GDAL) | ||||||
|     find_package(GDAL) |     find_package(GDAL) | ||||||
| 
 | 
 | ||||||
|  |     list(APPEND OSMIUM_EXTRA_FIND_VARS GDAL_FOUND) | ||||||
|     if(GDAL_FOUND) |     if(GDAL_FOUND) | ||||||
|         list(APPEND OSMIUM_LIBRARIES ${GDAL_LIBRARIES}) |         list(APPEND OSMIUM_LIBRARIES ${GDAL_LIBRARIES}) | ||||||
|         list(APPEND OSMIUM_INCLUDE_DIRS ${GDAL_INCLUDE_DIRS}) |         list(APPEND OSMIUM_INCLUDE_DIRS ${GDAL_INCLUDE_DIRS}) | ||||||
|     else() |     else() | ||||||
|         set(_missing_libraries 1) |  | ||||||
|         message(WARNING "Osmium: GDAL library is required but not found, please install it or configure the paths.") |         message(WARNING "Osmium: GDAL library is required but not found, please install it or configure the paths.") | ||||||
|     endif() |     endif() | ||||||
| endif() | endif() | ||||||
| @ -202,12 +184,12 @@ if(Osmium_USE_PROJ) | |||||||
|     find_path(PROJ_INCLUDE_DIR proj_api.h) |     find_path(PROJ_INCLUDE_DIR proj_api.h) | ||||||
|     find_library(PROJ_LIBRARY NAMES proj) |     find_library(PROJ_LIBRARY NAMES proj) | ||||||
| 
 | 
 | ||||||
|  |     list(APPEND OSMIUM_EXTRA_FIND_VARS PROJ_INCLUDE_DIR PROJ_LIBRARY) | ||||||
|     if(PROJ_INCLUDE_DIR AND PROJ_LIBRARY) |     if(PROJ_INCLUDE_DIR AND PROJ_LIBRARY) | ||||||
|         set(PROJ_FOUND 1) |         set(PROJ_FOUND 1) | ||||||
|         list(APPEND OSMIUM_LIBRARIES ${PROJ_LIBRARY}) |         list(APPEND OSMIUM_LIBRARIES ${PROJ_LIBRARY}) | ||||||
|         list(APPEND OSMIUM_INCLUDE_DIRS ${PROJ_INCLUDE_DIR}) |         list(APPEND OSMIUM_INCLUDE_DIRS ${PROJ_INCLUDE_DIR}) | ||||||
|     else() |     else() | ||||||
|         set(_missing_libraries 1) |  | ||||||
|         message(WARNING "Osmium: PROJ.4 library is required but not found, please install it or configure the paths.") |         message(WARNING "Osmium: PROJ.4 library is required but not found, please install it or configure the paths.") | ||||||
|     endif() |     endif() | ||||||
| endif() | endif() | ||||||
| @ -217,21 +199,19 @@ endif() | |||||||
| if(Osmium_USE_SPARSEHASH) | if(Osmium_USE_SPARSEHASH) | ||||||
|     find_path(SPARSEHASH_INCLUDE_DIR google/sparsetable) |     find_path(SPARSEHASH_INCLUDE_DIR google/sparsetable) | ||||||
| 
 | 
 | ||||||
|  |     list(APPEND OSMIUM_EXTRA_FIND_VARS SPARSEHASH_INCLUDE_DIR) | ||||||
|     if(SPARSEHASH_INCLUDE_DIR) |     if(SPARSEHASH_INCLUDE_DIR) | ||||||
|         # Find size of sparsetable::size_type. This does not work on older |         # Find size of sparsetable::size_type. This does not work on older | ||||||
|         # CMake versions because they can do this check only in C, not in C++. |         # CMake versions because they can do this check only in C, not in C++. | ||||||
|         include(CheckTypeSize) |         if (NOT CMAKE_VERSION VERSION_LESS 3.0) | ||||||
|         set(CMAKE_REQUIRED_INCLUDES ${SPARSEHASH_INCLUDE_DIR}) |            include(CheckTypeSize) | ||||||
|         set(CMAKE_EXTRA_INCLUDE_FILES "google/sparsetable") |            set(CMAKE_REQUIRED_INCLUDES ${SPARSEHASH_INCLUDE_DIR}) | ||||||
|         check_type_size("google::sparsetable<int>::size_type" SPARSETABLE_SIZE_TYPE LANGUAGE CXX) |            set(CMAKE_EXTRA_INCLUDE_FILES "google/sparsetable") | ||||||
|         set(CMAKE_EXTRA_INCLUDE_FILES) |            check_type_size("google::sparsetable<int>::size_type" SPARSETABLE_SIZE_TYPE LANGUAGE CXX) | ||||||
|         set(CMAKE_REQUIRED_INCLUDES) |            set(CMAKE_EXTRA_INCLUDE_FILES) | ||||||
| 
 |            set(CMAKE_REQUIRED_INCLUDES) | ||||||
|         # Falling back to checking size_t if google::sparsetable<int>::size_type |         else() | ||||||
|         # could not be checked. |            set(SPARSETABLE_SIZE_TYPE ${CMAKE_SIZEOF_VOID_P}) | ||||||
|         if(SPARSETABLE_SIZE_TYPE STREQUAL "") |  | ||||||
|             check_type_size("void*" VOID_PTR_SIZE) |  | ||||||
|             set(SPARSETABLE_SIZE_TYPE ${VOID_PTR_SIZE}) |  | ||||||
|         endif() |         endif() | ||||||
| 
 | 
 | ||||||
|         # Sparsetable::size_type must be at least 8 bytes (64bit), otherwise |         # Sparsetable::size_type must be at least 8 bytes (64bit), otherwise | ||||||
| @ -244,7 +224,6 @@ if(Osmium_USE_SPARSEHASH) | |||||||
|             message(WARNING "Osmium: Disabled Google SparseHash library on 32bit system (size_type=${SPARSETABLE_SIZE_TYPE}).") |             message(WARNING "Osmium: Disabled Google SparseHash library on 32bit system (size_type=${SPARSETABLE_SIZE_TYPE}).") | ||||||
|         endif() |         endif() | ||||||
|     else() |     else() | ||||||
|         set(_missing_libraries 1) |  | ||||||
|         message(WARNING "Osmium: Google SparseHash library is required but not found, please install it or configure the paths.") |         message(WARNING "Osmium: Google SparseHash library is required but not found, please install it or configure the paths.") | ||||||
|     endif() |     endif() | ||||||
| endif() | endif() | ||||||
| @ -274,9 +253,14 @@ endif() | |||||||
| #  Check that all required libraries are available | #  Check that all required libraries are available | ||||||
| # | # | ||||||
| #---------------------------------------------------------------------- | #---------------------------------------------------------------------- | ||||||
| if(Osmium_FIND_REQUIRED AND _missing_libraries) | if (OSMIUM_EXTRA_FIND_VARS) | ||||||
|     message(FATAL_ERROR "Required library or libraries missing. Aborting.") |     list(REMOVE_DUPLICATES OSMIUM_EXTRA_FIND_VARS) | ||||||
| endif() | endif() | ||||||
|  | # Handle the QUIETLY and REQUIRED arguments and set OSMIUM_FOUND to TRUE if | ||||||
|  | # all listed variables are TRUE. | ||||||
|  | include(FindPackageHandleStandardArgs) | ||||||
|  | find_package_handle_standard_args(Osmium REQUIRED_VARS OSMIUM_INCLUDE_DIR ${OSMIUM_EXTRA_FIND_VARS}) | ||||||
|  | unset(OSMIUM_EXTRA_FIND_VARS) | ||||||
| 
 | 
 | ||||||
| #---------------------------------------------------------------------- | #---------------------------------------------------------------------- | ||||||
| # | # | ||||||
|  | |||||||
							
								
								
									
										2
									
								
								third_party/libosmium/cmake/iwyu.sh
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								third_party/libosmium/cmake/iwyu.sh
									
									
									
									
										vendored
									
									
								
							| @ -16,7 +16,7 @@ echo "INCLUDE WHAT YOU USE REPORT:" >$log | |||||||
| 
 | 
 | ||||||
| allok=yes | allok=yes | ||||||
| 
 | 
 | ||||||
| for file in `find include/osmium -name \*.hpp`; do | for file in `find include/osmium -name \*.hpp | sort`; do | ||||||
|     mkdir -p `dirname build/check_reports/$file` |     mkdir -p `dirname build/check_reports/$file` | ||||||
|     ifile="build/check_reports/${file%.hpp}.iwyu" |     ifile="build/check_reports/${file%.hpp}.iwyu" | ||||||
|     $cmdline $file >$ifile 2>&1 |     $cmdline $file >$ifile 2>&1 | ||||||
|  | |||||||
							
								
								
									
										27
									
								
								third_party/libosmium/examples/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										27
									
								
								third_party/libosmium/examples/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							| @ -14,12 +14,10 @@ set(EXAMPLES | |||||||
|     count |     count | ||||||
|     create_node_cache |     create_node_cache | ||||||
|     debug |     debug | ||||||
|  |     filter_discussions | ||||||
|     index |     index | ||||||
|     read |     read | ||||||
|     serdump |     serdump | ||||||
|     toogr |  | ||||||
|     toogr2 |  | ||||||
|     toogr2_exp |  | ||||||
|     use_node_cache |     use_node_cache | ||||||
|     CACHE STRING "Example programs" |     CACHE STRING "Example programs" | ||||||
| ) | ) | ||||||
| @ -30,7 +28,7 @@ set(EXAMPLES | |||||||
| #  Examples depending on wingetopt | #  Examples depending on wingetopt | ||||||
| # | # | ||||||
| #----------------------------------------------------------------------------- | #----------------------------------------------------------------------------- | ||||||
| set(GETOPT_EXAMPLES area_test convert serdump toogr toogr2 toogr2_exp) | set(GETOPT_EXAMPLES area_test convert serdump) | ||||||
| if(NOT GETOPT_MISSING) | if(NOT GETOPT_MISSING) | ||||||
|     foreach(example ${GETOPT_EXAMPLES}) |     foreach(example ${GETOPT_EXAMPLES}) | ||||||
|         list(APPEND EXAMPLE_LIBS_${example} ${GETOPT_LIBRARY}) |         list(APPEND EXAMPLE_LIBS_${example} ${GETOPT_LIBRARY}) | ||||||
| @ -74,27 +72,6 @@ else() | |||||||
| endif() | endif() | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| #----------------------------------------------------------------------------- |  | ||||||
| # |  | ||||||
| #  Examples depending on GDAL/PROJ.4/SparseHash |  | ||||||
| # |  | ||||||
| #----------------------------------------------------------------------------- |  | ||||||
| set(OGR_EXAMPLES toogr toogr2 toogr2_exp) |  | ||||||
| 
 |  | ||||||
| if(GDAL_FOUND AND PROJ_FOUND AND SPARSEHASH_FOUND) |  | ||||||
|     foreach(example ${OGR_EXAMPLES}) |  | ||||||
|         list(APPEND EXAMPLE_LIBS_${example} ${GDAL_LIBRARIES}) |  | ||||||
|         list(APPEND EXAMPLE_LIBS_${example} ${PROJ_LIBRARIES}) |  | ||||||
|     endforeach() |  | ||||||
| else() |  | ||||||
|     message(STATUS "Configuring examples - Skipping examples because GDAL and/or Proj.4 and/or SparseHash not found:") |  | ||||||
|     foreach(example ${OGR_EXAMPLES}) |  | ||||||
|         message(STATUS "  - osmium_${example}") |  | ||||||
|         list(REMOVE_ITEM EXAMPLES ${example}) |  | ||||||
|     endforeach() |  | ||||||
| endif() |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| #----------------------------------------------------------------------------- | #----------------------------------------------------------------------------- | ||||||
| # | # | ||||||
| #  Configure examples | #  Configure examples | ||||||
|  | |||||||
							
								
								
									
										72
									
								
								third_party/libosmium/examples/osmium_filter_discussions.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								third_party/libosmium/examples/osmium_filter_discussions.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,72 @@ | |||||||
|  | /*
 | ||||||
|  | 
 | ||||||
|  |   Read OSM changesets with discussions from a changeset dump like the one | ||||||
|  |   you get from http://planet.osm.org/planet/discussions-latest.osm.bz2
 | ||||||
|  |   and write out only those changesets which have discussions (ie comments). | ||||||
|  | 
 | ||||||
|  |   The code in this example file is released into the Public Domain. | ||||||
|  | 
 | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | #include <algorithm> // for std::copy_if
 | ||||||
|  | #include <iostream> // for std::cout, std::cerr
 | ||||||
|  | 
 | ||||||
|  | // we want to read OSM files in XML format
 | ||||||
|  | // (other formats don't support full changesets, so only XML is needed here)
 | ||||||
|  | #include <osmium/io/xml_input.hpp> | ||||||
|  | #include <osmium/io/input_iterator.hpp> | ||||||
|  | 
 | ||||||
|  | // we want to write OSM files in XML format
 | ||||||
|  | #include <osmium/io/xml_output.hpp> | ||||||
|  | #include <osmium/io/output_iterator.hpp> | ||||||
|  | 
 | ||||||
|  | // we want to support any compressioon (.gz2 and .bz2)
 | ||||||
|  | #include <osmium/io/any_compression.hpp> | ||||||
|  | 
 | ||||||
|  | int main(int argc, char* argv[]) { | ||||||
|  |     if (argc != 3) { | ||||||
|  |         std::cout << "Usage: " << argv[0] << " INFILE OUTFILE\n"; | ||||||
|  |         exit(1); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // The input file, deduce file format from file suffix
 | ||||||
|  |     osmium::io::File infile(argv[1]); | ||||||
|  | 
 | ||||||
|  |     // The output file, force class XML OSM file format
 | ||||||
|  |     osmium::io::File outfile(argv[2], "osm"); | ||||||
|  | 
 | ||||||
|  |     // Initialize Reader for the input file.
 | ||||||
|  |     // Read only changesets (will ignore nodes, ways, and
 | ||||||
|  |     // relations if there are any).
 | ||||||
|  |     osmium::io::Reader reader(infile, osmium::osm_entity_bits::changeset); | ||||||
|  | 
 | ||||||
|  |     // Get the header from the input file
 | ||||||
|  |     osmium::io::Header header = reader.header(); | ||||||
|  | 
 | ||||||
|  |     // Initialize writer for the output file. Use the header from the input
 | ||||||
|  |     // file for the output file. This will copy over some header information.
 | ||||||
|  |     // The last parameter will tell the writer that it is allowed to overwrite
 | ||||||
|  |     // an existing file. Without it, it will refuse to do so.
 | ||||||
|  |     osmium::io::Writer writer(outfile, header, osmium::io::overwrite::allow); | ||||||
|  | 
 | ||||||
|  |     // Create range of input iterators that will iterator over all changesets
 | ||||||
|  |     // delivered from input file through the "reader".
 | ||||||
|  |     auto input_range = osmium::io::make_input_iterator_range<osmium::Changeset>(reader); | ||||||
|  | 
 | ||||||
|  |     // Create an output iterator writing through the "writer" object to the
 | ||||||
|  |     // output file.
 | ||||||
|  |     auto output_iterator = osmium::io::make_output_iterator(writer); | ||||||
|  | 
 | ||||||
|  |     // Copy all changesets from input to output that have at least one comment.
 | ||||||
|  |     std::copy_if(input_range.begin(), input_range.end(), output_iterator, [](const osmium::Changeset& changeset) { | ||||||
|  |         return changeset.num_comments() > 0; | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     // Explicitly close the writer and reader. Will throw an exception if
 | ||||||
|  |     // there is a problem. If you wait for the destructor to close the writer
 | ||||||
|  |     // and reader, you will not notice the problem, because destructors must
 | ||||||
|  |     // not throw.
 | ||||||
|  |     writer.close(); | ||||||
|  |     reader.close(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
							
								
								
									
										244
									
								
								third_party/libosmium/examples/osmium_toogr.cpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										244
									
								
								third_party/libosmium/examples/osmium_toogr.cpp
									
									
									
									
										vendored
									
									
								
							| @ -1,244 +0,0 @@ | |||||||
| /*
 |  | ||||||
| 
 |  | ||||||
|   This is an example tool that converts OSM data to some output format |  | ||||||
|   like Spatialite or Shapefiles using the OGR library. |  | ||||||
| 
 |  | ||||||
|   The code in this example file is released into the Public Domain. |  | ||||||
| 
 |  | ||||||
| */ |  | ||||||
| 
 |  | ||||||
| #include <iostream> |  | ||||||
| #include <getopt.h> |  | ||||||
| 
 |  | ||||||
| #include <osmium/index/map/all.hpp> |  | ||||||
| #include <osmium/handler/node_locations_for_ways.hpp> |  | ||||||
| #include <osmium/visitor.hpp> |  | ||||||
| 
 |  | ||||||
| #include <osmium/geom/ogr.hpp> |  | ||||||
| #include <osmium/io/any_input.hpp> |  | ||||||
| #include <osmium/handler.hpp> |  | ||||||
| 
 |  | ||||||
| typedef osmium::index::map::Dummy<osmium::unsigned_object_id_type, osmium::Location> index_neg_type; |  | ||||||
| typedef osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location> index_pos_type; |  | ||||||
| 
 |  | ||||||
| typedef osmium::handler::NodeLocationsForWays<index_pos_type, index_neg_type> location_handler_type; |  | ||||||
| 
 |  | ||||||
| class MyOGRHandler : public osmium::handler::Handler { |  | ||||||
| 
 |  | ||||||
|     OGRDataSource* m_data_source; |  | ||||||
|     OGRLayer* m_layer_point; |  | ||||||
|     OGRLayer* m_layer_linestring; |  | ||||||
| 
 |  | ||||||
|     osmium::geom::OGRFactory<> m_factory; |  | ||||||
| 
 |  | ||||||
| public: |  | ||||||
| 
 |  | ||||||
|     MyOGRHandler(const std::string& driver_name, const std::string& filename) { |  | ||||||
| 
 |  | ||||||
|         OGRRegisterAll(); |  | ||||||
| 
 |  | ||||||
|         OGRSFDriver* driver = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName(driver_name.c_str()); |  | ||||||
|         if (!driver) { |  | ||||||
|             std::cerr << driver_name << " driver not available.\n"; |  | ||||||
|             exit(1); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         CPLSetConfigOption("OGR_SQLITE_SYNCHRONOUS", "FALSE"); |  | ||||||
|         const char* options[] = { "SPATIALITE=TRUE", nullptr }; |  | ||||||
|         m_data_source = driver->CreateDataSource(filename.c_str(), const_cast<char**>(options)); |  | ||||||
|         if (!m_data_source) { |  | ||||||
|             std::cerr << "Creation of output file failed.\n"; |  | ||||||
|             exit(1); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         OGRSpatialReference sparef; |  | ||||||
|         sparef.SetWellKnownGeogCS("WGS84"); |  | ||||||
|         m_layer_point = m_data_source->CreateLayer("postboxes", &sparef, wkbPoint, nullptr); |  | ||||||
|         if (!m_layer_point) { |  | ||||||
|             std::cerr << "Layer creation failed.\n"; |  | ||||||
|             exit(1); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         OGRFieldDefn layer_point_field_id("id", OFTReal); |  | ||||||
|         layer_point_field_id.SetWidth(10); |  | ||||||
| 
 |  | ||||||
|         if (m_layer_point->CreateField(&layer_point_field_id) != OGRERR_NONE) { |  | ||||||
|             std::cerr << "Creating id field failed.\n"; |  | ||||||
|             exit(1); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         OGRFieldDefn layer_point_field_operator("operator", OFTString); |  | ||||||
|         layer_point_field_operator.SetWidth(30); |  | ||||||
| 
 |  | ||||||
|         if (m_layer_point->CreateField(&layer_point_field_operator) != OGRERR_NONE) { |  | ||||||
|             std::cerr << "Creating operator field failed.\n"; |  | ||||||
|             exit(1); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         /* Transactions might make things faster, then again they might not.
 |  | ||||||
|            Feel free to experiment and benchmark and report back. */ |  | ||||||
|         m_layer_point->StartTransaction(); |  | ||||||
| 
 |  | ||||||
|         m_layer_linestring = m_data_source->CreateLayer("roads", &sparef, wkbLineString, nullptr); |  | ||||||
|         if (!m_layer_linestring) { |  | ||||||
|             std::cerr << "Layer creation failed.\n"; |  | ||||||
|             exit(1); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         OGRFieldDefn layer_linestring_field_id("id", OFTReal); |  | ||||||
|         layer_linestring_field_id.SetWidth(10); |  | ||||||
| 
 |  | ||||||
|         if (m_layer_linestring->CreateField(&layer_linestring_field_id) != OGRERR_NONE) { |  | ||||||
|             std::cerr << "Creating id field failed.\n"; |  | ||||||
|             exit(1); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         OGRFieldDefn layer_linestring_field_type("type", OFTString); |  | ||||||
|         layer_linestring_field_type.SetWidth(30); |  | ||||||
| 
 |  | ||||||
|         if (m_layer_linestring->CreateField(&layer_linestring_field_type) != OGRERR_NONE) { |  | ||||||
|             std::cerr << "Creating type field failed.\n"; |  | ||||||
|             exit(1); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         m_layer_linestring->StartTransaction(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     ~MyOGRHandler() { |  | ||||||
|         m_layer_linestring->CommitTransaction(); |  | ||||||
|         m_layer_point->CommitTransaction(); |  | ||||||
|         OGRDataSource::DestroyDataSource(m_data_source); |  | ||||||
|         OGRCleanupAll(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     void node(const osmium::Node& node) { |  | ||||||
|         const char* amenity = node.tags().get_value_by_key("amenity"); |  | ||||||
|         if (amenity && !strcmp(amenity, "post_box")) { |  | ||||||
|             OGRFeature* feature = OGRFeature::CreateFeature(m_layer_point->GetLayerDefn()); |  | ||||||
|             std::unique_ptr<OGRPoint> ogr_point = m_factory.create_point(node); |  | ||||||
|             feature->SetGeometry(ogr_point.get()); |  | ||||||
|             feature->SetField("id", static_cast<double>(node.id())); |  | ||||||
|             feature->SetField("operator", node.tags().get_value_by_key("operator")); |  | ||||||
| 
 |  | ||||||
|             if (m_layer_point->CreateFeature(feature) != OGRERR_NONE) { |  | ||||||
|                 std::cerr << "Failed to create feature.\n"; |  | ||||||
|                 exit(1); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             OGRFeature::DestroyFeature(feature); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     void way(const osmium::Way& way) { |  | ||||||
|         const char* highway = way.tags().get_value_by_key("highway"); |  | ||||||
|         if (highway) { |  | ||||||
|             try { |  | ||||||
|                 std::unique_ptr<OGRLineString> ogr_linestring = m_factory.create_linestring(way); |  | ||||||
|                 OGRFeature* feature = OGRFeature::CreateFeature(m_layer_linestring->GetLayerDefn()); |  | ||||||
|                 feature->SetGeometry(ogr_linestring.get()); |  | ||||||
|                 feature->SetField("id", static_cast<double>(way.id())); |  | ||||||
|                 feature->SetField("type", highway); |  | ||||||
| 
 |  | ||||||
|                 if (m_layer_linestring->CreateFeature(feature) != OGRERR_NONE) { |  | ||||||
|                     std::cerr << "Failed to create feature.\n"; |  | ||||||
|                     exit(1); |  | ||||||
|                 } |  | ||||||
| 
 |  | ||||||
|                 OGRFeature::DestroyFeature(feature); |  | ||||||
|             } catch (osmium::geometry_error&) { |  | ||||||
|                 std::cerr << "Ignoring illegal geometry for way " << way.id() << ".\n"; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| /* ================================================== */ |  | ||||||
| 
 |  | ||||||
| void print_help() { |  | ||||||
|     std::cout << "osmium_toogr [OPTIONS] [INFILE [OUTFILE]]\n\n" \ |  | ||||||
|               << "If INFILE is not given stdin is assumed.\n" \ |  | ||||||
|               << "If OUTFILE is not given 'ogr_out' is used.\n" \ |  | ||||||
|               << "\nOptions:\n" \ |  | ||||||
|               << "  -h, --help                 This help message\n" \ |  | ||||||
|               << "  -l, --location_store=TYPE  Set location store\n" \ |  | ||||||
|               << "  -f, --format=FORMAT        Output OGR format (Default: 'SQLite')\n" \ |  | ||||||
|               << "  -L                         See available location stores\n"; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| int main(int argc, char* argv[]) { |  | ||||||
|     const auto& map_factory = osmium::index::MapFactory<osmium::unsigned_object_id_type, osmium::Location>::instance(); |  | ||||||
| 
 |  | ||||||
|     static struct option long_options[] = { |  | ||||||
|         {"help",                 no_argument, 0, 'h'}, |  | ||||||
|         {"format",               required_argument, 0, 'f'}, |  | ||||||
|         {"location_store",       required_argument, 0, 'l'}, |  | ||||||
|         {"list_location_stores", no_argument, 0, 'L'}, |  | ||||||
|         {0, 0, 0, 0} |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     std::string output_format { "SQLite" }; |  | ||||||
|     std::string location_store { "sparse_mem_array" }; |  | ||||||
| 
 |  | ||||||
|     while (true) { |  | ||||||
|         int c = getopt_long(argc, argv, "hf:l:L", long_options, 0); |  | ||||||
|         if (c == -1) { |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         switch (c) { |  | ||||||
|             case 'h': |  | ||||||
|                 print_help(); |  | ||||||
|                 exit(0); |  | ||||||
|             case 'f': |  | ||||||
|                 output_format = optarg; |  | ||||||
|                 break; |  | ||||||
|             case 'l': |  | ||||||
|                 location_store = optarg; |  | ||||||
|                 break; |  | ||||||
|             case 'L': |  | ||||||
|                 std::cout << "Available map types:\n"; |  | ||||||
|                 for (const auto& map_type : map_factory.map_types()) { |  | ||||||
|                     std::cout << "  " << map_type << "\n"; |  | ||||||
|                 } |  | ||||||
|                 exit(0); |  | ||||||
|             default: |  | ||||||
|                 exit(1); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     std::string input_filename; |  | ||||||
|     std::string output_filename("ogr_out"); |  | ||||||
|     int remaining_args = argc - optind; |  | ||||||
|     if (remaining_args > 2) { |  | ||||||
|         std::cerr << "Usage: " << argv[0] << " [OPTIONS] [INFILE [OUTFILE]]" << std::endl; |  | ||||||
|         exit(1); |  | ||||||
|     } else if (remaining_args == 2) { |  | ||||||
|         input_filename =  argv[optind]; |  | ||||||
|         output_filename = argv[optind+1]; |  | ||||||
|     } else if (remaining_args == 1) { |  | ||||||
|         input_filename =  argv[optind]; |  | ||||||
|     } else { |  | ||||||
|         input_filename = "-"; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     osmium::io::Reader reader(input_filename); |  | ||||||
| 
 |  | ||||||
|     std::unique_ptr<index_pos_type> index_pos = map_factory.create_map(location_store); |  | ||||||
|     index_neg_type index_neg; |  | ||||||
|     location_handler_type location_handler(*index_pos, index_neg); |  | ||||||
|     location_handler.ignore_errors(); |  | ||||||
| 
 |  | ||||||
|     MyOGRHandler ogr_handler(output_format, output_filename); |  | ||||||
| 
 |  | ||||||
|     osmium::apply(reader, location_handler, ogr_handler); |  | ||||||
|     reader.close(); |  | ||||||
| 
 |  | ||||||
|     int locations_fd = open("locations.dump", O_WRONLY | O_CREAT, 0644); |  | ||||||
|     if (locations_fd < 0) { |  | ||||||
|         throw std::system_error(errno, std::system_category(), "Open failed"); |  | ||||||
|     } |  | ||||||
|     index_pos->dump_as_list(locations_fd); |  | ||||||
|     close(locations_fd); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
							
								
								
									
										331
									
								
								third_party/libosmium/examples/osmium_toogr2.cpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										331
									
								
								third_party/libosmium/examples/osmium_toogr2.cpp
									
									
									
									
										vendored
									
									
								
							| @ -1,331 +0,0 @@ | |||||||
| /*
 |  | ||||||
| 
 |  | ||||||
|   This is an example tool that converts OSM data to some output format |  | ||||||
|   like Spatialite or Shapefiles using the OGR library. |  | ||||||
| 
 |  | ||||||
|   This version does multipolygon handling (in contrast to the osmium_toogr |  | ||||||
|   example which doesn't). |  | ||||||
| 
 |  | ||||||
|   The code in this example file is released into the Public Domain. |  | ||||||
| 
 |  | ||||||
| */ |  | ||||||
| 
 |  | ||||||
| #include <iostream> |  | ||||||
| #include <getopt.h> |  | ||||||
| 
 |  | ||||||
| // usually you only need one or two of these
 |  | ||||||
| #include <osmium/index/map/dummy.hpp> |  | ||||||
| #include <osmium/index/map/sparse_mem_array.hpp> |  | ||||||
| 
 |  | ||||||
| #include <osmium/handler/node_locations_for_ways.hpp> |  | ||||||
| #include <osmium/visitor.hpp> |  | ||||||
| #include <osmium/area/multipolygon_collector.hpp> |  | ||||||
| #include <osmium/area/assembler.hpp> |  | ||||||
| 
 |  | ||||||
| #include <osmium/geom/mercator_projection.hpp> |  | ||||||
| //#include <osmium/geom/projection.hpp>
 |  | ||||||
| #include <osmium/geom/ogr.hpp> |  | ||||||
| #include <osmium/io/any_input.hpp> |  | ||||||
| #include <osmium/handler.hpp> |  | ||||||
| 
 |  | ||||||
| typedef osmium::index::map::Dummy<osmium::unsigned_object_id_type, osmium::Location> index_neg_type; |  | ||||||
| 
 |  | ||||||
| typedef osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, osmium::Location> index_pos_type; |  | ||||||
| 
 |  | ||||||
| typedef osmium::handler::NodeLocationsForWays<index_pos_type, index_neg_type> location_handler_type; |  | ||||||
| 
 |  | ||||||
| class MyOGRHandler : public osmium::handler::Handler { |  | ||||||
| 
 |  | ||||||
|     OGRDataSource* m_data_source; |  | ||||||
|     OGRLayer* m_layer_point; |  | ||||||
|     OGRLayer* m_layer_linestring; |  | ||||||
|     OGRLayer* m_layer_polygon; |  | ||||||
| 
 |  | ||||||
|     // Choose one of the following:
 |  | ||||||
| 
 |  | ||||||
|     // 1. Use WGS84, do not project coordinates.
 |  | ||||||
|     //osmium::geom::OGRFactory<> m_factory {};
 |  | ||||||
| 
 |  | ||||||
|     // 2. Project coordinates into "Web Mercator".
 |  | ||||||
|     osmium::geom::OGRFactory<osmium::geom::MercatorProjection> m_factory; |  | ||||||
| 
 |  | ||||||
|     // 3. Use any projection that the proj library can handle.
 |  | ||||||
|     //    (Initialize projection with EPSG code or proj string).
 |  | ||||||
|     //    In addition you need to link with "-lproj" and add
 |  | ||||||
|     //    #include <osmium/geom/projection.hpp>.
 |  | ||||||
|     //osmium::geom::OGRFactory<osmium::geom::Projection> m_factory {osmium::geom::Projection(3857)};
 |  | ||||||
| 
 |  | ||||||
| public: |  | ||||||
| 
 |  | ||||||
|     MyOGRHandler(const std::string& driver_name, const std::string& filename) { |  | ||||||
| 
 |  | ||||||
|         OGRRegisterAll(); |  | ||||||
| 
 |  | ||||||
|         OGRSFDriver* driver = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName(driver_name.c_str()); |  | ||||||
|         if (!driver) { |  | ||||||
|             std::cerr << driver_name << " driver not available.\n"; |  | ||||||
|             exit(1); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         CPLSetConfigOption("OGR_SQLITE_SYNCHRONOUS", "FALSE"); |  | ||||||
|         const char* options[] = { "SPATIALITE=TRUE", nullptr }; |  | ||||||
|         m_data_source = driver->CreateDataSource(filename.c_str(), const_cast<char**>(options)); |  | ||||||
|         if (!m_data_source) { |  | ||||||
|             std::cerr << "Creation of output file failed.\n"; |  | ||||||
|             exit(1); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         OGRSpatialReference sparef; |  | ||||||
|         sparef.importFromProj4(m_factory.proj_string().c_str()); |  | ||||||
| 
 |  | ||||||
|         m_layer_point = m_data_source->CreateLayer("postboxes", &sparef, wkbPoint, nullptr); |  | ||||||
|         if (!m_layer_point) { |  | ||||||
|             std::cerr << "Layer creation failed.\n"; |  | ||||||
|             exit(1); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         OGRFieldDefn layer_point_field_id("id", OFTReal); |  | ||||||
|         layer_point_field_id.SetWidth(10); |  | ||||||
| 
 |  | ||||||
|         if (m_layer_point->CreateField(&layer_point_field_id) != OGRERR_NONE) { |  | ||||||
|             std::cerr << "Creating id field failed.\n"; |  | ||||||
|             exit(1); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         OGRFieldDefn layer_point_field_operator("operator", OFTString); |  | ||||||
|         layer_point_field_operator.SetWidth(30); |  | ||||||
| 
 |  | ||||||
|         if (m_layer_point->CreateField(&layer_point_field_operator) != OGRERR_NONE) { |  | ||||||
|             std::cerr << "Creating operator field failed.\n"; |  | ||||||
|             exit(1); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         /* Transactions might make things faster, then again they might not.
 |  | ||||||
|            Feel free to experiment and benchmark and report back. */ |  | ||||||
|         m_layer_point->StartTransaction(); |  | ||||||
| 
 |  | ||||||
|         m_layer_linestring = m_data_source->CreateLayer("roads", &sparef, wkbLineString, nullptr); |  | ||||||
|         if (!m_layer_linestring) { |  | ||||||
|             std::cerr << "Layer creation failed.\n"; |  | ||||||
|             exit(1); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         OGRFieldDefn layer_linestring_field_id("id", OFTReal); |  | ||||||
|         layer_linestring_field_id.SetWidth(10); |  | ||||||
| 
 |  | ||||||
|         if (m_layer_linestring->CreateField(&layer_linestring_field_id) != OGRERR_NONE) { |  | ||||||
|             std::cerr << "Creating id field failed.\n"; |  | ||||||
|             exit(1); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         OGRFieldDefn layer_linestring_field_type("type", OFTString); |  | ||||||
|         layer_linestring_field_type.SetWidth(30); |  | ||||||
| 
 |  | ||||||
|         if (m_layer_linestring->CreateField(&layer_linestring_field_type) != OGRERR_NONE) { |  | ||||||
|             std::cerr << "Creating type field failed.\n"; |  | ||||||
|             exit(1); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         m_layer_linestring->StartTransaction(); |  | ||||||
| 
 |  | ||||||
|         m_layer_polygon = m_data_source->CreateLayer("buildings", &sparef, wkbMultiPolygon, nullptr); |  | ||||||
|         if (!m_layer_polygon) { |  | ||||||
|             std::cerr << "Layer creation failed.\n"; |  | ||||||
|             exit(1); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         OGRFieldDefn layer_polygon_field_id("id", OFTInteger); |  | ||||||
|         layer_polygon_field_id.SetWidth(10); |  | ||||||
| 
 |  | ||||||
|         if (m_layer_polygon->CreateField(&layer_polygon_field_id) != OGRERR_NONE) { |  | ||||||
|             std::cerr << "Creating id field failed.\n"; |  | ||||||
|             exit(1); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         OGRFieldDefn layer_polygon_field_type("type", OFTString); |  | ||||||
|         layer_polygon_field_type.SetWidth(30); |  | ||||||
| 
 |  | ||||||
|         if (m_layer_polygon->CreateField(&layer_polygon_field_type) != OGRERR_NONE) { |  | ||||||
|             std::cerr << "Creating type field failed.\n"; |  | ||||||
|             exit(1); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         m_layer_polygon->StartTransaction(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     ~MyOGRHandler() { |  | ||||||
|         m_layer_polygon->CommitTransaction(); |  | ||||||
|         m_layer_linestring->CommitTransaction(); |  | ||||||
|         m_layer_point->CommitTransaction(); |  | ||||||
|         OGRDataSource::DestroyDataSource(m_data_source); |  | ||||||
|         OGRCleanupAll(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     void node(const osmium::Node& node) { |  | ||||||
|         const char* amenity = node.tags()["amenity"]; |  | ||||||
|         if (amenity && !strcmp(amenity, "post_box")) { |  | ||||||
|             OGRFeature* feature = OGRFeature::CreateFeature(m_layer_point->GetLayerDefn()); |  | ||||||
|             std::unique_ptr<OGRPoint> ogr_point = m_factory.create_point(node); |  | ||||||
|             feature->SetGeometry(ogr_point.get()); |  | ||||||
|             feature->SetField("id", static_cast<double>(node.id())); |  | ||||||
|             feature->SetField("operator", node.tags()["operator"]); |  | ||||||
| 
 |  | ||||||
|             if (m_layer_point->CreateFeature(feature) != OGRERR_NONE) { |  | ||||||
|                 std::cerr << "Failed to create feature.\n"; |  | ||||||
|                 exit(1); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             OGRFeature::DestroyFeature(feature); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     void way(const osmium::Way& way) { |  | ||||||
|         const char* highway = way.tags()["highway"]; |  | ||||||
|         if (highway) { |  | ||||||
|             try { |  | ||||||
|                 std::unique_ptr<OGRLineString> ogr_linestring = m_factory.create_linestring(way); |  | ||||||
|                 OGRFeature* feature = OGRFeature::CreateFeature(m_layer_linestring->GetLayerDefn()); |  | ||||||
|                 feature->SetGeometry(ogr_linestring.get()); |  | ||||||
|                 feature->SetField("id", static_cast<double>(way.id())); |  | ||||||
|                 feature->SetField("type", highway); |  | ||||||
| 
 |  | ||||||
|                 if (m_layer_linestring->CreateFeature(feature) != OGRERR_NONE) { |  | ||||||
|                     std::cerr << "Failed to create feature.\n"; |  | ||||||
|                     exit(1); |  | ||||||
|                 } |  | ||||||
| 
 |  | ||||||
|                 OGRFeature::DestroyFeature(feature); |  | ||||||
|             } catch (osmium::geometry_error&) { |  | ||||||
|                 std::cerr << "Ignoring illegal geometry for way " << way.id() << ".\n"; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     void area(const osmium::Area& area) { |  | ||||||
|         const char* building = area.tags()["building"]; |  | ||||||
|         if (building) { |  | ||||||
|             try { |  | ||||||
|                 std::unique_ptr<OGRMultiPolygon> ogr_polygon = m_factory.create_multipolygon(area); |  | ||||||
|                 OGRFeature* feature = OGRFeature::CreateFeature(m_layer_polygon->GetLayerDefn()); |  | ||||||
|                 feature->SetGeometry(ogr_polygon.get()); |  | ||||||
|                 feature->SetField("id", static_cast<int>(area.id())); |  | ||||||
|                 feature->SetField("type", building); |  | ||||||
| 
 |  | ||||||
|                 std::string type = ""; |  | ||||||
|                 if (area.from_way()) { |  | ||||||
|                     type += "w"; |  | ||||||
|                 } else { |  | ||||||
|                     type += "r"; |  | ||||||
|                 } |  | ||||||
|                 feature->SetField("type", type.c_str()); |  | ||||||
| 
 |  | ||||||
|                 if (m_layer_polygon->CreateFeature(feature) != OGRERR_NONE) { |  | ||||||
|                     std::cerr << "Failed to create feature.\n"; |  | ||||||
|                     exit(1); |  | ||||||
|                 } |  | ||||||
| 
 |  | ||||||
|                 OGRFeature::DestroyFeature(feature); |  | ||||||
|             } catch (osmium::geometry_error&) { |  | ||||||
|                 std::cerr << "Ignoring illegal geometry for area " << area.id() << " created from " << (area.from_way() ? "way" : "relation") << " with id=" << area.orig_id() << ".\n"; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| /* ================================================== */ |  | ||||||
| 
 |  | ||||||
| void print_help() { |  | ||||||
|     std::cout << "osmium_toogr [OPTIONS] [INFILE [OUTFILE]]\n\n" \ |  | ||||||
|               << "If INFILE is not given stdin is assumed.\n" \ |  | ||||||
|               << "If OUTFILE is not given 'ogr_out' is used.\n" \ |  | ||||||
|               << "\nOptions:\n" \ |  | ||||||
|               << "  -h, --help           This help message\n" \ |  | ||||||
|               << "  -d, --debug          Enable debug output\n" \ |  | ||||||
|               << "  -f, --format=FORMAT  Output OGR format (Default: 'SQLite')\n"; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| int main(int argc, char* argv[]) { |  | ||||||
|     static struct option long_options[] = { |  | ||||||
|         {"help",   no_argument, 0, 'h'}, |  | ||||||
|         {"debug",  no_argument, 0, 'd'}, |  | ||||||
|         {"format", required_argument, 0, 'f'}, |  | ||||||
|         {0, 0, 0, 0} |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     std::string output_format("SQLite"); |  | ||||||
|     bool debug = false; |  | ||||||
| 
 |  | ||||||
|     while (true) { |  | ||||||
|         int c = getopt_long(argc, argv, "hdf:", long_options, 0); |  | ||||||
|         if (c == -1) { |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         switch (c) { |  | ||||||
|             case 'h': |  | ||||||
|                 print_help(); |  | ||||||
|                 exit(0); |  | ||||||
|             case 'd': |  | ||||||
|                 debug = true; |  | ||||||
|                 break; |  | ||||||
|             case 'f': |  | ||||||
|                 output_format = optarg; |  | ||||||
|                 break; |  | ||||||
|             default: |  | ||||||
|                 exit(1); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     std::string input_filename; |  | ||||||
|     std::string output_filename("ogr_out"); |  | ||||||
|     int remaining_args = argc - optind; |  | ||||||
|     if (remaining_args > 2) { |  | ||||||
|         std::cerr << "Usage: " << argv[0] << " [OPTIONS] [INFILE [OUTFILE]]" << std::endl; |  | ||||||
|         exit(1); |  | ||||||
|     } else if (remaining_args == 2) { |  | ||||||
|         input_filename =  argv[optind]; |  | ||||||
|         output_filename = argv[optind+1]; |  | ||||||
|     } else if (remaining_args == 1) { |  | ||||||
|         input_filename =  argv[optind]; |  | ||||||
|     } else { |  | ||||||
|         input_filename = "-"; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     osmium::area::Assembler::config_type assembler_config; |  | ||||||
|     assembler_config.enable_debug_output(debug); |  | ||||||
|     osmium::area::MultipolygonCollector<osmium::area::Assembler> collector(assembler_config); |  | ||||||
| 
 |  | ||||||
|     std::cerr << "Pass 1...\n"; |  | ||||||
|     osmium::io::Reader reader1(input_filename); |  | ||||||
|     collector.read_relations(reader1); |  | ||||||
|     reader1.close(); |  | ||||||
|     std::cerr << "Pass 1 done\n"; |  | ||||||
| 
 |  | ||||||
|     index_pos_type index_pos; |  | ||||||
|     index_neg_type index_neg; |  | ||||||
|     location_handler_type location_handler(index_pos, index_neg); |  | ||||||
|     location_handler.ignore_errors(); |  | ||||||
| 
 |  | ||||||
|     MyOGRHandler ogr_handler(output_format, output_filename); |  | ||||||
| 
 |  | ||||||
|     std::cerr << "Pass 2...\n"; |  | ||||||
|     osmium::io::Reader reader2(input_filename); |  | ||||||
| 
 |  | ||||||
|     osmium::apply(reader2, location_handler, ogr_handler, collector.handler([&ogr_handler](const osmium::memory::Buffer& area_buffer) { |  | ||||||
|         osmium::apply(area_buffer, ogr_handler); |  | ||||||
|     })); |  | ||||||
| 
 |  | ||||||
|     reader2.close(); |  | ||||||
|     std::cerr << "Pass 2 done\n"; |  | ||||||
| 
 |  | ||||||
|     std::vector<const osmium::Relation*> incomplete_relations = collector.get_incomplete_relations(); |  | ||||||
|     if (!incomplete_relations.empty()) { |  | ||||||
|         std::cerr << "Warning! Some member ways missing for these multipolygon relations:"; |  | ||||||
|         for (const auto* relation : incomplete_relations) { |  | ||||||
|             std::cerr << " " << relation->id(); |  | ||||||
|         } |  | ||||||
|         std::cerr << "\n"; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
							
								
								
									
										305
									
								
								third_party/libosmium/examples/osmium_toogr2_exp.cpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										305
									
								
								third_party/libosmium/examples/osmium_toogr2_exp.cpp
									
									
									
									
										vendored
									
									
								
							| @ -1,305 +0,0 @@ | |||||||
| /*
 |  | ||||||
| 
 |  | ||||||
|   This is an example tool that converts OSM data to some output format |  | ||||||
|   like Spatialite or Shapefiles using the OGR library. |  | ||||||
| 
 |  | ||||||
|   This version does multipolygon handling (in contrast to the osmium_toogr |  | ||||||
|   example which doesn't). |  | ||||||
| 
 |  | ||||||
|   This version (..._exp) uses a new experimental unsupported interface. |  | ||||||
| 
 |  | ||||||
|   The code in this example file is released into the Public Domain. |  | ||||||
| 
 |  | ||||||
| */ |  | ||||||
| 
 |  | ||||||
| #include <iostream> |  | ||||||
| #include <getopt.h> |  | ||||||
| 
 |  | ||||||
| #include <osmium/index/map/sparse_mem_array.hpp> |  | ||||||
| 
 |  | ||||||
| #include <osmium/visitor.hpp> |  | ||||||
| 
 |  | ||||||
| #include <osmium/geom/mercator_projection.hpp> |  | ||||||
| //#include <osmium/geom/projection.hpp>
 |  | ||||||
| #include <osmium/geom/ogr.hpp> |  | ||||||
| #include <osmium/io/any_input.hpp> |  | ||||||
| #include <osmium/handler.hpp> |  | ||||||
| #include <osmium/experimental/flex_reader.hpp> |  | ||||||
| 
 |  | ||||||
| typedef osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, osmium::Location> index_type; |  | ||||||
| typedef osmium::handler::NodeLocationsForWays<index_type> location_handler_type; |  | ||||||
| 
 |  | ||||||
| class MyOGRHandler : public osmium::handler::Handler { |  | ||||||
| 
 |  | ||||||
|     OGRDataSource* m_data_source; |  | ||||||
|     OGRLayer* m_layer_point; |  | ||||||
|     OGRLayer* m_layer_linestring; |  | ||||||
|     OGRLayer* m_layer_polygon; |  | ||||||
| 
 |  | ||||||
|     // Choose one of the following:
 |  | ||||||
| 
 |  | ||||||
|     // 1. Use WGS84, do not project coordinates.
 |  | ||||||
|     //osmium::geom::OGRFactory<> m_factory {};
 |  | ||||||
| 
 |  | ||||||
|     // 2. Project coordinates into "Web Mercator".
 |  | ||||||
|     osmium::geom::OGRFactory<osmium::geom::MercatorProjection> m_factory; |  | ||||||
| 
 |  | ||||||
|     // 3. Use any projection that the proj library can handle.
 |  | ||||||
|     //    (Initialize projection with EPSG code or proj string).
 |  | ||||||
|     //    In addition you need to link with "-lproj" and add
 |  | ||||||
|     //    #include <osmium/geom/projection.hpp>.
 |  | ||||||
|     //osmium::geom::OGRFactory<osmium::geom::Projection> m_factory {osmium::geom::Projection(3857)};
 |  | ||||||
| 
 |  | ||||||
| public: |  | ||||||
| 
 |  | ||||||
|     MyOGRHandler(const std::string& driver_name, const std::string& filename) { |  | ||||||
| 
 |  | ||||||
|         OGRRegisterAll(); |  | ||||||
| 
 |  | ||||||
|         OGRSFDriver* driver = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName(driver_name.c_str()); |  | ||||||
|         if (!driver) { |  | ||||||
|             std::cerr << driver_name << " driver not available.\n"; |  | ||||||
|             exit(1); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         CPLSetConfigOption("OGR_SQLITE_SYNCHRONOUS", "FALSE"); |  | ||||||
|         const char* options[] = { "SPATIALITE=TRUE", nullptr }; |  | ||||||
|         m_data_source = driver->CreateDataSource(filename.c_str(), const_cast<char**>(options)); |  | ||||||
|         if (!m_data_source) { |  | ||||||
|             std::cerr << "Creation of output file failed.\n"; |  | ||||||
|             exit(1); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         OGRSpatialReference sparef; |  | ||||||
|         sparef.importFromProj4(m_factory.proj_string().c_str()); |  | ||||||
| 
 |  | ||||||
|         m_layer_point = m_data_source->CreateLayer("postboxes", &sparef, wkbPoint, nullptr); |  | ||||||
|         if (!m_layer_point) { |  | ||||||
|             std::cerr << "Layer creation failed.\n"; |  | ||||||
|             exit(1); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         OGRFieldDefn layer_point_field_id("id", OFTReal); |  | ||||||
|         layer_point_field_id.SetWidth(10); |  | ||||||
| 
 |  | ||||||
|         if (m_layer_point->CreateField(&layer_point_field_id) != OGRERR_NONE) { |  | ||||||
|             std::cerr << "Creating id field failed.\n"; |  | ||||||
|             exit(1); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         OGRFieldDefn layer_point_field_operator("operator", OFTString); |  | ||||||
|         layer_point_field_operator.SetWidth(30); |  | ||||||
| 
 |  | ||||||
|         if (m_layer_point->CreateField(&layer_point_field_operator) != OGRERR_NONE) { |  | ||||||
|             std::cerr << "Creating operator field failed.\n"; |  | ||||||
|             exit(1); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         /* Transactions might make things faster, then again they might not.
 |  | ||||||
|            Feel free to experiment and benchmark and report back. */ |  | ||||||
|         m_layer_point->StartTransaction(); |  | ||||||
| 
 |  | ||||||
|         m_layer_linestring = m_data_source->CreateLayer("roads", &sparef, wkbLineString, nullptr); |  | ||||||
|         if (!m_layer_linestring) { |  | ||||||
|             std::cerr << "Layer creation failed.\n"; |  | ||||||
|             exit(1); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         OGRFieldDefn layer_linestring_field_id("id", OFTReal); |  | ||||||
|         layer_linestring_field_id.SetWidth(10); |  | ||||||
| 
 |  | ||||||
|         if (m_layer_linestring->CreateField(&layer_linestring_field_id) != OGRERR_NONE) { |  | ||||||
|             std::cerr << "Creating id field failed.\n"; |  | ||||||
|             exit(1); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         OGRFieldDefn layer_linestring_field_type("type", OFTString); |  | ||||||
|         layer_linestring_field_type.SetWidth(30); |  | ||||||
| 
 |  | ||||||
|         if (m_layer_linestring->CreateField(&layer_linestring_field_type) != OGRERR_NONE) { |  | ||||||
|             std::cerr << "Creating type field failed.\n"; |  | ||||||
|             exit(1); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         m_layer_linestring->StartTransaction(); |  | ||||||
| 
 |  | ||||||
|         m_layer_polygon = m_data_source->CreateLayer("buildings", &sparef, wkbMultiPolygon, nullptr); |  | ||||||
|         if (!m_layer_polygon) { |  | ||||||
|             std::cerr << "Layer creation failed.\n"; |  | ||||||
|             exit(1); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         OGRFieldDefn layer_polygon_field_id("id", OFTInteger); |  | ||||||
|         layer_polygon_field_id.SetWidth(10); |  | ||||||
| 
 |  | ||||||
|         if (m_layer_polygon->CreateField(&layer_polygon_field_id) != OGRERR_NONE) { |  | ||||||
|             std::cerr << "Creating id field failed.\n"; |  | ||||||
|             exit(1); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         OGRFieldDefn layer_polygon_field_type("type", OFTString); |  | ||||||
|         layer_polygon_field_type.SetWidth(30); |  | ||||||
| 
 |  | ||||||
|         if (m_layer_polygon->CreateField(&layer_polygon_field_type) != OGRERR_NONE) { |  | ||||||
|             std::cerr << "Creating type field failed.\n"; |  | ||||||
|             exit(1); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         m_layer_polygon->StartTransaction(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     ~MyOGRHandler() { |  | ||||||
|         m_layer_polygon->CommitTransaction(); |  | ||||||
|         m_layer_linestring->CommitTransaction(); |  | ||||||
|         m_layer_point->CommitTransaction(); |  | ||||||
|         OGRDataSource::DestroyDataSource(m_data_source); |  | ||||||
|         OGRCleanupAll(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     void node(const osmium::Node& node) { |  | ||||||
|         const char* amenity = node.tags()["amenity"]; |  | ||||||
|         if (amenity && !strcmp(amenity, "post_box")) { |  | ||||||
|             OGRFeature* feature = OGRFeature::CreateFeature(m_layer_point->GetLayerDefn()); |  | ||||||
|             std::unique_ptr<OGRPoint> ogr_point = m_factory.create_point(node); |  | ||||||
|             feature->SetGeometry(ogr_point.get()); |  | ||||||
|             feature->SetField("id", static_cast<double>(node.id())); |  | ||||||
|             feature->SetField("operator", node.tags()["operator"]); |  | ||||||
| 
 |  | ||||||
|             if (m_layer_point->CreateFeature(feature) != OGRERR_NONE) { |  | ||||||
|                 std::cerr << "Failed to create feature.\n"; |  | ||||||
|                 exit(1); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             OGRFeature::DestroyFeature(feature); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     void way(const osmium::Way& way) { |  | ||||||
|         const char* highway = way.tags()["highway"]; |  | ||||||
|         if (highway) { |  | ||||||
|             try { |  | ||||||
|                 std::unique_ptr<OGRLineString> ogr_linestring = m_factory.create_linestring(way); |  | ||||||
|                 OGRFeature* feature = OGRFeature::CreateFeature(m_layer_linestring->GetLayerDefn()); |  | ||||||
|                 feature->SetGeometry(ogr_linestring.get()); |  | ||||||
|                 feature->SetField("id", static_cast<double>(way.id())); |  | ||||||
|                 feature->SetField("type", highway); |  | ||||||
| 
 |  | ||||||
|                 if (m_layer_linestring->CreateFeature(feature) != OGRERR_NONE) { |  | ||||||
|                     std::cerr << "Failed to create feature.\n"; |  | ||||||
|                     exit(1); |  | ||||||
|                 } |  | ||||||
| 
 |  | ||||||
|                 OGRFeature::DestroyFeature(feature); |  | ||||||
|             } catch (osmium::geometry_error&) { |  | ||||||
|                 std::cerr << "Ignoring illegal geometry for way " << way.id() << ".\n"; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     void area(const osmium::Area& area) { |  | ||||||
|         const char* building = area.tags()["building"]; |  | ||||||
|         if (building) { |  | ||||||
|             try { |  | ||||||
|                 std::unique_ptr<OGRMultiPolygon> ogr_polygon = m_factory.create_multipolygon(area); |  | ||||||
|                 OGRFeature* feature = OGRFeature::CreateFeature(m_layer_polygon->GetLayerDefn()); |  | ||||||
|                 feature->SetGeometry(ogr_polygon.get()); |  | ||||||
|                 feature->SetField("id", static_cast<int>(area.id())); |  | ||||||
|                 feature->SetField("type", building); |  | ||||||
| 
 |  | ||||||
|                 std::string type = ""; |  | ||||||
|                 if (area.from_way()) { |  | ||||||
|                     type += "w"; |  | ||||||
|                 } else { |  | ||||||
|                     type += "r"; |  | ||||||
|                 } |  | ||||||
|                 feature->SetField("type", type.c_str()); |  | ||||||
| 
 |  | ||||||
|                 if (m_layer_polygon->CreateFeature(feature) != OGRERR_NONE) { |  | ||||||
|                     std::cerr << "Failed to create feature.\n"; |  | ||||||
|                     exit(1); |  | ||||||
|                 } |  | ||||||
| 
 |  | ||||||
|                 OGRFeature::DestroyFeature(feature); |  | ||||||
|             } catch (osmium::geometry_error&) { |  | ||||||
|                 std::cerr << "Ignoring illegal geometry for area " << area.id() << " created from " << (area.from_way() ? "way" : "relation") << " with id=" << area.orig_id() << ".\n"; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| /* ================================================== */ |  | ||||||
| 
 |  | ||||||
| void print_help() { |  | ||||||
|     std::cout << "osmium_toogr [OPTIONS] [INFILE [OUTFILE]]\n\n" \ |  | ||||||
|               << "If INFILE is not given stdin is assumed.\n" \ |  | ||||||
|               << "If OUTFILE is not given 'ogr_out' is used.\n" \ |  | ||||||
|               << "\nOptions:\n" \ |  | ||||||
|               << "  -h, --help           This help message\n" \ |  | ||||||
|               << "  -f, --format=FORMAT  Output OGR format (Default: 'SQLite')\n"; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| int main(int argc, char* argv[]) { |  | ||||||
|     static struct option long_options[] = { |  | ||||||
|         {"help",   no_argument, 0, 'h'}, |  | ||||||
|         {"format", required_argument, 0, 'f'}, |  | ||||||
|         {0, 0, 0, 0} |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     std::string output_format("SQLite"); |  | ||||||
| 
 |  | ||||||
|     while (true) { |  | ||||||
|         int c = getopt_long(argc, argv, "hf:", long_options, 0); |  | ||||||
|         if (c == -1) { |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         switch (c) { |  | ||||||
|             case 'h': |  | ||||||
|                 print_help(); |  | ||||||
|                 exit(0); |  | ||||||
|             case 'f': |  | ||||||
|                 output_format = optarg; |  | ||||||
|                 break; |  | ||||||
|             default: |  | ||||||
|                 exit(1); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     std::string input_filename; |  | ||||||
|     std::string output_filename("ogr_out"); |  | ||||||
|     int remaining_args = argc - optind; |  | ||||||
|     if (remaining_args > 2) { |  | ||||||
|         std::cerr << "Usage: " << argv[0] << " [OPTIONS] [INFILE [OUTFILE]]" << std::endl; |  | ||||||
|         exit(1); |  | ||||||
|     } else if (remaining_args == 2) { |  | ||||||
|         input_filename =  argv[optind]; |  | ||||||
|         output_filename = argv[optind+1]; |  | ||||||
|     } else if (remaining_args == 1) { |  | ||||||
|         input_filename =  argv[optind]; |  | ||||||
|     } else { |  | ||||||
|         input_filename = "-"; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     index_type index_pos; |  | ||||||
|     location_handler_type location_handler(index_pos); |  | ||||||
|     osmium::experimental::FlexReader<location_handler_type> exr(input_filename, location_handler, osmium::osm_entity_bits::object); |  | ||||||
| 
 |  | ||||||
|     MyOGRHandler ogr_handler(output_format, output_filename); |  | ||||||
| 
 |  | ||||||
|     while (auto buffer = exr.read()) { |  | ||||||
|         osmium::apply(buffer, ogr_handler); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     exr.close(); |  | ||||||
| 
 |  | ||||||
|     std::vector<const osmium::Relation*> incomplete_relations = exr.collector().get_incomplete_relations(); |  | ||||||
|     if (!incomplete_relations.empty()) { |  | ||||||
|         std::cerr << "Warning! Some member ways missing for these multipolygon relations:"; |  | ||||||
|         for (const auto* relation : incomplete_relations) { |  | ||||||
|             std::cerr << " " << relation->id(); |  | ||||||
|         } |  | ||||||
|         std::cerr << "\n"; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
							
								
								
									
										406
									
								
								third_party/libosmium/include/gdalcpp.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										406
									
								
								third_party/libosmium/include/gdalcpp.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,406 @@ | |||||||
|  | #ifndef GDALCPP_HPP | ||||||
|  | #define GDALCPP_HPP | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  | 
 | ||||||
|  | C++11 wrapper classes for GDAL/OGR. | ||||||
|  | 
 | ||||||
|  | Version 1.1.1 | ||||||
|  | 
 | ||||||
|  | https://github.com/joto/gdalcpp
 | ||||||
|  | 
 | ||||||
|  | Copyright 2015 Jochen Topf <jochen@topf.org> | ||||||
|  | 
 | ||||||
|  | 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> | ||||||
|  | #include <stdexcept> | ||||||
|  | #include <string> | ||||||
|  | #include <vector> | ||||||
|  | 
 | ||||||
|  | #include <gdal_priv.h> | ||||||
|  | #include <gdal_version.h> | ||||||
|  | #include <ogr_api.h> | ||||||
|  | #include <ogrsf_frmts.h> | ||||||
|  | 
 | ||||||
|  | namespace gdalcpp { | ||||||
|  | 
 | ||||||
|  | #if GDAL_VERSION_MAJOR >= 2 | ||||||
|  |     using gdal_driver_type = GDALDriver; | ||||||
|  |     using gdal_dataset_type = GDALDataset; | ||||||
|  | #else | ||||||
|  |     using gdal_driver_type = OGRSFDriver; | ||||||
|  |     using gdal_dataset_type = OGRDataSource; | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Exception thrown for all errors in this class. | ||||||
|  |      */ | ||||||
|  |     class gdal_error : public std::runtime_error { | ||||||
|  | 
 | ||||||
|  |         std::string m_driver; | ||||||
|  |         std::string m_dataset; | ||||||
|  |         std::string m_layer; | ||||||
|  |         std::string m_field; | ||||||
|  |         OGRErr m_error; | ||||||
|  | 
 | ||||||
|  |     public: | ||||||
|  | 
 | ||||||
|  |         gdal_error(const std::string& message, | ||||||
|  |                    OGRErr error, | ||||||
|  |                    const std::string& driver = "", | ||||||
|  |                    const std::string& dataset = "", | ||||||
|  |                    const std::string& layer = "", | ||||||
|  |                    const std::string& field = "") : | ||||||
|  |             std::runtime_error(message), | ||||||
|  |             m_driver(driver), | ||||||
|  |             m_dataset(dataset), | ||||||
|  |             m_layer(layer), | ||||||
|  |             m_field(field), | ||||||
|  |             m_error(error) { | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         const std::string& driver() const { | ||||||
|  |             return m_driver; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         const std::string& dataset() const { | ||||||
|  |             return m_dataset; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         const std::string& layer() const { | ||||||
|  |             return m_layer; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         const std::string& field() const { | ||||||
|  |             return m_field; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         OGRErr error() const { | ||||||
|  |             return m_error; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     }; // class gdal_error
 | ||||||
|  | 
 | ||||||
|  |     namespace detail { | ||||||
|  | 
 | ||||||
|  |         struct init_wrapper { | ||||||
|  |             init_wrapper() { OGRRegisterAll(); } | ||||||
|  |             ~init_wrapper() { OGRCleanupAll(); } | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         struct init_library { | ||||||
|  |             init_library() { | ||||||
|  |                 static init_wrapper iw; | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         class Driver : private init_library { | ||||||
|  | 
 | ||||||
|  |             gdal_driver_type* m_driver; | ||||||
|  | 
 | ||||||
|  |         public: | ||||||
|  | 
 | ||||||
|  |             Driver(const std::string& driver_name) : | ||||||
|  |                 init_library(), | ||||||
|  | #if GDAL_VERSION_MAJOR >= 2 | ||||||
|  |                 m_driver(GetGDALDriverManager()->GetDriverByName(driver_name.c_str())) { | ||||||
|  | #else | ||||||
|  |                 m_driver(OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName(driver_name.c_str())) { | ||||||
|  | #endif | ||||||
|  |                 if (!m_driver) { | ||||||
|  |                     throw gdal_error(std::string("unknown driver: '") + driver_name + "'", OGRERR_NONE, driver_name); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             gdal_driver_type& get() const { | ||||||
|  |                 return *m_driver; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |         }; // struct Driver
 | ||||||
|  | 
 | ||||||
|  |         struct Options { | ||||||
|  | 
 | ||||||
|  |             std::vector<std::string> m_options; | ||||||
|  |             std::unique_ptr<const char*[]> m_ptrs; | ||||||
|  | 
 | ||||||
|  |             Options(const std::vector<std::string>& options) : | ||||||
|  |                 m_options(options), | ||||||
|  |                 m_ptrs(new const char*[options.size()+1]) { | ||||||
|  |                 std::transform(m_options.begin(), m_options.end(), m_ptrs.get(), [&](const std::string& s) { | ||||||
|  |                     return s.data(); | ||||||
|  |                 }); | ||||||
|  |                 m_ptrs[options.size()] = nullptr; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             char** get() const { | ||||||
|  |                 return const_cast<char**>(m_ptrs.get()); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |         }; // struct Options
 | ||||||
|  | 
 | ||||||
|  |     } // namespace detail
 | ||||||
|  | 
 | ||||||
|  |     class SRS { | ||||||
|  | 
 | ||||||
|  |         OGRSpatialReference m_spatial_reference; | ||||||
|  | 
 | ||||||
|  |     public: | ||||||
|  | 
 | ||||||
|  |         SRS() : | ||||||
|  |             m_spatial_reference() { | ||||||
|  |             auto result = m_spatial_reference.SetWellKnownGeogCS("WGS84"); | ||||||
|  |             if (result != OGRERR_NONE) { | ||||||
|  |                 throw gdal_error(std::string("can not initialize spatial reference system WGS84"), result); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         explicit SRS(int epsg) : | ||||||
|  |             m_spatial_reference() { | ||||||
|  |             auto result = m_spatial_reference.importFromEPSG(epsg); | ||||||
|  |             if (result != OGRERR_NONE) { | ||||||
|  |                 throw gdal_error(std::string("can not initialize spatial reference system for EPSG:") + std::to_string(epsg), result); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         explicit SRS(const char* name) : | ||||||
|  |             m_spatial_reference() { | ||||||
|  |             auto result = m_spatial_reference.importFromProj4(name); | ||||||
|  |             if (result != OGRERR_NONE) { | ||||||
|  |                 throw gdal_error(std::string("can not initialize spatial reference system '") + name + "'", result); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         explicit SRS(const std::string& name) : | ||||||
|  |             m_spatial_reference() { | ||||||
|  |             auto result = m_spatial_reference.importFromProj4(name.c_str()); | ||||||
|  |             if (result != OGRERR_NONE) { | ||||||
|  |                 throw gdal_error(std::string("can not initialize spatial reference system '") + name + "'", result); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         explicit SRS(const OGRSpatialReference& spatial_reference) : | ||||||
|  |             m_spatial_reference(spatial_reference) { | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         OGRSpatialReference& get() { | ||||||
|  |             return m_spatial_reference; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         const OGRSpatialReference& get() const { | ||||||
|  |             return m_spatial_reference; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     }; // class SRS
 | ||||||
|  | 
 | ||||||
|  |     class Dataset { | ||||||
|  | 
 | ||||||
|  |         struct gdal_dataset_deleter { | ||||||
|  | 
 | ||||||
|  |             void operator()(gdal_dataset_type* ds) { | ||||||
|  | #if GDAL_VERSION_MAJOR >= 2 | ||||||
|  |                 GDALClose(ds); | ||||||
|  | #else | ||||||
|  |                 OGRDataSource::DestroyDataSource(ds); | ||||||
|  | #endif | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |         }; // struct gdal_dataset_deleter
 | ||||||
|  | 
 | ||||||
|  |         std::string m_driver_name; | ||||||
|  |         std::string m_dataset_name; | ||||||
|  |         detail::Options m_options; | ||||||
|  |         SRS m_srs; | ||||||
|  |         std::unique_ptr<gdal_dataset_type, gdal_dataset_deleter> m_dataset; | ||||||
|  | 
 | ||||||
|  |     public: | ||||||
|  | 
 | ||||||
|  |         Dataset(const std::string& driver_name, const std::string& dataset_name, const SRS& srs = SRS{}, const std::vector<std::string>& options = {}) : | ||||||
|  |             m_driver_name(driver_name), | ||||||
|  |             m_dataset_name(dataset_name), | ||||||
|  |             m_options(options), | ||||||
|  |             m_srs(srs), | ||||||
|  | #if GDAL_VERSION_MAJOR >= 2 | ||||||
|  |             m_dataset(detail::Driver(driver_name).get().Create(dataset_name.c_str(), 0, 0, 0, GDT_Unknown, m_options.get())) { | ||||||
|  | #else | ||||||
|  |             m_dataset(detail::Driver(driver_name).get().CreateDataSource(dataset_name.c_str(), m_options.get())) { | ||||||
|  | #endif | ||||||
|  |             if (!m_dataset) { | ||||||
|  |                 throw gdal_error(std::string("failed to create dataset '") + dataset_name + "'", OGRERR_NONE, driver_name, dataset_name); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         const std::string& driver_name() const { | ||||||
|  |             return m_driver_name; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         const std::string& dataset_name() const { | ||||||
|  |             return m_dataset_name; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         gdal_dataset_type& get() const { | ||||||
|  |             return *m_dataset; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         SRS& srs() { | ||||||
|  |             return m_srs; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         void exec(const char* sql) { | ||||||
|  |             auto result = m_dataset->ExecuteSQL(sql, nullptr, nullptr); | ||||||
|  |             if (result) { | ||||||
|  |                 m_dataset->ReleaseResultSet(result); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         void exec(const std::string& sql) { | ||||||
|  |             exec(sql.c_str()); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |         Dataset& start_transaction() { | ||||||
|  | #if GDAL_VERSION_MAJOR >= 2 | ||||||
|  |             m_dataset->StartTransaction(); | ||||||
|  | #endif | ||||||
|  |             return *this; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         Dataset& commit_transaction() { | ||||||
|  | #if GDAL_VERSION_MAJOR >= 2 | ||||||
|  |             m_dataset->CommitTransaction(); | ||||||
|  | #endif | ||||||
|  |             return *this; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     }; // class Dataset
 | ||||||
|  | 
 | ||||||
|  |     class Layer { | ||||||
|  | 
 | ||||||
|  |         detail::Options m_options; | ||||||
|  |         Dataset& m_dataset; | ||||||
|  |         OGRLayer* m_layer; | ||||||
|  | 
 | ||||||
|  |     public: | ||||||
|  | 
 | ||||||
|  |         Layer(Dataset& dataset, const std::string& layer_name, OGRwkbGeometryType type, const std::vector<std::string>& options = {}) : | ||||||
|  |             m_options(options), | ||||||
|  |             m_dataset(dataset), | ||||||
|  |             m_layer(dataset.get().CreateLayer(layer_name.c_str(), &dataset.srs().get(), type, m_options.get())) { | ||||||
|  |             if (!m_layer) { | ||||||
|  |                 throw gdal_error(std::string("failed to create layer '") + layer_name + "'", OGRERR_NONE, | ||||||
|  |                     dataset.driver_name(), dataset.dataset_name(), layer_name); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         OGRLayer& get() { | ||||||
|  |             return *m_layer; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         const OGRLayer& get() const { | ||||||
|  |             return *m_layer; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         Dataset& dataset() const { | ||||||
|  |             return m_dataset; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         const char* name() const { | ||||||
|  |             return m_layer->GetName(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         Layer& add_field(const std::string& field_name, OGRFieldType type, int width, int precision=0) { | ||||||
|  |             OGRFieldDefn field(field_name.c_str(), type); | ||||||
|  |             field.SetWidth(width); | ||||||
|  |             field.SetPrecision(precision); | ||||||
|  | 
 | ||||||
|  |             if (m_layer->CreateField(&field) != OGRERR_NONE) { | ||||||
|  |                 throw gdal_error(std::string("failed to create field '") + field_name + "' in layer '" + name() + "'", OGRERR_NONE, | ||||||
|  |                     m_dataset.driver_name(), m_dataset.dataset_name(), name(), field_name); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             return *this; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         Layer& start_transaction() { | ||||||
|  |             OGRErr result = m_layer->StartTransaction(); | ||||||
|  |             if (result != OGRERR_NONE) { | ||||||
|  |                 throw gdal_error(std::string("starting transaction on layer '") + name() + "' failed", result, m_dataset.driver_name(), m_dataset.dataset_name(), name()); | ||||||
|  |             } | ||||||
|  |             return *this; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         Layer& commit_transaction() { | ||||||
|  |             OGRErr result = m_layer->CommitTransaction(); | ||||||
|  |             if (result != OGRERR_NONE) { | ||||||
|  |                 throw gdal_error(std::string("committing transaction on layer '") + name() + "' failed", result, m_dataset.driver_name(), m_dataset.dataset_name(), name()); | ||||||
|  |             } | ||||||
|  |             return *this; | ||||||
|  |          } | ||||||
|  | 
 | ||||||
|  |     }; // class Layer
 | ||||||
|  | 
 | ||||||
|  |     class Feature { | ||||||
|  | 
 | ||||||
|  |         Layer& m_layer; | ||||||
|  |         OGRFeature m_feature; | ||||||
|  | 
 | ||||||
|  |     public: | ||||||
|  | 
 | ||||||
|  |         Feature(Layer& layer, std::unique_ptr<OGRGeometry>&& geometry) : | ||||||
|  |             m_layer(layer), | ||||||
|  |             m_feature(m_layer.get().GetLayerDefn()) { | ||||||
|  |             OGRErr result = m_feature.SetGeometryDirectly(geometry.release()); | ||||||
|  |             if (result != OGRERR_NONE) { | ||||||
|  |                 throw gdal_error(std::string("setting feature geometry in layer '") + m_layer.name() + "' failed", result, m_layer.dataset().driver_name(), m_layer.dataset().dataset_name()); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         void add_to_layer() { | ||||||
|  |             OGRErr result = m_layer.get().CreateFeature(&m_feature); | ||||||
|  |             if (result != OGRERR_NONE) { | ||||||
|  |                 throw gdal_error(std::string("creating feature in layer '") + m_layer.name() + "' failed", result, m_layer.dataset().driver_name(), m_layer.dataset().dataset_name()); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         template <class T> | ||||||
|  |         Feature& set_field(int n, T&& arg) { | ||||||
|  |             m_feature.SetField(n, std::forward<T>(arg)); | ||||||
|  |             return *this; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         template <class T> | ||||||
|  |         Feature& set_field(const char* name, T&& arg) { | ||||||
|  |             m_feature.SetField(name, std::forward<T>(arg)); | ||||||
|  |             return *this; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     }; // class Feature
 | ||||||
|  | 
 | ||||||
|  | } // namespace gdalcpp
 | ||||||
|  | 
 | ||||||
|  | #endif // GDALCPP_HPP
 | ||||||
| @ -34,9 +34,13 @@ DEALINGS IN THE SOFTWARE. | |||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| #include <algorithm> | #include <algorithm> | ||||||
|  | #include <cassert> | ||||||
|  | #include <cstring> | ||||||
| #include <iostream> | #include <iostream> | ||||||
| #include <iterator> | #include <iterator> | ||||||
| #include <list> | #include <list> | ||||||
|  | #include <set> | ||||||
|  | #include <string> | ||||||
| #include <map> | #include <map> | ||||||
| #include <vector> | #include <vector> | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -113,7 +113,7 @@ namespace osmium { | |||||||
|                     return m_second; |                     return m_second; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 bool to_left_of(const osmium::Location location) const { |                 bool to_left_of(const osmium::Location& location) const { | ||||||
|     //                std::cerr << "segment " << first() << "--" << second() << " to_left_of(" << location << "\n";
 |     //                std::cerr << "segment " << first() << "--" << second() << " to_left_of(" << location << "\n";
 | ||||||
| 
 | 
 | ||||||
|                     if (first().location() == location || second().location() == location) { |                     if (first().location() == location || second().location() == location) { | ||||||
| @ -195,8 +195,8 @@ namespace osmium { | |||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             inline bool y_range_overlap(const NodeRefSegment& s1, const NodeRefSegment& s2) { |             inline bool y_range_overlap(const NodeRefSegment& s1, const NodeRefSegment& s2) { | ||||||
|                 auto m1 = std::minmax(s1.first().location().y(), s1.second().location().y()); |                 const std::pair<int32_t, int32_t> m1 = std::minmax(s1.first().location().y(), s1.second().location().y()); | ||||||
|                 auto m2 = std::minmax(s2.first().location().y(), s2.second().location().y()); |                 const std::pair<int32_t, int32_t> m2 = std::minmax(s2.first().location().y(), s2.second().location().y()); | ||||||
|                 if (m1.first > m2.second || m2.first > m1.second) { |                 if (m1.first > m2.second || m2.first > m1.second) { | ||||||
|                     return false; |                     return false; | ||||||
|                 } |                 } | ||||||
| @ -204,19 +204,25 @@ namespace osmium { | |||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             /**
 |             /**
 | ||||||
|              * Calculate the intersection between to NodeRefSegments. The result is returned |              * Calculate the intersection between two NodeRefSegments. The | ||||||
|              * as a Location. Note that because the Location uses integers with limited |              * result is returned as a Location. Note that because the Location | ||||||
|              * precision internally, the result might be slightly different than the |              * uses integers with limited precision internally, the result | ||||||
|              * numerically correct location. |              * might be slightly different than the numerically correct | ||||||
|  |              * location. | ||||||
|              * |              * | ||||||
|              * If the segments touch in one of their endpoints, it doesn't count as an |              * This function uses integer arithmentic as much as possible and | ||||||
|              * intersection. |              * will not work if the segments are longer than about half the | ||||||
|  |              * planet. This shouldn't happen with real data, so it isn't a big | ||||||
|  |              * problem. | ||||||
|              * |              * | ||||||
|              * If the segments intersect not in a single point but in multiple points, ie |              * If the segments touch in one of their endpoints, it doesn't | ||||||
|              * if they overlap, this is NOT detected. |              * count as an intersection. | ||||||
|              * |              * | ||||||
|              * @returns Undefined osmium::Location if there is no intersection or a defined |              * If the segments intersect not in a single point but in multiple | ||||||
|              *          Location if the segments intersect. |              * 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) { |             inline osmium::Location calculate_intersection(const NodeRefSegment& s1, const NodeRefSegment& s2) { | ||||||
|                 if (s1.first().location()  == s2.first().location()  || |                 if (s1.first().location()  == s2.first().location()  || | ||||||
| @ -226,26 +232,32 @@ namespace osmium { | |||||||
|                     return osmium::Location(); |                     return osmium::Location(); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 auto d = (static_cast<int64_t>(s2.second().y()) - static_cast<int64_t>(s2.first().y())) * |                 int64_t s1ax = s1.first().x(); | ||||||
|                          (static_cast<int64_t>(s1.second().x()) - static_cast<int64_t>(s1.first().x())) - |                 int64_t s1ay = s1.first().y(); | ||||||
|                          (static_cast<int64_t>(s2.second().x()) - static_cast<int64_t>(s2.first().x())) * |                 int64_t s1bx = s1.second().x(); | ||||||
|                          (static_cast<int64_t>(s1.second().y()) - static_cast<int64_t>(s1.first().y())); |                 int64_t s1by = s1.second().y(); | ||||||
|  |                 int64_t s2ax = s2.first().x(); | ||||||
|  |                 int64_t s2ay = s2.first().y(); | ||||||
|  |                 int64_t s2bx = s2.second().x(); | ||||||
|  |                 int64_t s2by = s2.second().y(); | ||||||
|  | 
 | ||||||
|  |                 int64_t d = (s2by - s2ay) * (s1bx - s1ax) - | ||||||
|  |                             (s2bx - s2ax) * (s1by - s1ay); | ||||||
| 
 | 
 | ||||||
|                 if (d != 0) { |                 if (d != 0) { | ||||||
|                     double denom  = ((s2.second().lat() - s2.first().lat())*(s1.second().lon() - s1.first().lon())) - |                     int64_t na = (s2bx - s2ax) * (s1ay - s2ay) - | ||||||
|                                     ((s2.second().lon() - s2.first().lon())*(s1.second().lat() - s1.first().lat())); |                                  (s2by - s2ay) * (s1ax - s2ax); | ||||||
| 
 | 
 | ||||||
|                     double nume_a = ((s2.second().lon() - s2.first().lon())*(s1.first().lat() - s2.first().lat())) - |                     int64_t nb = (s1bx - s1ax) * (s1ay - s2ay) - | ||||||
|                                     ((s2.second().lat() - s2.first().lat())*(s1.first().lon() - s2.first().lon())); |                                  (s1by - s1ay) * (s1ax - s2ax); | ||||||
| 
 | 
 | ||||||
|                     double nume_b = ((s1.second().lon() - s1.first().lon())*(s1.first().lat() - s2.first().lat())) - |                     if ((d > 0 && na >= 0 && na <= d && nb >= 0 && nb <= d) || | ||||||
|                                     ((s1.second().lat() - s1.first().lat())*(s1.first().lon() - s2.first().lon())); |                         (d < 0 && na <= 0 && na >= d && nb <= 0 && nb >= d)) { | ||||||
|  | 
 | ||||||
|  |                         double ua = double(na) / d; | ||||||
|  |                         int32_t ix = int32_t(s1ax + ua*(s1bx - s1ax)); | ||||||
|  |                         int32_t iy = int32_t(s1ay + ua*(s1by - s1ay)); | ||||||
| 
 | 
 | ||||||
|                     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(ix, iy); | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|  | |||||||
| @ -34,12 +34,14 @@ DEALINGS IN THE SOFTWARE. | |||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| #include <algorithm> | #include <algorithm> | ||||||
| #include <cassert> | #include <cstdint> | ||||||
|  | #include <cstdlib> | ||||||
| #include <iostream> | #include <iostream> | ||||||
| #include <list> | #include <iterator> | ||||||
| #include <set> | #include <set> | ||||||
| #include <vector> | #include <vector> | ||||||
| 
 | 
 | ||||||
|  | #include <osmium/osm/location.hpp> | ||||||
| #include <osmium/osm/node_ref.hpp> | #include <osmium/osm/node_ref.hpp> | ||||||
| #include <osmium/area/detail/node_ref_segment.hpp> | #include <osmium/area/detail/node_ref_segment.hpp> | ||||||
| 
 | 
 | ||||||
| @ -148,7 +150,8 @@ namespace osmium { | |||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void swap_segments(ProtoRing& other) { |                 void swap_segments(ProtoRing& other) { | ||||||
|                     std::swap(m_segments, other.m_segments); |                     using std::swap; | ||||||
|  |                     swap(m_segments, other.m_segments); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void add_inner_ring(ProtoRing* ring) { |                 void add_inner_ring(ProtoRing* ring) { | ||||||
|  | |||||||
| @ -41,6 +41,8 @@ DEALINGS IN THE SOFTWARE. | |||||||
| #include <osmium/area/problem_reporter.hpp> | #include <osmium/area/problem_reporter.hpp> | ||||||
| #include <osmium/area/detail/node_ref_segment.hpp> | #include <osmium/area/detail/node_ref_segment.hpp> | ||||||
| #include <osmium/memory/buffer.hpp> | #include <osmium/memory/buffer.hpp> | ||||||
|  | #include <osmium/osm/location.hpp> | ||||||
|  | #include <osmium/osm/node_ref.hpp> | ||||||
| #include <osmium/osm/relation.hpp> | #include <osmium/osm/relation.hpp> | ||||||
| #include <osmium/osm/way.hpp> | #include <osmium/osm/way.hpp> | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -53,7 +53,7 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|     namespace relations { |     namespace relations { | ||||||
|         class RelationMeta; |         class RelationMeta; | ||||||
|     } |     } // namespace relations
 | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|      * @brief Code related to the building of areas (multipolygons) from relations. |      * @brief Code related to the building of areas (multipolygons) from relations. | ||||||
| @ -71,7 +71,7 @@ namespace osmium { | |||||||
|          * |          * | ||||||
|          * @tparam TAssembler Multipolygon Assembler class. |          * @tparam TAssembler Multipolygon Assembler class. | ||||||
|          */ |          */ | ||||||
|         template <class TAssembler> |         template <typename TAssembler> | ||||||
|         class MultipolygonCollector : public osmium::relations::Collector<MultipolygonCollector<TAssembler>, false, true, false> { |         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 osmium::relations::Collector<MultipolygonCollector<TAssembler>, false, true, false> collector_type; | ||||||
| @ -87,7 +87,8 @@ namespace osmium { | |||||||
|             void flush_output_buffer() { |             void flush_output_buffer() { | ||||||
|                 if (this->callback()) { |                 if (this->callback()) { | ||||||
|                     osmium::memory::Buffer buffer(initial_output_buffer_size); |                     osmium::memory::Buffer buffer(initial_output_buffer_size); | ||||||
|                     std::swap(buffer, m_output_buffer); |                     using std::swap; | ||||||
|  |                     swap(buffer, m_output_buffer); | ||||||
|                     this->callback()(std::move(buffer)); |                     this->callback()(std::move(buffer)); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| @ -176,28 +177,6 @@ namespace osmium { | |||||||
|                 } catch (osmium::invalid_location&) { |                 } catch (osmium::invalid_location&) { | ||||||
|                     // XXX ignore
 |                     // 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() { |             void flush() { | ||||||
| @ -206,7 +185,10 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|             osmium::memory::Buffer read() { |             osmium::memory::Buffer read() { | ||||||
|                 osmium::memory::Buffer buffer(initial_output_buffer_size, osmium::memory::Buffer::auto_grow::yes); |                 osmium::memory::Buffer buffer(initial_output_buffer_size, osmium::memory::Buffer::auto_grow::yes); | ||||||
|                 std::swap(buffer, m_output_buffer); | 
 | ||||||
|  |                 using std::swap; | ||||||
|  |                 swap(buffer, m_output_buffer); | ||||||
|  | 
 | ||||||
|                 return buffer; |                 return buffer; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -54,7 +54,7 @@ namespace osmium { | |||||||
|                 ProblemReporterStream(m_sstream) { |                 ProblemReporterStream(m_sstream) { | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             virtual ~ProblemReporterException() = default; |             ~ProblemReporterException() override = default; | ||||||
| 
 | 
 | ||||||
|             void report_duplicate_node(osmium::object_id_type node_id1, osmium::object_id_type node_id2, osmium::Location location) override { |             void report_duplicate_node(osmium::object_id_type node_id1, osmium::object_id_type node_id2, osmium::Location location) override { | ||||||
|                 m_sstream.str(); |                 m_sstream.str(); | ||||||
|  | |||||||
| @ -42,34 +42,12 @@ DEALINGS IN THE SOFTWARE. | |||||||
|  * @attention If you include this file, you'll need to link with `libgdal`. |  * @attention If you include this file, you'll need to link with `libgdal`. | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| #ifdef _MSC_VER |  | ||||||
| # pragma warning(push) |  | ||||||
| # pragma warning(disable : 4458) |  | ||||||
| #else |  | ||||||
| # pragma GCC diagnostic push |  | ||||||
| # ifdef __clang__ |  | ||||||
| #  pragma GCC diagnostic ignored "-Wdocumentation-unknown-command" |  | ||||||
| # endif |  | ||||||
| # pragma GCC diagnostic ignored "-Wfloat-equal" |  | ||||||
| # pragma GCC diagnostic ignored "-Wold-style-cast" |  | ||||||
| # pragma GCC diagnostic ignored "-Wpadded" |  | ||||||
| # pragma GCC diagnostic ignored "-Wredundant-decls" |  | ||||||
| # pragma GCC diagnostic ignored "-Wshadow" |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #include <ogr_api.h> |  | ||||||
| #include <ogrsf_frmts.h> |  | ||||||
| 
 |  | ||||||
| #ifdef _MSC_VER |  | ||||||
| # pragma warning(pop) |  | ||||||
| #else |  | ||||||
| # pragma GCC diagnostic pop |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #include <memory> | #include <memory> | ||||||
| #include <stdexcept> | 
 | ||||||
|  | #include <gdalcpp.hpp> | ||||||
| 
 | 
 | ||||||
| #include <osmium/area/problem_reporter.hpp> | #include <osmium/area/problem_reporter.hpp> | ||||||
|  | #include <osmium/geom/factory.hpp> | ||||||
| #include <osmium/geom/ogr.hpp> | #include <osmium/geom/ogr.hpp> | ||||||
| #include <osmium/osm/location.hpp> | #include <osmium/osm/location.hpp> | ||||||
| #include <osmium/osm/types.hpp> | #include <osmium/osm/types.hpp> | ||||||
| @ -86,24 +64,15 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|             osmium::geom::OGRFactory<> m_ogr_factory; |             osmium::geom::OGRFactory<> m_ogr_factory; | ||||||
| 
 | 
 | ||||||
|             OGRDataSource* m_data_source; |             gdalcpp::Layer m_layer_perror; | ||||||
| 
 |             gdalcpp::Layer m_layer_lerror; | ||||||
|             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) { |             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()); |                 gdalcpp::Feature feature(m_layer_perror, m_ogr_factory.create_point(location)); | ||||||
|                 std::unique_ptr<OGRPoint> ogr_point = m_ogr_factory.create_point(location); |                 feature.set_field("id1", static_cast<double>(id1)); | ||||||
|                 feature->SetGeometry(ogr_point.get()); |                 feature.set_field("id2", static_cast<double>(id2)); | ||||||
|                 feature->SetField("id1", static_cast<double>(id1)); |                 feature.set_field("problem_type", problem_type); | ||||||
|                 feature->SetField("id2", static_cast<double>(id2)); |                 feature.add_to_layer(); | ||||||
|                 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) { |             void write_line(const char* problem_type, osmium::object_id_type id1, osmium::object_id_type id2, osmium::Location loc1, osmium::Location loc2) { | ||||||
| @ -112,83 +81,30 @@ namespace osmium { | |||||||
|                 std::unique_ptr<OGRLineString> ogr_linestring = std::unique_ptr<OGRLineString>(new OGRLineString()); |                 std::unique_ptr<OGRLineString> ogr_linestring = std::unique_ptr<OGRLineString>(new OGRLineString()); | ||||||
|                 ogr_linestring->addPoint(ogr_point1.get()); |                 ogr_linestring->addPoint(ogr_point1.get()); | ||||||
|                 ogr_linestring->addPoint(ogr_point2.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) { |                 gdalcpp::Feature feature(m_layer_lerror, std::move(ogr_linestring)); | ||||||
|                     std::runtime_error("Failed to create feature on layer 'lerrors'"); |                 feature.set_field("id1", static_cast<double>(id1)); | ||||||
|                 } |                 feature.set_field("id2", static_cast<double>(id2)); | ||||||
| 
 |                 feature.set_field("problem_type", problem_type); | ||||||
|                 OGRFeature::DestroyFeature(feature); |                 feature.add_to_layer(); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|         public: |         public: | ||||||
| 
 | 
 | ||||||
|             explicit ProblemReporterOGR(OGRDataSource* data_source) : |             explicit ProblemReporterOGR(gdalcpp::Dataset& dataset) : | ||||||
|                 m_data_source(data_source) { |                 m_layer_perror(dataset, "perrors", wkbPoint), | ||||||
|  |                 m_layer_lerror(dataset, "lerrors", wkbLineString) { | ||||||
| 
 | 
 | ||||||
|                 OGRSpatialReference sparef; |                 m_layer_perror.add_field("id1", OFTReal, 10); | ||||||
|                 sparef.SetWellKnownGeogCS("WGS84"); |                 m_layer_perror.add_field("id2", OFTReal, 10); | ||||||
|  |                 m_layer_perror.add_field("problem_type", OFTString, 30); | ||||||
| 
 | 
 | ||||||
|                 m_layer_perror = m_data_source->CreateLayer("perrors", &sparef, wkbPoint, nullptr); |                 m_layer_lerror.add_field("id1", OFTReal, 10); | ||||||
|                 if (!m_layer_perror) { |                 m_layer_lerror.add_field("id2", OFTReal, 10); | ||||||
|                     std::runtime_error("Layer creation failed for layer 'perrors'"); |                 m_layer_lerror.add_field("problem_type", OFTString, 30); | ||||||
|                 } |  | ||||||
| 
 |  | ||||||
|                 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; |             ~ProblemReporterOGR() override = default; | ||||||
| 
 | 
 | ||||||
|             void report_duplicate_node(osmium::object_id_type node_id1, osmium::object_id_type node_id2, osmium::Location location) override { |             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); |                 write_point("duplicate_node", node_id1, node_id2, location); | ||||||
|  | |||||||
| @ -54,7 +54,7 @@ namespace osmium { | |||||||
|                 m_out(&out) { |                 m_out(&out) { | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             virtual ~ProblemReporterStream() = default; |             ~ProblemReporterStream() override = default; | ||||||
| 
 | 
 | ||||||
|             void header(const char* msg) { |             void header(const char* msg) { | ||||||
|                 *m_out << "DATA PROBLEM: " << msg << " on " << item_type_to_char(m_object_type) << m_object_id << ": "; |                 *m_out << "DATA PROBLEM: " << msg << " on " << item_type_to_char(m_object_type) << m_object_id << ": "; | ||||||
|  | |||||||
| @ -134,7 +134,7 @@ namespace osmium { | |||||||
|              * Reserve space for an object of class T in buffer and return |              * Reserve space for an object of class T in buffer and return | ||||||
|              * pointer to it. |              * pointer to it. | ||||||
|              */ |              */ | ||||||
|             template <class T> |             template <typename T> | ||||||
|             T* reserve_space_for() { |             T* reserve_space_for() { | ||||||
|                 assert(m_buffer.is_aligned()); |                 assert(m_buffer.is_aligned()); | ||||||
|                 return reinterpret_cast<T*>(m_buffer.reserve_space(sizeof(T))); |                 return reinterpret_cast<T*>(m_buffer.reserve_space(sizeof(T))); | ||||||
| @ -182,7 +182,7 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|         }; // class Builder
 |         }; // class Builder
 | ||||||
| 
 | 
 | ||||||
|         template <class TItem> |         template <typename TItem> | ||||||
|         class ObjectBuilder : public Builder { |         class ObjectBuilder : public Builder { | ||||||
| 
 | 
 | ||||||
|             static_assert(std::is_base_of<osmium::memory::Item, TItem>::value, "ObjectBuilder can only build objects derived from osmium::memory::Item"); |             static_assert(std::is_base_of<osmium::memory::Item, TItem>::value, "ObjectBuilder can only build objects derived from osmium::memory::Item"); | ||||||
|  | |||||||
| @ -33,9 +33,11 @@ DEALINGS IN THE SOFTWARE. | |||||||
| 
 | 
 | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
|  | #include <cassert> | ||||||
| #include <cstring> | #include <cstring> | ||||||
| #include <initializer_list> | #include <initializer_list> | ||||||
| #include <new> | #include <new> | ||||||
|  | #include <stdexcept> | ||||||
| #include <string> | #include <string> | ||||||
| #include <utility> | #include <utility> | ||||||
| 
 | 
 | ||||||
| @ -53,7 +55,7 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|     namespace memory { |     namespace memory { | ||||||
|         class Buffer; |         class Buffer; | ||||||
|     } |     } // namespace memory
 | ||||||
| 
 | 
 | ||||||
|     namespace builder { |     namespace builder { | ||||||
| 
 | 
 | ||||||
| @ -76,6 +78,12 @@ namespace osmium { | |||||||
|              * @param value Tag value (0-terminated string). |              * @param value Tag value (0-terminated string). | ||||||
|              */ |              */ | ||||||
|             void add_tag(const char* key, const char* value) { |             void add_tag(const char* key, const char* value) { | ||||||
|  |                 if (std::strlen(key) > osmium::max_osm_string_length) { | ||||||
|  |                     throw std::length_error("OSM tag key is too long"); | ||||||
|  |                 } | ||||||
|  |                 if (std::strlen(value) > osmium::max_osm_string_length) { | ||||||
|  |                     throw std::length_error("OSM tag value is too long"); | ||||||
|  |                 } | ||||||
|                 add_size(append(key) + append(value)); |                 add_size(append(key) + append(value)); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
| @ -87,8 +95,15 @@ namespace osmium { | |||||||
|              * @param value Pointer to tag value. |              * @param value Pointer to tag value. | ||||||
|              * @param value_length Length of value (not including the \0 byte). |              * @param value_length Length of value (not including the \0 byte). | ||||||
|              */ |              */ | ||||||
|             void add_tag(const char* key, const string_size_type key_length, const char* value, const string_size_type value_length) { |             void add_tag(const char* key, const size_t key_length, const char* value, const size_t value_length) { | ||||||
|                 add_size(append(key, key_length) + append_zero() + append(value, value_length) + append_zero()); |                 if (key_length > osmium::max_osm_string_length) { | ||||||
|  |                     throw std::length_error("OSM tag key is too long"); | ||||||
|  |                 } | ||||||
|  |                 if (value_length > osmium::max_osm_string_length) { | ||||||
|  |                     throw std::length_error("OSM tag value is too long"); | ||||||
|  |                 } | ||||||
|  |                 add_size(append(key,   osmium::memory::item_size_type(key_length))   + append_zero() + | ||||||
|  |                          append(value, osmium::memory::item_size_type(value_length)) + append_zero()); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             /**
 |             /**
 | ||||||
| @ -98,13 +113,46 @@ namespace osmium { | |||||||
|              * @param value Tag value. |              * @param value Tag value. | ||||||
|              */ |              */ | ||||||
|             void add_tag(const std::string& key, const std::string& 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)) + |                 if (key.size() > osmium::max_osm_string_length) { | ||||||
|                          append(value.data(), static_cast_with_assert<string_size_type>(value.size() + 1))); |                     throw std::length_error("OSM tag key is too long"); | ||||||
|  |                 } | ||||||
|  |                 if (value.size() > osmium::max_osm_string_length) { | ||||||
|  |                     throw std::length_error("OSM tag value is too long"); | ||||||
|  |                 } | ||||||
|  |                 add_size(append(key.data(),   osmium::memory::item_size_type(key.size())   + 1) + | ||||||
|  |                          append(value.data(), osmium::memory::item_size_type(value.size()) + 1)); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             /**
 | ||||||
|  |              * Add tag to buffer. | ||||||
|  |              * | ||||||
|  |              * @param tag Tag. | ||||||
|  |              */ | ||||||
|  |             void add_tag(const osmium::Tag& tag) { | ||||||
|  |                 add_size(append(tag.key()) + append(tag.value())); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             /**
 | ||||||
|  |              * Add tag to buffer. | ||||||
|  |              * | ||||||
|  |              * @param tag Pair of key/value 0-terminated strings. | ||||||
|  |              */ | ||||||
|  |             void add_tag(const std::pair<const char*, const char*>& tag) { | ||||||
|  |                 add_tag(tag.first, tag.second); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             /**
 | ||||||
|  |              * Add tag to buffer. | ||||||
|  |              * | ||||||
|  |              * @param tag Pair of std::string references. | ||||||
|  |              */ | ||||||
|  |             void add_tag(const std::pair<const std::string&, const std::string&>& tag) { | ||||||
|  |                 add_tag(tag.first, tag.second); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|         }; // class TagListBuilder
 |         }; // class TagListBuilder
 | ||||||
| 
 | 
 | ||||||
|         template <class T> |         template <typename T> | ||||||
|         class NodeRefListBuilder : public ObjectBuilder<T> { |         class NodeRefListBuilder : public ObjectBuilder<T> { | ||||||
| 
 | 
 | ||||||
|         public: |         public: | ||||||
| @ -122,7 +170,7 @@ namespace osmium { | |||||||
|                 static_cast<Builder*>(this)->add_size(sizeof(osmium::NodeRef)); |                 static_cast<Builder*>(this)->add_size(sizeof(osmium::NodeRef)); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             void add_node_ref(const object_id_type ref, const osmium::Location location = Location()) { |             void add_node_ref(const object_id_type ref, const osmium::Location& location = Location{}) { | ||||||
|                 add_node_ref(NodeRef(ref, location)); |                 add_node_ref(NodeRef(ref, location)); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
| @ -141,35 +189,17 @@ namespace osmium { | |||||||
|              *               will be set. |              *               will be set. | ||||||
|              * @param role The role. |              * @param role The role. | ||||||
|              * @param length Length of role (without \0 termination). |              * @param length Length of role (without \0 termination). | ||||||
|  |              * @throws std:length_error If role is longer than osmium::max_osm_string_length | ||||||
|              */ |              */ | ||||||
|             void add_role(osmium::RelationMember& member, const char* role, const string_size_type length) { |             void add_role(osmium::RelationMember& member, const char* role, const size_t length) { | ||||||
|                 member.set_role_size(length + 1); |                 if (length > osmium::max_osm_string_length) { | ||||||
|                 add_size(append(role, length) + append_zero()); |                     throw std::length_error("OSM relation member role is too long"); | ||||||
|  |                 } | ||||||
|  |                 member.set_role_size(osmium::string_size_type(length) + 1); | ||||||
|  |                 add_size(append(role, osmium::memory::item_size_type(length)) + append_zero()); | ||||||
|                 add_padding(true); |                 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))); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             /**
 |  | ||||||
|              * 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())); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|         public: |         public: | ||||||
| 
 | 
 | ||||||
|             explicit RelationMemberListBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) : |             explicit RelationMemberListBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) : | ||||||
| @ -190,8 +220,10 @@ namespace osmium { | |||||||
|              * @param full_member Optional pointer to the member object. If it |              * @param full_member Optional pointer to the member object. If it | ||||||
|              *                    is available a copy will be added to the |              *                    is available a copy will be added to the | ||||||
|              *                    relation. |              *                    relation. | ||||||
|  |              * @throws std:length_error If role_length is greater than | ||||||
|  |              *         osmium::max_osm_string_length | ||||||
|              */ |              */ | ||||||
|             void add_member(osmium::item_type type, object_id_type ref, const char* role, const string_size_type role_length, const osmium::OSMObject* full_member = nullptr) { |             void add_member(osmium::item_type type, object_id_type ref, const char* role, const size_t role_length, const osmium::OSMObject* full_member = nullptr) { | ||||||
|                 osmium::RelationMember* member = reserve_space_for<osmium::RelationMember>(); |                 osmium::RelationMember* member = reserve_space_for<osmium::RelationMember>(); | ||||||
|                 new (member) osmium::RelationMember(ref, type, full_member != nullptr); |                 new (member) osmium::RelationMember(ref, type, full_member != nullptr); | ||||||
|                 add_size(sizeof(RelationMember)); |                 add_size(sizeof(RelationMember)); | ||||||
| @ -210,9 +242,10 @@ namespace osmium { | |||||||
|              * @param full_member Optional pointer to the member object. If it |              * @param full_member Optional pointer to the member object. If it | ||||||
|              *                    is available a copy will be added to the |              *                    is available a copy will be added to the | ||||||
|              *                    relation. |              *                    relation. | ||||||
|  |              * @throws std:length_error If role is longer than osmium::max_osm_string_length | ||||||
|              */ |              */ | ||||||
|             void add_member(osmium::item_type type, object_id_type ref, const char* role, const osmium::OSMObject* full_member = nullptr) { |             void add_member(osmium::item_type type, object_id_type ref, const char* role, const osmium::OSMObject* full_member = nullptr) { | ||||||
|                 add_member(type, ref, role, strlen(role), full_member); |                 add_member(type, ref, role, std::strlen(role), full_member); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             /**
 |             /**
 | ||||||
| @ -224,6 +257,7 @@ namespace osmium { | |||||||
|              * @param full_member Optional pointer to the member object. If it |              * @param full_member Optional pointer to the member object. If it | ||||||
|              *                    is available a copy will be added to the |              *                    is available a copy will be added to the | ||||||
|              *                    relation. |              *                    relation. | ||||||
|  |              * @throws std:length_error If role is longer than osmium::max_osm_string_length | ||||||
|              */ |              */ | ||||||
|             void add_member(osmium::item_type type, object_id_type ref, const std::string& role, const osmium::OSMObject* full_member = nullptr) { |             void add_member(osmium::item_type type, object_id_type ref, const std::string& role, const osmium::OSMObject* full_member = nullptr) { | ||||||
|                 add_member(type, ref, role.data(), role.size(), full_member); |                 add_member(type, ref, role.data(), role.size(), full_member); | ||||||
| @ -231,7 +265,65 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|         }; // class RelationMemberListBuilder
 |         }; // class RelationMemberListBuilder
 | ||||||
| 
 | 
 | ||||||
|         template <class T> |         class ChangesetDiscussionBuilder : public ObjectBuilder<ChangesetDiscussion> { | ||||||
|  | 
 | ||||||
|  |             osmium::ChangesetComment* m_comment = nullptr; | ||||||
|  | 
 | ||||||
|  |             void add_user(osmium::ChangesetComment& comment, const char* user, const size_t length) { | ||||||
|  |                 if (length > osmium::max_osm_string_length) { | ||||||
|  |                     throw std::length_error("OSM user name is too long"); | ||||||
|  |                 } | ||||||
|  |                 comment.set_user_size(osmium::string_size_type(length) + 1); | ||||||
|  |                 add_size(append(user, osmium::memory::item_size_type(length)) + append_zero()); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             void add_text(osmium::ChangesetComment& comment, const char* text, const size_t length) { | ||||||
|  |                 // XXX There is no limit on the length of a comment text. We
 | ||||||
|  |                 // limit it here to 2^16-2 characters, because that's all that
 | ||||||
|  |                 // will fit into our internal data structure. This is not ideal,
 | ||||||
|  |                 // and will have to be discussed and cleared up.
 | ||||||
|  |                 if (length > std::numeric_limits<osmium::string_size_type>::max() - 1) { | ||||||
|  |                     throw std::length_error("OSM changeset comment is too long"); | ||||||
|  |                 } | ||||||
|  |                 comment.set_text_size(osmium::string_size_type(length) + 1); | ||||||
|  |                 add_size(append(text, osmium::memory::item_size_type(length)) + append_zero()); | ||||||
|  |                 add_padding(true); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |         public: | ||||||
|  | 
 | ||||||
|  |             explicit ChangesetDiscussionBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) : | ||||||
|  |                 ObjectBuilder<ChangesetDiscussion>(buffer, parent) { | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             ~ChangesetDiscussionBuilder() { | ||||||
|  |                 assert(!m_comment && "You have to always call both add_comment() and then add_comment_text() in that order for each comment!"); | ||||||
|  |                 add_padding(); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             void add_comment(osmium::Timestamp date, osmium::user_id_type uid, const char* user) { | ||||||
|  |                 assert(!m_comment && "You have to always call both add_comment() and then add_comment_text() in that order for each comment!"); | ||||||
|  |                 m_comment = reserve_space_for<osmium::ChangesetComment>(); | ||||||
|  |                 new (m_comment) osmium::ChangesetComment(date, uid); | ||||||
|  |                 add_size(sizeof(ChangesetComment)); | ||||||
|  |                 add_user(*m_comment, user, std::strlen(user)); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             void add_comment_text(const char* text) { | ||||||
|  |                 assert(m_comment && "You have to always call both add_comment() and then add_comment_text() in that order for each comment!"); | ||||||
|  |                 add_text(*m_comment, text, std::strlen(text)); | ||||||
|  |                 m_comment = nullptr; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             void add_comment_text(const std::string& text) { | ||||||
|  |                 assert(m_comment && "You have to always call both add_comment() and then add_comment_text() in that order for each comment!"); | ||||||
|  |                 add_text(*m_comment, text.c_str(), text.size()); | ||||||
|  |                 m_comment = nullptr; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |         }; // class ChangesetDiscussionBuilder
 | ||||||
|  | 
 | ||||||
|  |         template <typename T> | ||||||
|         class OSMObjectBuilder : public ObjectBuilder<T> { |         class OSMObjectBuilder : public ObjectBuilder<T> { | ||||||
| 
 | 
 | ||||||
|         public: |         public: | ||||||
|  | |||||||
| @ -46,8 +46,7 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|         public: |         public: | ||||||
| 
 | 
 | ||||||
|             DiffHandler() { |             DiffHandler() = default; | ||||||
|             } |  | ||||||
| 
 | 
 | ||||||
|             void node(const osmium::DiffNode&) const { |             void node(const osmium::DiffNode&) const { | ||||||
|             } |             } | ||||||
|  | |||||||
| @ -43,7 +43,12 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|     class OSMObject; |     class OSMObject; | ||||||
| 
 | 
 | ||||||
|     template <class TBasicIterator> |     /**
 | ||||||
|  |      * An input iterator wrapping any iterator over OSMObjects. When | ||||||
|  |      * dereferenced it will yield DiffObject objects pointing to the | ||||||
|  |      * underlying OSMObjects. | ||||||
|  |      */ | ||||||
|  |     template <typename TBasicIterator> | ||||||
|     class DiffIterator : public std::iterator<std::input_iterator_tag, const osmium::DiffObject> { |     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"); |         static_assert(std::is_base_of<osmium::OSMObject, typename TBasicIterator::value_type>::value, "TBasicIterator::value_type must derive from osmium::OSMObject"); | ||||||
| @ -56,37 +61,29 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|         mutable osmium::DiffObject m_diff; |         mutable osmium::DiffObject m_diff; | ||||||
| 
 | 
 | ||||||
|         void set_diff() const { |         void set_diff() const noexcept { | ||||||
|             assert(m_curr != m_end); |             assert(m_curr != m_end); | ||||||
| 
 | 
 | ||||||
|             TBasicIterator prev = m_prev; |             bool use_curr_for_prev =                    m_prev->type() != m_curr->type() || m_prev->id() != m_curr->id(); | ||||||
|             if (prev->type() != m_curr->type() || prev->id() != m_curr->id()) { |             bool use_curr_for_next = m_next == m_end || m_next->type() != m_curr->type() || m_next->id() != m_curr->id(); | ||||||
|                 prev = m_curr; |  | ||||||
|             } |  | ||||||
| 
 | 
 | ||||||
|             TBasicIterator next = m_next; |             m_diff = std::move(osmium::DiffObject{ | ||||||
|             if (next == m_end || next->type() != m_curr->type() || next->id() != m_curr->id()) { |                 *(use_curr_for_prev ? m_curr : m_prev), | ||||||
|                 next = m_curr; |                 *m_curr, | ||||||
|             } |                 *(use_curr_for_next ? m_curr : m_next) | ||||||
| 
 |             }); | ||||||
|             m_diff = osmium::DiffObject(*prev, *m_curr, *next); |  | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|     public: |     public: | ||||||
| 
 | 
 | ||||||
|         explicit DiffIterator(TBasicIterator begin, TBasicIterator end) : |         DiffIterator(TBasicIterator begin, TBasicIterator end) : | ||||||
|             m_prev(begin), |             m_prev(begin), | ||||||
|             m_curr(begin), |             m_curr(begin), | ||||||
|             m_next(begin == end ? begin : ++begin), |             m_next(begin == end ? begin : ++begin), | ||||||
|             m_end(end) { |             m_end(std::move(end)), | ||||||
|  |             m_diff() { | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         DiffIterator(const DiffIterator&) = default; |  | ||||||
|         DiffIterator& operator=(const DiffIterator&) = default; |  | ||||||
| 
 |  | ||||||
|         DiffIterator(DiffIterator&&) = default; |  | ||||||
|         DiffIterator& operator=(DiffIterator&&) = default; |  | ||||||
| 
 |  | ||||||
|         DiffIterator& operator++() { |         DiffIterator& operator++() { | ||||||
|             m_prev = std::move(m_curr); |             m_prev = std::move(m_curr); | ||||||
|             m_curr = m_next; |             m_curr = m_next; | ||||||
| @ -104,26 +101,35 @@ namespace osmium { | |||||||
|             return tmp; |             return tmp; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         bool operator==(const DiffIterator& rhs) const { |         bool operator==(const DiffIterator& rhs) const noexcept { | ||||||
|             return m_curr == rhs.m_curr && m_end == rhs.m_end; |             return m_curr == rhs.m_curr && m_end == rhs.m_end; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         bool operator!=(const DiffIterator& rhs) const { |         bool operator!=(const DiffIterator& rhs) const noexcept { | ||||||
|             return !(*this == rhs); |             return !(*this == rhs); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         reference operator*() const { |         reference operator*() const noexcept { | ||||||
|             set_diff(); |             set_diff(); | ||||||
|             return m_diff; |             return m_diff; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         pointer operator->() const { |         pointer operator->() const noexcept { | ||||||
|             set_diff(); |             set_diff(); | ||||||
|             return &m_diff; |             return &m_diff; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|     }; // class DiffIterator
 |     }; // class DiffIterator
 | ||||||
| 
 | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Create a DiffIterator based on the given iterators. | ||||||
|  |      */ | ||||||
|  |     template <typename TBasicIterator> | ||||||
|  |     inline DiffIterator<TBasicIterator> make_diff_iterator(TBasicIterator begin, | ||||||
|  |                                                            TBasicIterator end) { | ||||||
|  |         return DiffIterator<TBasicIterator>{begin, end}; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
| } // namespace osmium
 | } // namespace osmium
 | ||||||
| 
 | 
 | ||||||
| #endif // OSMIUM_DIFF_ITERATOR_HPP
 | #endif // OSMIUM_DIFF_ITERATOR_HPP
 | ||||||
|  | |||||||
| @ -43,7 +43,7 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|     namespace detail { |     namespace detail { | ||||||
| 
 | 
 | ||||||
|         template <class THandler> |         template <typename THandler> | ||||||
|         inline void apply_diff_iterator_recurse(const osmium::DiffObject& diff, THandler& handler) { |         inline void apply_diff_iterator_recurse(const osmium::DiffObject& diff, THandler& handler) { | ||||||
|             switch (diff.type()) { |             switch (diff.type()) { | ||||||
|                 case osmium::item_type::node: |                 case osmium::item_type::node: | ||||||
| @ -60,7 +60,7 @@ namespace osmium { | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         template <class THandler, class ...TRest> |         template <typename THandler, typename... TRest> | ||||||
|         inline void apply_diff_iterator_recurse(const osmium::DiffObject& diff, THandler& handler, TRest&... more) { |         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, handler); | ||||||
|             apply_diff_iterator_recurse(diff, more...); |             apply_diff_iterator_recurse(diff, more...); | ||||||
| @ -68,9 +68,9 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|     } // namespace detail
 |     } // namespace detail
 | ||||||
| 
 | 
 | ||||||
|     template <class TIterator, class ...THandlers> |     template <typename TIterator, typename... THandlers> | ||||||
|     inline void apply_diff(TIterator it, TIterator end, THandlers&... handlers) { |     inline void apply_diff(TIterator it, TIterator end, THandlers&... handlers) { | ||||||
|         typedef osmium::DiffIterator<TIterator> diff_iterator; |         using diff_iterator = osmium::DiffIterator<TIterator>; | ||||||
| 
 | 
 | ||||||
|         diff_iterator dit(it, end); |         diff_iterator dit(it, end); | ||||||
|         diff_iterator dend(end, end); |         diff_iterator dend(end, end); | ||||||
| @ -82,19 +82,19 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|     class OSMObject; |     class OSMObject; | ||||||
| 
 | 
 | ||||||
|     template <class TSource, class ...THandlers> |     template <typename TSource, typename... THandlers> | ||||||
|     inline void apply_diff(TSource& source, THandlers&... handlers) { |     inline void apply_diff(TSource& source, THandlers&... handlers) { | ||||||
|         apply_diff(osmium::io::InputIterator<TSource, osmium::OSMObject> {source}, |         apply_diff(osmium::io::InputIterator<TSource, osmium::OSMObject> {source}, | ||||||
|                    osmium::io::InputIterator<TSource, osmium::OSMObject> {}, |                    osmium::io::InputIterator<TSource, osmium::OSMObject> {}, | ||||||
|                    handlers...); |                    handlers...); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     template <class ...THandlers> |     template <typename... THandlers> | ||||||
|     inline void apply_diff(osmium::memory::Buffer& buffer, THandlers&... handlers) { |     inline void apply_diff(osmium::memory::Buffer& buffer, THandlers&... handlers) { | ||||||
|         apply_diff(buffer.begin(), buffer.end(), handlers...); |         apply_diff(buffer.begin(), buffer.end(), handlers...); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     template <class ...THandlers> |     template <typename... THandlers> | ||||||
|     inline void apply_diff(const osmium::memory::Buffer& buffer, THandlers&... handlers) { |     inline void apply_diff(const osmium::memory::Buffer& buffer, THandlers&... handlers) { | ||||||
|         apply_diff(buffer.cbegin(), buffer.cend(), handlers...); |         apply_diff(buffer.cbegin(), buffer.cend(), handlers...); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -36,16 +36,11 @@ DEALINGS IN THE SOFTWARE. | |||||||
| #include <memory> | #include <memory> | ||||||
| #include <utility> | #include <utility> | ||||||
| 
 | 
 | ||||||
|  | #include <osmium/fwd.hpp> | ||||||
| #include <osmium/handler.hpp> | #include <osmium/handler.hpp> | ||||||
| 
 | 
 | ||||||
| namespace osmium { | namespace osmium { | ||||||
| 
 | 
 | ||||||
|     class Node; |  | ||||||
|     class Way; |  | ||||||
|     class Relation; |  | ||||||
|     class Area; |  | ||||||
|     class Changeset; |  | ||||||
| 
 |  | ||||||
|     namespace handler { |     namespace handler { | ||||||
| 
 | 
 | ||||||
|         namespace detail { |         namespace detail { | ||||||
| @ -83,11 +78,11 @@ namespace osmium { | |||||||
|             // to either call handler style functions or visitor style operator().
 |             // to either call handler style functions or visitor style operator().
 | ||||||
| 
 | 
 | ||||||
| #define OSMIUM_DYNAMIC_HANDLER_DISPATCH(_name_, _type_) \ | #define OSMIUM_DYNAMIC_HANDLER_DISPATCH(_name_, _type_) \ | ||||||
| template <class THandler> \ | template <typename THandler> \ | ||||||
| auto _name_##_dispatch(THandler& handler, const osmium::_type_& object, int) -> decltype(handler._name_(object), void()) { \ | auto _name_##_dispatch(THandler& handler, const osmium::_type_& object, int) -> decltype(handler._name_(object), void()) { \ | ||||||
|     handler._name_(object); \ |     handler._name_(object); \ | ||||||
| } \ | } \ | ||||||
| template <class THandler> \ | template <typename THandler> \ | ||||||
| auto _name_##_dispatch(THandler& handler, const osmium::_type_& object, long) -> decltype(handler(object), void()) { \ | auto _name_##_dispatch(THandler& handler, const osmium::_type_& object, long) -> decltype(handler(object), void()) { \ | ||||||
|     handler(object); \ |     handler(object); \ | ||||||
| } | } | ||||||
| @ -98,47 +93,47 @@ auto _name_##_dispatch(THandler& handler, const osmium::_type_& object, long) -> | |||||||
|             OSMIUM_DYNAMIC_HANDLER_DISPATCH(changeset, Changeset) |             OSMIUM_DYNAMIC_HANDLER_DISPATCH(changeset, Changeset) | ||||||
|             OSMIUM_DYNAMIC_HANDLER_DISPATCH(area, Area) |             OSMIUM_DYNAMIC_HANDLER_DISPATCH(area, Area) | ||||||
| 
 | 
 | ||||||
|             template <class THandler> |             template <typename THandler> | ||||||
|             auto flush_dispatch(THandler& handler, int) -> decltype(handler.flush(), void()) { |             auto flush_dispatch(THandler& handler, int) -> decltype(handler.flush(), void()) { | ||||||
|                 handler.flush(); |                 handler.flush(); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             template <class THandler> |             template <typename THandler> | ||||||
|             void flush_dispatch(THandler&, long) {} |             void flush_dispatch(THandler&, long) {} | ||||||
| 
 | 
 | ||||||
|             template <class THandler> |             template <typename THandler> | ||||||
|             class HandlerWrapper : public HandlerWrapperBase { |             class HandlerWrapper : public HandlerWrapperBase { | ||||||
| 
 | 
 | ||||||
|                 THandler m_handler; |                 THandler m_handler; | ||||||
| 
 | 
 | ||||||
|             public: |             public: | ||||||
| 
 | 
 | ||||||
|                 template <class... TArgs> |                 template <typename... TArgs> | ||||||
|                 HandlerWrapper(TArgs&&... args) : |                 HandlerWrapper(TArgs&&... args) : | ||||||
|                     m_handler(std::forward<TArgs>(args)...) { |                     m_handler(std::forward<TArgs>(args)...) { | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void node(const osmium::Node& node) override final { |                 void node(const osmium::Node& node) final { | ||||||
|                     node_dispatch(m_handler, node, 0); |                     node_dispatch(m_handler, node, 0); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void way(const osmium::Way& way) override final { |                 void way(const osmium::Way& way) final { | ||||||
|                     way_dispatch(m_handler, way, 0); |                     way_dispatch(m_handler, way, 0); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void relation(const osmium::Relation& relation) override final { |                 void relation(const osmium::Relation& relation) final { | ||||||
|                     relation_dispatch(m_handler, relation, 0); |                     relation_dispatch(m_handler, relation, 0); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void area(const osmium::Area& area) override final { |                 void area(const osmium::Area& area) final { | ||||||
|                     area_dispatch(m_handler, area, 0); |                     area_dispatch(m_handler, area, 0); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void changeset(const osmium::Changeset& changeset) override final { |                 void changeset(const osmium::Changeset& changeset) final { | ||||||
|                     changeset_dispatch(m_handler, changeset, 0); |                     changeset_dispatch(m_handler, changeset, 0); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void flush() override final { |                 void flush() final { | ||||||
|                     flush_dispatch(m_handler, 0); |                     flush_dispatch(m_handler, 0); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
| @ -157,7 +152,7 @@ auto _name_##_dispatch(THandler& handler, const osmium::_type_& object, long) -> | |||||||
|                 m_impl(impl_ptr(new osmium::handler::detail::HandlerWrapperBase)) { |                 m_impl(impl_ptr(new osmium::handler::detail::HandlerWrapperBase)) { | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             template <class THandler, class... TArgs> |             template <typename THandler, typename... TArgs> | ||||||
|             void set(TArgs&&... args) { |             void set(TArgs&&... args) { | ||||||
|                 m_impl = impl_ptr(new osmium::handler::detail::HandlerWrapper<THandler>(std::forward<TArgs>(args)...)); |                 m_impl = impl_ptr(new osmium::handler::detail::HandlerWrapper<THandler>(std::forward<TArgs>(args)...)); | ||||||
|             } |             } | ||||||
| @ -188,7 +183,7 @@ auto _name_##_dispatch(THandler& handler, const osmium::_type_& object, long) -> | |||||||
| 
 | 
 | ||||||
|         }; // class DynamicHandler
 |         }; // class DynamicHandler
 | ||||||
| 
 | 
 | ||||||
|     } // namspace handler
 |     } // namespace handler
 | ||||||
| 
 | 
 | ||||||
| } // namespace osmium
 | } // namespace osmium
 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -33,10 +33,18 @@ DEALINGS IN THE SOFTWARE. | |||||||
| 
 | 
 | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| #include <osmium/handler/node_locations_for_ways.hpp> | #include <string> | ||||||
| #include <osmium/visitor.hpp> | #include <vector> | ||||||
| #include <osmium/area/multipolygon_collector.hpp> | 
 | ||||||
| #include <osmium/area/assembler.hpp> | #include <osmium/area/assembler.hpp> | ||||||
|  | #include <osmium/area/multipolygon_collector.hpp> | ||||||
|  | #include <osmium/handler/node_locations_for_ways.hpp> | ||||||
|  | #include <osmium/io/file.hpp> | ||||||
|  | #include <osmium/io/header.hpp> | ||||||
|  | #include <osmium/io/reader.hpp> | ||||||
|  | #include <osmium/memory/buffer.hpp> | ||||||
|  | #include <osmium/osm/entity_bits.hpp> | ||||||
|  | #include <osmium/visitor.hpp> | ||||||
| 
 | 
 | ||||||
| namespace osmium { | namespace osmium { | ||||||
| 
 | 
 | ||||||
| @ -45,7 +53,7 @@ namespace osmium { | |||||||
|      */ |      */ | ||||||
|     namespace experimental { |     namespace experimental { | ||||||
| 
 | 
 | ||||||
|         template <class TLocationHandler> |         template <typename TLocationHandler> | ||||||
|         class FlexReader { |         class FlexReader { | ||||||
| 
 | 
 | ||||||
|             bool m_with_areas; |             bool m_with_areas; | ||||||
| @ -104,7 +112,7 @@ namespace osmium { | |||||||
|                 return buffer; |                 return buffer; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             osmium::io::Header header() const { |             osmium::io::Header header() { | ||||||
|                 return m_reader.header(); |                 return m_reader.header(); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										70
									
								
								third_party/libosmium/include/osmium/fwd.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								third_party/libosmium/include/osmium/fwd.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,70 @@ | |||||||
|  | #ifndef OSMIUM_FWD_HPP | ||||||
|  | #define OSMIUM_FWD_HPP | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  | 
 | ||||||
|  | This file is part of Osmium (http://osmcode.org/libosmium).
 | ||||||
|  | 
 | ||||||
|  | Copyright 2013-2015 Jochen Topf <jochen@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. | ||||||
|  | 
 | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * | ||||||
|  |  * @file | ||||||
|  |  * | ||||||
|  |  * This file contains forward declarations for commonly used Osmium classes. | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | namespace osmium { | ||||||
|  | 
 | ||||||
|  |     class Area; | ||||||
|  |     class Box; | ||||||
|  |     class Changeset; | ||||||
|  |     class ChangesetComment; | ||||||
|  |     class ChangesetDiscussion; | ||||||
|  |     class InnerRing; | ||||||
|  |     class Location; | ||||||
|  |     class Node; | ||||||
|  |     class NodeRef; | ||||||
|  |     class NodeRefList; | ||||||
|  |     class OSMEntity; | ||||||
|  |     class OSMObject; | ||||||
|  |     class OuterRing; | ||||||
|  |     class Relation; | ||||||
|  |     class RelationMemberList; | ||||||
|  |     class Segment; | ||||||
|  |     class Tag; | ||||||
|  |     class TagList; | ||||||
|  |     class Timestamp; | ||||||
|  |     class Way; | ||||||
|  |     class WayNodeList; | ||||||
|  | 
 | ||||||
|  | } // namespace osmium
 | ||||||
|  | 
 | ||||||
|  | #endif // OSMIUM_FWD_HPP
 | ||||||
| @ -33,7 +33,6 @@ DEALINGS IN THE SOFTWARE. | |||||||
| 
 | 
 | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| #include <cstddef> |  | ||||||
| #include <iosfwd> | #include <iosfwd> | ||||||
| #include <string> | #include <string> | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -61,7 +61,7 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|     public: |     public: | ||||||
| 
 | 
 | ||||||
|         geometry_error(const std::string& message, const char* object_type = "", osmium::object_id_type id = 0) : |         explicit geometry_error(const std::string& message, const char* object_type = "", osmium::object_id_type id = 0) : | ||||||
|             std::runtime_error(message), |             std::runtime_error(message), | ||||||
|             m_message(message), |             m_message(message), | ||||||
|             m_id(id) { |             m_id(id) { | ||||||
| @ -89,7 +89,7 @@ namespace osmium { | |||||||
|             return m_id; |             return m_id; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         virtual const char* what() const noexcept override { |         const char* what() const noexcept override { | ||||||
|             return m_message.c_str(); |             return m_message.c_str(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| @ -142,7 +142,7 @@ namespace osmium { | |||||||
|         /**
 |         /**
 | ||||||
|          * Geometry factory. |          * Geometry factory. | ||||||
|          */ |          */ | ||||||
|         template <class TGeomImpl, class TProjection = IdentityProjection> |         template <typename TGeomImpl, typename TProjection = IdentityProjection> | ||||||
|         class GeometryFactory { |         class GeometryFactory { | ||||||
| 
 | 
 | ||||||
|             /**
 |             /**
 | ||||||
| @ -166,8 +166,8 @@ namespace osmium { | |||||||
|             /**
 |             /**
 | ||||||
|              * Constructor for default initialized projection. |              * Constructor for default initialized projection. | ||||||
|              */ |              */ | ||||||
|             template <class... TArgs> |             template <typename... TArgs> | ||||||
|             GeometryFactory<TGeomImpl, TProjection>(TArgs&&... args) : |             explicit GeometryFactory<TGeomImpl, TProjection>(TArgs&&... args) : | ||||||
|                 m_projection(), |                 m_projection(), | ||||||
|                 m_impl(std::forward<TArgs>(args)...) { |                 m_impl(std::forward<TArgs>(args)...) { | ||||||
|             } |             } | ||||||
| @ -176,12 +176,13 @@ namespace osmium { | |||||||
|              * Constructor for explicitly initialized projection. Note that the |              * Constructor for explicitly initialized projection. Note that the | ||||||
|              * projection is moved into the GeometryFactory. |              * projection is moved into the GeometryFactory. | ||||||
|              */ |              */ | ||||||
|             template <class... TArgs> |             template <typename... TArgs> | ||||||
|             GeometryFactory<TGeomImpl, TProjection>(TProjection&& projection, TArgs&&... args) : |             explicit GeometryFactory<TGeomImpl, TProjection>(TProjection&& projection, TArgs&&... args) : | ||||||
|                 m_projection(std::move(projection)), |                 m_projection(std::move(projection)), | ||||||
|                 m_impl(std::forward<TArgs>(args)...) { |                 m_impl(std::forward<TArgs>(args)...) { | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  |             typedef TProjection projection_type; | ||||||
|             typedef typename TGeomImpl::point_type        point_type; |             typedef typename TGeomImpl::point_type        point_type; | ||||||
|             typedef typename TGeomImpl::linestring_type   linestring_type; |             typedef typename TGeomImpl::linestring_type   linestring_type; | ||||||
|             typedef typename TGeomImpl::polygon_type      polygon_type; |             typedef typename TGeomImpl::polygon_type      polygon_type; | ||||||
| @ -198,7 +199,7 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|             /* Point */ |             /* Point */ | ||||||
| 
 | 
 | ||||||
|             point_type create_point(const osmium::Location location) const { |             point_type create_point(const osmium::Location& location) const { | ||||||
|                 return m_impl.make_point(m_projection(location)); |                 return m_impl.make_point(m_projection(location)); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
| @ -226,7 +227,7 @@ namespace osmium { | |||||||
|                 m_impl.linestring_start(); |                 m_impl.linestring_start(); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             template <class TIter> |             template <typename TIter> | ||||||
|             size_t fill_linestring(TIter it, TIter end) { |             size_t fill_linestring(TIter it, TIter end) { | ||||||
|                 size_t num_points = 0; |                 size_t num_points = 0; | ||||||
|                 for (; it != end; ++it, ++num_points) { |                 for (; it != end; ++it, ++num_points) { | ||||||
| @ -235,7 +236,7 @@ namespace osmium { | |||||||
|                 return num_points; |                 return num_points; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             template <class TIter> |             template <typename TIter> | ||||||
|             size_t fill_linestring_unique(TIter it, TIter end) { |             size_t fill_linestring_unique(TIter it, TIter end) { | ||||||
|                 size_t num_points = 0; |                 size_t num_points = 0; | ||||||
|                 osmium::Location last_location; |                 osmium::Location last_location; | ||||||
| @ -300,7 +301,7 @@ namespace osmium { | |||||||
|                 m_impl.polygon_start(); |                 m_impl.polygon_start(); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             template <class TIter> |             template <typename TIter> | ||||||
|             size_t fill_polygon(TIter it, TIter end) { |             size_t fill_polygon(TIter it, TIter end) { | ||||||
|                 size_t num_points = 0; |                 size_t num_points = 0; | ||||||
|                 for (; it != end; ++it, ++num_points) { |                 for (; it != end; ++it, ++num_points) { | ||||||
| @ -309,7 +310,7 @@ namespace osmium { | |||||||
|                 return num_points; |                 return num_points; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             template <class TIter> |             template <typename TIter> | ||||||
|             size_t fill_polygon_unique(TIter it, TIter end) { |             size_t fill_polygon_unique(TIter it, TIter end) { | ||||||
|                 size_t num_points = 0; |                 size_t num_points = 0; | ||||||
|                 osmium::Location last_location; |                 osmium::Location last_location; | ||||||
|  | |||||||
| @ -88,7 +88,10 @@ namespace osmium { | |||||||
|                 linestring_type linestring_finish(size_t /* num_points */) { |                 linestring_type linestring_finish(size_t /* num_points */) { | ||||||
|                     assert(!m_str.empty()); |                     assert(!m_str.empty()); | ||||||
|                     std::string str; |                     std::string str; | ||||||
|                     std::swap(str, m_str); | 
 | ||||||
|  |                     using std::swap; | ||||||
|  |                     swap(str, m_str); | ||||||
|  | 
 | ||||||
|                     str.back() = ']'; |                     str.back() = ']'; | ||||||
|                     str += "}"; |                     str += "}"; | ||||||
|                     return str; |                     return str; | ||||||
| @ -134,7 +137,10 @@ namespace osmium { | |||||||
|                 multipolygon_type multipolygon_finish() { |                 multipolygon_type multipolygon_finish() { | ||||||
|                     assert(!m_str.empty()); |                     assert(!m_str.empty()); | ||||||
|                     std::string str; |                     std::string str; | ||||||
|                     std::swap(str, m_str); | 
 | ||||||
|  |                     using std::swap; | ||||||
|  |                     swap(str, m_str); | ||||||
|  | 
 | ||||||
|                     str.back() = ']'; |                     str.back() = ']'; | ||||||
|                     str += "}"; |                     str += "}"; | ||||||
|                     return str; |                     return str; | ||||||
| @ -144,7 +150,7 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|         } // namespace detail
 |         } // namespace detail
 | ||||||
| 
 | 
 | ||||||
|         template <class TProjection = IdentityProjection> |         template <typename TProjection = IdentityProjection> | ||||||
|         using GeoJSONFactory = GeometryFactory<osmium::geom::detail::GeoJSONFactoryImpl, TProjection>; |         using GeoJSONFactory = GeometryFactory<osmium::geom::detail::GeoJSONFactoryImpl, TProjection>; | ||||||
| 
 | 
 | ||||||
|     } // namespace geom
 |     } // namespace geom
 | ||||||
|  | |||||||
| @ -228,7 +228,7 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|         } // namespace detail
 |         } // namespace detail
 | ||||||
| 
 | 
 | ||||||
|         template <class TProjection = IdentityProjection> |         template <typename TProjection = IdentityProjection> | ||||||
|         using GEOSFactory = GeometryFactory<osmium::geom::detail::GEOSFactoryImpl, TProjection>; |         using GEOSFactory = GeometryFactory<osmium::geom::detail::GEOSFactoryImpl, TProjection>; | ||||||
| 
 | 
 | ||||||
|     } // namespace geom
 |     } // namespace geom
 | ||||||
|  | |||||||
| @ -47,35 +47,7 @@ DEALINGS IN THE SOFTWARE. | |||||||
| #include <memory> | #include <memory> | ||||||
| #include <utility> | #include <utility> | ||||||
| 
 | 
 | ||||||
| #ifdef _MSC_VER | #include <ogr_geometry.h> | ||||||
| # pragma warning(push) |  | ||||||
| # pragma warning(disable : 4458) |  | ||||||
| # pragma warning(disable : 4251) |  | ||||||
| #else |  | ||||||
| # pragma GCC diagnostic push |  | ||||||
| # ifdef __clang__ |  | ||||||
| #  pragma GCC diagnostic ignored "-Wdocumentation-unknown-command" |  | ||||||
| # endif |  | ||||||
| # pragma GCC diagnostic ignored "-Wfloat-equal" |  | ||||||
| # pragma GCC diagnostic ignored "-Wold-style-cast" |  | ||||||
| # pragma GCC diagnostic ignored "-Wpadded" |  | ||||||
| # pragma GCC diagnostic ignored "-Wredundant-decls" |  | ||||||
| # pragma GCC diagnostic ignored "-Wshadow" |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| /* Strictly speaking the following include would be enough here,
 |  | ||||||
|    but everybody using this file will very likely need the other includes, |  | ||||||
|    so we are adding them here, so that not everybody will need all those |  | ||||||
|    pragmas to disable warnings. */ |  | ||||||
| //#include <ogr_geometry.h>
 |  | ||||||
| #include <ogr_api.h> |  | ||||||
| #include <ogrsf_frmts.h> |  | ||||||
| 
 |  | ||||||
| #ifdef _MSC_VER |  | ||||||
| # pragma warning(pop) |  | ||||||
| #else |  | ||||||
| # pragma GCC diagnostic pop |  | ||||||
| #endif |  | ||||||
| 
 | 
 | ||||||
| #include <osmium/geom/coordinates.hpp> | #include <osmium/geom/coordinates.hpp> | ||||||
| #include <osmium/geom/factory.hpp> | #include <osmium/geom/factory.hpp> | ||||||
| @ -196,7 +168,7 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|         } // namespace detail
 |         } // namespace detail
 | ||||||
| 
 | 
 | ||||||
|         template <class TProjection = IdentityProjection> |         template <typename TProjection = IdentityProjection> | ||||||
|         using OGRFactory = GeometryFactory<osmium::geom::detail::OGRFactoryImpl, TProjection>; |         using OGRFactory = GeometryFactory<osmium::geom::detail::OGRFactoryImpl, TProjection>; | ||||||
| 
 | 
 | ||||||
|     } // namespace geom
 |     } // namespace geom
 | ||||||
|  | |||||||
| @ -46,7 +46,7 @@ namespace osmium { | |||||||
|              * A geometry factory implementation that can be used with the |              * A geometry factory implementation that can be used with the | ||||||
|              * RapidJSON (https://github.com/miloyip/rapidjson) JSON writer.
 |              * RapidJSON (https://github.com/miloyip/rapidjson) JSON writer.
 | ||||||
|              */ |              */ | ||||||
|             template <class TWriter> |             template <typename TWriter> | ||||||
|             class RapidGeoJSONFactoryImpl { |             class RapidGeoJSONFactoryImpl { | ||||||
| 
 | 
 | ||||||
|                 TWriter* m_writer; |                 TWriter* m_writer; | ||||||
| @ -180,7 +180,7 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|         } // namespace detail
 |         } // namespace detail
 | ||||||
| 
 | 
 | ||||||
|         template <class TWriter, class TProjection = IdentityProjection> |         template <typename TWriter, typename TProjection = IdentityProjection> | ||||||
|         using RapidGeoJSONFactory = GeometryFactory<detail::RapidGeoJSONFactoryImpl<TWriter>, TProjection>; |         using RapidGeoJSONFactory = GeometryFactory<detail::RapidGeoJSONFactoryImpl<TWriter>, TProjection>; | ||||||
| 
 | 
 | ||||||
|     } // namespace geom
 |     } // namespace geom
 | ||||||
|  | |||||||
| @ -67,10 +67,10 @@ namespace osmium { | |||||||
|             explicit Tile(uint32_t zoom, const osmium::Location& location) : |             explicit Tile(uint32_t zoom, const osmium::Location& location) : | ||||||
|                 z(zoom) { |                 z(zoom) { | ||||||
|                 osmium::geom::Coordinates c = lonlat_to_mercator(location); |                 osmium::geom::Coordinates c = lonlat_to_mercator(location); | ||||||
|                 const int32_t n = 1LL << zoom; |                 const int32_t n = 1 << zoom; | ||||||
|                 const double scale = detail::max_coordinate_epsg3857 * 2 / n; |                 const double scale = detail::max_coordinate_epsg3857 * 2 / n; | ||||||
|                 x = detail::restrict_to_range<int32_t>((c.x + detail::max_coordinate_epsg3857) / scale, 0, n-1); |                 x = uint32_t(detail::restrict_to_range<int32_t>(int32_t((c.x + detail::max_coordinate_epsg3857) / scale), 0, n-1)); | ||||||
|                 y = detail::restrict_to_range<int32_t>((detail::max_coordinate_epsg3857 - c.y) / scale, 0, n-1); |                 y = uint32_t(detail::restrict_to_range<int32_t>(int32_t((detail::max_coordinate_epsg3857 - c.y) / scale), 0, n-1)); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|         }; // struct Tile
 |         }; // struct Tile
 | ||||||
|  | |||||||
| @ -188,7 +188,9 @@ namespace osmium { | |||||||
|                 linestring_type linestring_finish(size_t num_points) { |                 linestring_type linestring_finish(size_t num_points) { | ||||||
|                     set_size(m_linestring_size_offset, num_points); |                     set_size(m_linestring_size_offset, num_points); | ||||||
|                     std::string data; |                     std::string data; | ||||||
|                     std::swap(data, m_data); | 
 | ||||||
|  |                     using std::swap; | ||||||
|  |                     swap(data, m_data); | ||||||
| 
 | 
 | ||||||
|                     if (m_out_type == out_type::hex) { |                     if (m_out_type == out_type::hex) { | ||||||
|                         return convert_to_hex(data); |                         return convert_to_hex(data); | ||||||
| @ -246,7 +248,9 @@ namespace osmium { | |||||||
|                 multipolygon_type multipolygon_finish() { |                 multipolygon_type multipolygon_finish() { | ||||||
|                     set_size(m_multipolygon_size_offset, m_polygons); |                     set_size(m_multipolygon_size_offset, m_polygons); | ||||||
|                     std::string data; |                     std::string data; | ||||||
|                     std::swap(data, m_data); | 
 | ||||||
|  |                     using std::swap; | ||||||
|  |                     swap(data, m_data); | ||||||
| 
 | 
 | ||||||
|                     if (m_out_type == out_type::hex) { |                     if (m_out_type == out_type::hex) { | ||||||
|                         return convert_to_hex(data); |                         return convert_to_hex(data); | ||||||
| @ -259,7 +263,7 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|         } // namespace detail
 |         } // namespace detail
 | ||||||
| 
 | 
 | ||||||
|         template <class TProjection = IdentityProjection> |         template <typename TProjection = IdentityProjection> | ||||||
|         using WKBFactory = GeometryFactory<osmium::geom::detail::WKBFactoryImpl, TProjection>; |         using WKBFactory = GeometryFactory<osmium::geom::detail::WKBFactoryImpl, TProjection>; | ||||||
| 
 | 
 | ||||||
|     } // namespace geom
 |     } // namespace geom
 | ||||||
|  | |||||||
| @ -86,7 +86,10 @@ namespace osmium { | |||||||
|                 linestring_type linestring_finish(size_t /* num_points */) { |                 linestring_type linestring_finish(size_t /* num_points */) { | ||||||
|                     assert(!m_str.empty()); |                     assert(!m_str.empty()); | ||||||
|                     std::string str; |                     std::string str; | ||||||
|                     std::swap(str, m_str); | 
 | ||||||
|  |                     using std::swap; | ||||||
|  |                     swap(str, m_str); | ||||||
|  | 
 | ||||||
|                     str.back() = ')'; |                     str.back() = ')'; | ||||||
|                     return str; |                     return str; | ||||||
|                 } |                 } | ||||||
| @ -131,7 +134,10 @@ namespace osmium { | |||||||
|                 multipolygon_type multipolygon_finish() { |                 multipolygon_type multipolygon_finish() { | ||||||
|                     assert(!m_str.empty()); |                     assert(!m_str.empty()); | ||||||
|                     std::string str; |                     std::string str; | ||||||
|                     std::swap(str, m_str); | 
 | ||||||
|  |                     using std::swap; | ||||||
|  |                     swap(str, m_str); | ||||||
|  | 
 | ||||||
|                     str.back() = ')'; |                     str.back() = ')'; | ||||||
|                     return str; |                     return str; | ||||||
|                 } |                 } | ||||||
| @ -140,7 +146,7 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|         } // namespace detail
 |         } // namespace detail
 | ||||||
| 
 | 
 | ||||||
|         template <class TProjection = IdentityProjection> |         template <typename TProjection = IdentityProjection> | ||||||
|         using WKTFactory = GeometryFactory<osmium::geom::detail::WKTFactoryImpl, TProjection>; |         using WKTFactory = GeometryFactory<osmium::geom::detail::WKTFactoryImpl, TProjection>; | ||||||
| 
 | 
 | ||||||
|     } // namespace geom
 |     } // namespace geom
 | ||||||
|  | |||||||
							
								
								
									
										19
									
								
								third_party/libosmium/include/osmium/handler.hpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										19
									
								
								third_party/libosmium/include/osmium/handler.hpp
									
									
									
									
										vendored
									
									
								
							| @ -33,19 +33,9 @@ DEALINGS IN THE SOFTWARE. | |||||||
| 
 | 
 | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| namespace osmium { | #include <osmium/fwd.hpp> | ||||||
| 
 | 
 | ||||||
|     class OSMObject; | namespace osmium { | ||||||
|     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 |      * @brief Osmium handlers provide callbacks for OSM objects | ||||||
| @ -89,12 +79,15 @@ namespace osmium { | |||||||
|             void inner_ring(const osmium::InnerRing&) const { |             void inner_ring(const osmium::InnerRing&) const { | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  |             void changeset_discussion(const osmium::ChangesetDiscussion&) const { | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|             void flush() const { |             void flush() const { | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|         }; // class Handler
 |         }; // class Handler
 | ||||||
| 
 | 
 | ||||||
|     } // namspace handler
 |     } // namespace handler
 | ||||||
| 
 | 
 | ||||||
| } // namespace osmium
 | } // namespace osmium
 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -38,14 +38,14 @@ DEALINGS IN THE SOFTWARE. | |||||||
| #include <osmium/handler.hpp> | #include <osmium/handler.hpp> | ||||||
| 
 | 
 | ||||||
| #define OSMIUM_CHAIN_HANDLER_CALL(_func_, _type_) \ | #define OSMIUM_CHAIN_HANDLER_CALL(_func_, _type_) \ | ||||||
|     template <int N, int SIZE, class THandlers> \ |     template <int N, int SIZE, typename THandlers> \ | ||||||
|     struct call_ ## _func_ { \ |     struct call_ ## _func_ { \ | ||||||
|         void operator()(THandlers& handlers, osmium::_type_& object) { \ |         void operator()(THandlers& handlers, osmium::_type_& object) { \ | ||||||
|             std::get<N>(handlers)._func_(object); \ |             std::get<N>(handlers)._func_(object); \ | ||||||
|             call_ ## _func_<N+1, SIZE, THandlers>()(handlers, object); \ |             call_ ## _func_<N+1, SIZE, THandlers>()(handlers, object); \ | ||||||
|         } \ |         } \ | ||||||
|     }; \ |     }; \ | ||||||
|     template <int SIZE, class THandlers> \ |     template <int SIZE, typename THandlers> \ | ||||||
|     struct call_ ## _func_<SIZE, SIZE, THandlers> { \ |     struct call_ ## _func_<SIZE, SIZE, THandlers> { \ | ||||||
|         void operator()(THandlers&, osmium::_type_&) {} \ |         void operator()(THandlers&, osmium::_type_&) {} \ | ||||||
|     }; |     }; | ||||||
| @ -64,13 +64,13 @@ namespace osmium { | |||||||
|          * This handler allows chaining of any number of handlers into a single |          * This handler allows chaining of any number of handlers into a single | ||||||
|          * handler. |          * handler. | ||||||
|          */ |          */ | ||||||
|         template <class ...THandler> |         template <typename... THandler> | ||||||
|         class ChainHandler : public osmium::handler::Handler { |         class ChainHandler : public osmium::handler::Handler { | ||||||
| 
 | 
 | ||||||
|             typedef std::tuple<THandler&...> handlers_type; |             typedef std::tuple<THandler&...> handlers_type; | ||||||
|             handlers_type m_handlers; |             handlers_type m_handlers; | ||||||
| 
 | 
 | ||||||
|             template <int N, int SIZE, class THandlers> |             template <int N, int SIZE, typename THandlers> | ||||||
|             struct call_flush { |             struct call_flush { | ||||||
|                 void operator()(THandlers& handlers) { |                 void operator()(THandlers& handlers) { | ||||||
|                     std::get<N>(handlers).flush(); |                     std::get<N>(handlers).flush(); | ||||||
| @ -78,7 +78,7 @@ namespace osmium { | |||||||
|                 } |                 } | ||||||
|             }; // struct call_flush
 |             }; // struct call_flush
 | ||||||
| 
 | 
 | ||||||
|             template <int SIZE, class THandlers> |             template <int SIZE, typename THandlers> | ||||||
|             struct call_flush<SIZE, SIZE, THandlers> { |             struct call_flush<SIZE, SIZE, THandlers> { | ||||||
|                 void operator()(THandlers&) {} |                 void operator()(THandlers&) {} | ||||||
|             }; // struct call_flush
 |             }; // struct call_flush
 | ||||||
|  | |||||||
| @ -60,7 +60,7 @@ namespace osmium { | |||||||
|          *                        get(id) methods. |          *                        get(id) methods. | ||||||
|          * @tparam TStorageNegIDs Same but for negative IDs. |          * @tparam TStorageNegIDs Same but for negative IDs. | ||||||
|          */ |          */ | ||||||
|         template <class TStoragePosIDs, class TStorageNegIDs = dummy_type> |         template <typename TStoragePosIDs, typename TStorageNegIDs = dummy_type> | ||||||
|         class NodeLocationsForWays : public osmium::handler::Handler { |         class NodeLocationsForWays : public osmium::handler::Handler { | ||||||
| 
 | 
 | ||||||
|             static_assert(std::is_base_of<osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>, TStoragePosIDs>::value, "Index class must be derived from osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>"); |             static_assert(std::is_base_of<osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>, TStoragePosIDs>::value, "Index class must be derived from osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>"); | ||||||
|  | |||||||
| @ -56,11 +56,13 @@ namespace osmium { | |||||||
|         public: |         public: | ||||||
| 
 | 
 | ||||||
|             BoolVector() = default; |             BoolVector() = default; | ||||||
|  | 
 | ||||||
|             BoolVector(const BoolVector&) = default; |             BoolVector(const BoolVector&) = default; | ||||||
|             BoolVector(BoolVector&&) = default; |             BoolVector(BoolVector&&) = default; | ||||||
|             BoolVector& operator=(const BoolVector&) = default; |             BoolVector& operator=(const BoolVector&) = default; | ||||||
|             BoolVector& operator=(BoolVector&&) = default; |             BoolVector& operator=(BoolVector&&) = default; | ||||||
|             ~BoolVector() = default; | 
 | ||||||
|  |             ~BoolVector() noexcept = default; | ||||||
| 
 | 
 | ||||||
|             void set(T id, bool value = true) { |             void set(T id, bool value = true) { | ||||||
|                 if (m_bits.size() <= id) { |                 if (m_bits.size() <= id) { | ||||||
|  | |||||||
| @ -47,19 +47,18 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|         namespace detail { |         namespace detail { | ||||||
| 
 | 
 | ||||||
|             template <class T> |             template <typename T> | ||||||
|             inline T* create_map_with_fd(const std::vector<std::string>& config) { |             inline T* create_map_with_fd(const std::vector<std::string>& config) { | ||||||
|                 if (config.size() == 1) { |                 if (config.size() == 1) { | ||||||
|                     return new T(); |                     return new T(); | ||||||
|                 } else { |  | ||||||
|                     assert(config.size() > 1); |  | ||||||
|                     const std::string& filename = config[1]; |  | ||||||
|                     int fd = ::open(filename.c_str(), O_CREAT | O_RDWR, 0644); |  | ||||||
|                     if (fd == -1) { |  | ||||||
|                         throw std::runtime_error(std::string("can't open file '") + filename + "': " + strerror(errno)); |  | ||||||
|                     } |  | ||||||
|                     return new T(fd); |  | ||||||
|                 } |                 } | ||||||
|  |                 assert(config.size() > 1); | ||||||
|  |                 const std::string& filename = config[1]; | ||||||
|  |                 int fd = ::open(filename.c_str(), O_CREAT | O_RDWR, 0644); | ||||||
|  |                 if (fd == -1) { | ||||||
|  |                     throw std::runtime_error(std::string("can't open file '") + filename + "': " + strerror(errno)); | ||||||
|  |                 } | ||||||
|  |                 return new T(fd); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|         } // namespace detail
 |         } // namespace detail
 | ||||||
|  | |||||||
| @ -54,6 +54,8 @@ namespace osmium { | |||||||
|                 mmap_vector_base<T>() { |                 mmap_vector_base<T>() { | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  |             ~mmap_vector_anon() noexcept = default; | ||||||
|  | 
 | ||||||
|         }; // class mmap_vector_anon
 |         }; // class mmap_vector_anon
 | ||||||
| 
 | 
 | ||||||
|     } // namespace detail
 |     } // namespace detail
 | ||||||
|  | |||||||
| @ -60,7 +60,7 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|         public: |         public: | ||||||
| 
 | 
 | ||||||
|             explicit mmap_vector_base(int fd, size_t capacity, size_t size = 0) : |             mmap_vector_base(int fd, size_t capacity, size_t size = 0) : | ||||||
|                 m_size(size), |                 m_size(size), | ||||||
|                 m_mapping(capacity, osmium::util::MemoryMapping::mapping_mode::write_shared, fd) { |                 m_mapping(capacity, osmium::util::MemoryMapping::mapping_mode::write_shared, fd) { | ||||||
|             } |             } | ||||||
| @ -70,6 +70,8 @@ namespace osmium { | |||||||
|                 m_mapping(capacity) { |                 m_mapping(capacity) { | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  |             ~mmap_vector_base() noexcept = default; | ||||||
|  | 
 | ||||||
|             typedef T value_type; |             typedef T value_type; | ||||||
|             typedef T& reference; |             typedef T& reference; | ||||||
|             typedef const T& const_reference; |             typedef const T& const_reference; | ||||||
| @ -78,8 +80,6 @@ namespace osmium { | |||||||
|             typedef T* iterator; |             typedef T* iterator; | ||||||
|             typedef const T* const_iterator; |             typedef const T* const_iterator; | ||||||
| 
 | 
 | ||||||
|             ~mmap_vector_base() = default; |  | ||||||
| 
 |  | ||||||
|             void close() { |             void close() { | ||||||
|                 m_mapping.unmap(); |                 m_mapping.unmap(); | ||||||
|             } |             } | ||||||
|  | |||||||
| @ -50,17 +50,21 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|         public: |         public: | ||||||
| 
 | 
 | ||||||
|             explicit mmap_vector_file() : mmap_vector_base<T>( |             mmap_vector_file() : | ||||||
|  |                 mmap_vector_base<T>( | ||||||
|                     osmium::detail::create_tmp_file(), |                     osmium::detail::create_tmp_file(), | ||||||
|                     osmium::detail::mmap_vector_size_increment) { |                     osmium::detail::mmap_vector_size_increment) { | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             explicit mmap_vector_file(int fd) : mmap_vector_base<T>( |             explicit mmap_vector_file(int fd) : | ||||||
|  |                 mmap_vector_base<T>( | ||||||
|                     fd, |                     fd, | ||||||
|                     osmium::util::file_size(fd) / sizeof(T), |                     osmium::util::file_size(fd) / sizeof(T), | ||||||
|                     osmium::util::file_size(fd) / sizeof(T)) { |                     osmium::util::file_size(fd) / sizeof(T)) { | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  |             ~mmap_vector_file() noexcept = default; | ||||||
|  | 
 | ||||||
|         }; // class mmap_vector_file
 |         }; // class mmap_vector_file
 | ||||||
| 
 | 
 | ||||||
|     } // namespace detail
 |     } // namespace detail
 | ||||||
|  | |||||||
| @ -48,7 +48,7 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|         namespace map { |         namespace map { | ||||||
| 
 | 
 | ||||||
|             template <class TVector, typename TId, typename TValue> |             template <typename TVector, typename TId, typename TValue> | ||||||
|             class VectorBasedDenseMap : public Map<TId, TValue> { |             class VectorBasedDenseMap : public Map<TId, TValue> { | ||||||
| 
 | 
 | ||||||
|                 TVector m_vector; |                 TVector m_vector; | ||||||
| @ -68,20 +68,20 @@ namespace osmium { | |||||||
|                     m_vector(fd) { |                     m_vector(fd) { | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 ~VectorBasedDenseMap() = default; |                 ~VectorBasedDenseMap() noexcept final = default; | ||||||
| 
 | 
 | ||||||
|                 void reserve(const size_t size) override final { |                 void reserve(const size_t size) final { | ||||||
|                     m_vector.reserve(size); |                     m_vector.reserve(size); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void set(const TId id, const TValue value) override final { |                 void set(const TId id, const TValue value) final { | ||||||
|                     if (size() <= id) { |                     if (size() <= id) { | ||||||
|                         m_vector.resize(id+1); |                         m_vector.resize(id+1); | ||||||
|                     } |                     } | ||||||
|                     m_vector[id] = value; |                     m_vector[id] = value; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 const TValue get(const TId id) const override final { |                 const TValue get(const TId id) const final { | ||||||
|                     try { |                     try { | ||||||
|                         const TValue& value = m_vector.at(id); |                         const TValue& value = m_vector.at(id); | ||||||
|                         if (value == osmium::index::empty_value<TValue>()) { |                         if (value == osmium::index::empty_value<TValue>()) { | ||||||
| @ -93,7 +93,7 @@ namespace osmium { | |||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 size_t size() const override final { |                 size_t size() const final { | ||||||
|                     return m_vector.size(); |                     return m_vector.size(); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
| @ -101,16 +101,16 @@ namespace osmium { | |||||||
|                     return m_vector.size() * sizeof(element_type); |                     return m_vector.size() * sizeof(element_type); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 size_t used_memory() const override final { |                 size_t used_memory() const final { | ||||||
|                     return sizeof(TValue) * size(); |                     return sizeof(TValue) * size(); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void clear() override final { |                 void clear() final { | ||||||
|                     m_vector.clear(); |                     m_vector.clear(); | ||||||
|                     m_vector.shrink_to_fit(); |                     m_vector.shrink_to_fit(); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void dump_as_array(const int fd) override final { |                 void dump_as_array(const int fd) final { | ||||||
|                     osmium::io::detail::reliable_write(fd, reinterpret_cast<const char*>(m_vector.data()), byte_size()); |                     osmium::io::detail::reliable_write(fd, reinterpret_cast<const char*>(m_vector.data()), byte_size()); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
| @ -161,17 +161,17 @@ namespace osmium { | |||||||
|                     m_vector() { |                     m_vector() { | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 VectorBasedSparseMap(int fd) : |                 explicit VectorBasedSparseMap(int fd) : | ||||||
|                     m_vector(fd) { |                     m_vector(fd) { | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 ~VectorBasedSparseMap() override final = default; |                 ~VectorBasedSparseMap() final = default; | ||||||
| 
 | 
 | ||||||
|                 void set(const TId id, const TValue value) override final { |                 void set(const TId id, const TValue value) final { | ||||||
|                     m_vector.push_back(element_type(id, value)); |                     m_vector.push_back(element_type(id, value)); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 const TValue get(const TId id) const override final { |                 const TValue get(const TId id) const final { | ||||||
|                     const element_type element { |                     const element_type element { | ||||||
|                         id, |                         id, | ||||||
|                         osmium::index::empty_value<TValue>() |                         osmium::index::empty_value<TValue>() | ||||||
| @ -186,7 +186,7 @@ namespace osmium { | |||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 size_t size() const override final { |                 size_t size() const final { | ||||||
|                     return m_vector.size(); |                     return m_vector.size(); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
| @ -194,20 +194,20 @@ namespace osmium { | |||||||
|                     return m_vector.size() * sizeof(element_type); |                     return m_vector.size() * sizeof(element_type); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 size_t used_memory() const override final { |                 size_t used_memory() const final { | ||||||
|                     return sizeof(element_type) * size(); |                     return sizeof(element_type) * size(); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void clear() override final { |                 void clear() final { | ||||||
|                     m_vector.clear(); |                     m_vector.clear(); | ||||||
|                     m_vector.shrink_to_fit(); |                     m_vector.shrink_to_fit(); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void sort() override final { |                 void sort() final { | ||||||
|                     std::sort(m_vector.begin(), m_vector.end()); |                     std::sort(m_vector.begin(), m_vector.end()); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void dump_as_list(const int fd) override final { |                 void dump_as_list(const int fd) final { | ||||||
|                     osmium::io::detail::reliable_write(fd, reinterpret_cast<const char*>(m_vector.data()), byte_size()); |                     osmium::io::detail::reliable_write(fd, reinterpret_cast<const char*>(m_vector.data()), byte_size()); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -75,9 +75,9 @@ namespace osmium { | |||||||
|                     m_vector(fd) { |                     m_vector(fd) { | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 ~VectorBasedSparseMultimap() = default; |                 ~VectorBasedSparseMultimap() noexcept final = default; | ||||||
| 
 | 
 | ||||||
|                 void set(const TId id, const TValue value) override final { |                 void set(const TId id, const TValue value) final { | ||||||
|                     m_vector.push_back(element_type(id, value)); |                     m_vector.push_back(element_type(id, value)); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
| @ -105,7 +105,7 @@ namespace osmium { | |||||||
|                     }); |                     }); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 size_t size() const override final { |                 size_t size() const final { | ||||||
|                     return m_vector.size(); |                     return m_vector.size(); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
| @ -113,16 +113,16 @@ namespace osmium { | |||||||
|                     return m_vector.size() * sizeof(element_type); |                     return m_vector.size() * sizeof(element_type); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 size_t used_memory() const override final { |                 size_t used_memory() const final { | ||||||
|                     return sizeof(element_type) * size(); |                     return sizeof(element_type) * size(); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void clear() override final { |                 void clear() final { | ||||||
|                     m_vector.clear(); |                     m_vector.clear(); | ||||||
|                     m_vector.shrink_to_fit(); |                     m_vector.shrink_to_fit(); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void sort() override final { |                 void sort() final { | ||||||
|                     std::sort(m_vector.begin(), m_vector.end()); |                     std::sort(m_vector.begin(), m_vector.end()); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
| @ -147,7 +147,7 @@ namespace osmium { | |||||||
|                     ); |                     ); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void dump_as_list(const int fd) override final { |                 void dump_as_list(const int fd) final { | ||||||
|                     osmium::io::detail::reliable_write(fd, reinterpret_cast<const char*>(m_vector.data()), byte_size()); |                     osmium::io::detail::reliable_write(fd, reinterpret_cast<const char*>(m_vector.data()), byte_size()); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -89,7 +89,7 @@ namespace osmium { | |||||||
|          * the full range, so the max value is a good "empty" value. |          * the full range, so the max value is a good "empty" value. | ||||||
|          */ |          */ | ||||||
|         template <> |         template <> | ||||||
|         inline OSMIUM_CONSTEXPR size_t empty_value<size_t>() { |         inline constexpr size_t empty_value<size_t>() { | ||||||
|             return std::numeric_limits<size_t>::max(); |             return std::numeric_limits<size_t>::max(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -84,7 +84,8 @@ namespace osmium { | |||||||
|             template <typename TId, typename TValue> |             template <typename TId, typename TValue> | ||||||
|             class Map { |             class Map { | ||||||
| 
 | 
 | ||||||
|                 static_assert(std::is_integral<TId>::value && std::is_unsigned<TId>::value, "TId template parameter for class Map must be unsigned integral type"); |                 static_assert(std::is_integral<TId>::value && std::is_unsigned<TId>::value, | ||||||
|  |                               "TId template parameter for class Map must be unsigned integral type"); | ||||||
| 
 | 
 | ||||||
|                 Map(const Map&) = delete; |                 Map(const Map&) = delete; | ||||||
|                 Map& operator=(const Map&) = delete; |                 Map& operator=(const Map&) = delete; | ||||||
| @ -104,7 +105,7 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|                 Map() = default; |                 Map() = default; | ||||||
| 
 | 
 | ||||||
|                 virtual ~Map() = default; |                 virtual ~Map() noexcept = default; | ||||||
| 
 | 
 | ||||||
|                 virtual void reserve(const size_t) { |                 virtual void reserve(const size_t) { | ||||||
|                     // default implementation is empty
 |                     // default implementation is empty
 | ||||||
| @ -147,10 +148,16 @@ namespace osmium { | |||||||
|                     // default implementation is empty
 |                     // default implementation is empty
 | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|  |                 // This function could usually be const in derived classes,
 | ||||||
|  |                 // but not always. It could, for instance, sort internal data.
 | ||||||
|  |                 // This is why it is not declared const here.
 | ||||||
|                 virtual void dump_as_list(const int /*fd*/) { |                 virtual void dump_as_list(const int /*fd*/) { | ||||||
|                     throw std::runtime_error("can't dump as list"); |                     throw std::runtime_error("can't dump as list"); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|  |                 // This function could usually be const in derived classes,
 | ||||||
|  |                 // but not always. It could, for instance, sort internal data.
 | ||||||
|  |                 // This is why it is not declared const here.
 | ||||||
|                 virtual void dump_as_array(const int /*fd*/) { |                 virtual void dump_as_array(const int /*fd*/) { | ||||||
|                     throw std::runtime_error("can't dump as array"); |                     throw std::runtime_error("can't dump as array"); | ||||||
|                 } |                 } | ||||||
| @ -252,12 +259,14 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
| #define OSMIUM_CONCATENATE_DETAIL_(x, y) x##y | #define OSMIUM_CONCATENATE_DETAIL_(x, y) x##y | ||||||
| #define OSMIUM_CONCATENATE_(x, y) OSMIUM_CONCATENATE_DETAIL_(x, y) | #define OSMIUM_CONCATENATE_(x, y) OSMIUM_CONCATENATE_DETAIL_(x, y) | ||||||
| #define OSMIUM_MAKE_UNIQUE_(x) OSMIUM_CONCATENATE_(x, __COUNTER__) |  | ||||||
| 
 | 
 | ||||||
| #define REGISTER_MAP(id, value, klass, name) \ | #define REGISTER_MAP(id, value, klass, name) \ | ||||||
| namespace { \ | namespace osmium { namespace index { namespace detail { \ | ||||||
|     const bool OSMIUM_MAKE_UNIQUE_(registered_index_map_##name) = osmium::index::register_map<id, value, klass>(#name); \ |     const bool OSMIUM_CONCATENATE_(registered_, name) = osmium::index::register_map<id, value, klass>(#name); \ | ||||||
| } |     inline bool OSMIUM_CONCATENATE_(get_registered_, name)() noexcept { \ | ||||||
|  |         return OSMIUM_CONCATENATE_(registered_, name); \ | ||||||
|  |     } \ | ||||||
|  | } } } | ||||||
| 
 | 
 | ||||||
|     } // namespace index
 |     } // namespace index
 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -56,25 +56,25 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|                 Dummy() = default; |                 Dummy() = default; | ||||||
| 
 | 
 | ||||||
|                 ~Dummy() override final = default; |                 ~Dummy() noexcept final = default; | ||||||
| 
 | 
 | ||||||
|                 void set(const TId, const TValue) override final { |                 void set(const TId, const TValue) final { | ||||||
|                     // intentionally left blank
 |                     // intentionally left blank
 | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 const TValue get(const TId id) const override final { |                 const TValue get(const TId id) const final { | ||||||
|                     not_found_error(id); |                     not_found_error(id); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 size_t size() const override final { |                 size_t size() const final { | ||||||
|                     return 0; |                     return 0; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 size_t used_memory() const override final { |                 size_t used_memory() const final { | ||||||
|                     return 0; |                     return 0; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void clear() override final { |                 void clear() final { | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|             }; // class Dummy
 |             }; // class Dummy
 | ||||||
|  | |||||||
| @ -71,36 +71,37 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|                 SparseMemMap() = default; |                 SparseMemMap() = default; | ||||||
| 
 | 
 | ||||||
|                 ~SparseMemMap() override final = default; |                 ~SparseMemMap() noexcept final = default; | ||||||
| 
 | 
 | ||||||
|                 void set(const TId id, const TValue value) override final { |                 void set(const TId id, const TValue value) final { | ||||||
|                     m_elements[id] = value; |                     m_elements[id] = value; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 const TValue get(const TId id) const override final { |                 const TValue get(const TId id) const final { | ||||||
|                     try { |                     auto it = m_elements.find(id); | ||||||
|                         return m_elements.at(id); |                     if (it == m_elements.end()) { | ||||||
|                     } catch (std::out_of_range&) { |  | ||||||
|                         not_found_error(id); |                         not_found_error(id); | ||||||
|                     } |                     } | ||||||
|  |                     return it->second; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 size_t size() const override final { |                 size_t size() const noexcept final { | ||||||
|                     return m_elements.size(); |                     return m_elements.size(); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 size_t used_memory() const override final { |                 size_t used_memory() const noexcept final { | ||||||
|                     return element_size * m_elements.size(); |                     return element_size * m_elements.size(); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void clear() override final { |                 void clear() final { | ||||||
|                     m_elements.clear(); |                     m_elements.clear(); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void dump_as_list(const int fd) override final { |                 void dump_as_list(const int fd) final { | ||||||
|                     typedef typename std::map<TId, TValue>::value_type t; |                     typedef typename std::map<TId, TValue>::value_type t; | ||||||
|                     std::vector<t> v; |                     std::vector<t> v; | ||||||
|                     std::copy(m_elements.begin(), m_elements.end(), std::back_inserter(v)); |                     v.reserve(m_elements.size()); | ||||||
|  |                     std::copy(m_elements.cbegin(), m_elements.cend(), std::back_inserter(v)); | ||||||
|                     osmium::io::detail::reliable_write(fd, reinterpret_cast<const char*>(v.data()), sizeof(t) * v.size()); |                     osmium::io::detail::reliable_write(fd, reinterpret_cast<const char*>(v.data()), sizeof(t) * v.size()); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -88,16 +88,16 @@ namespace osmium { | |||||||
|                     m_elements(grow_size) { |                     m_elements(grow_size) { | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 ~SparseMemTable() override final = default; |                 ~SparseMemTable() noexcept final = default; | ||||||
| 
 | 
 | ||||||
|                 void set(const TId id, const TValue value) override final { |                 void set(const TId id, const TValue value) final { | ||||||
|                     if (id >= m_elements.size()) { |                     if (id >= m_elements.size()) { | ||||||
|                         m_elements.resize(id + m_grow_size); |                         m_elements.resize(id + m_grow_size); | ||||||
|                     } |                     } | ||||||
|                     m_elements[id] = value; |                     m_elements[id] = value; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 const TValue get(const TId id) const override final { |                 const TValue get(const TId id) const final { | ||||||
|                     if (id >= m_elements.size()) { |                     if (id >= m_elements.size()) { | ||||||
|                         not_found_error(id); |                         not_found_error(id); | ||||||
|                     } |                     } | ||||||
| @ -107,22 +107,23 @@ namespace osmium { | |||||||
|                     return m_elements[id]; |                     return m_elements[id]; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 size_t size() const override final { |                 size_t size() const final { | ||||||
|                     return m_elements.size(); |                     return m_elements.size(); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 size_t used_memory() const override final { |                 size_t used_memory() const final { | ||||||
|                     // unused elements use 1 bit, used elements sizeof(TValue) bytes
 |                     // unused elements use 1 bit, used elements sizeof(TValue) bytes
 | ||||||
|                     // http://google-sparsehash.googlecode.com/svn/trunk/doc/sparsetable.html
 |                     // http://google-sparsehash.googlecode.com/svn/trunk/doc/sparsetable.html
 | ||||||
|                     return (m_elements.size() / 8) + (m_elements.num_nonempty() * sizeof(TValue)); |                     return (m_elements.size() / 8) + (m_elements.num_nonempty() * sizeof(TValue)); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void clear() override final { |                 void clear() final { | ||||||
|                     m_elements.clear(); |                     m_elements.clear(); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void dump_as_list(const int fd) override final { |                 void dump_as_list(const int fd) final { | ||||||
|                     std::vector<std::pair<TId, TValue>> v; |                     std::vector<std::pair<TId, TValue>> v; | ||||||
|  |                     v.reserve(m_elements.size()); | ||||||
|                     int n = 0; |                     int n = 0; | ||||||
|                     for (const TValue value : m_elements) { |                     for (const TValue value : m_elements) { | ||||||
|                         if (value != osmium::index::empty_value<TValue>()) { |                         if (value != osmium::index::empty_value<TValue>()) { | ||||||
|  | |||||||
| @ -118,7 +118,7 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|             }; // class Multimap
 |             }; // class Multimap
 | ||||||
| 
 | 
 | ||||||
|         } // namespace map
 |         } // namespace multimap
 | ||||||
| 
 | 
 | ||||||
|     } // namespace index
 |     } // namespace index
 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -62,16 +62,18 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|             public: |             public: | ||||||
| 
 | 
 | ||||||
|                 explicit HybridIterator(typename main_map_type::iterator begin_main, |                  HybridIterator(typename main_map_type::iterator begin_main, | ||||||
|                                typename main_map_type::iterator end_main, |                                 typename main_map_type::iterator end_main, | ||||||
|                                typename extra_map_type::iterator begin_extra, |                                 typename extra_map_type::iterator begin_extra, | ||||||
|                                typename extra_map_type::iterator end_extra) : |                                 typename extra_map_type::iterator end_extra) : | ||||||
|                     m_begin_main(begin_main), |                     m_begin_main(begin_main), | ||||||
|                     m_end_main(end_main), |                     m_end_main(end_main), | ||||||
|                     m_begin_extra(begin_extra), |                     m_begin_extra(begin_extra), | ||||||
|                     m_end_extra(end_extra) { |                     m_end_extra(end_extra) { | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|  |                 ~HybridIterator() noexcept = default; | ||||||
|  | 
 | ||||||
|                 HybridIterator& operator++() { |                 HybridIterator& operator++() { | ||||||
|                     if (m_begin_main == m_end_main) { |                     if (m_begin_main == m_end_main) { | ||||||
|                         ++m_begin_extra; |                         ++m_begin_extra; | ||||||
| @ -134,11 +136,13 @@ namespace osmium { | |||||||
|                     m_extra() { |                     m_extra() { | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 size_t size() const override final { |                 ~Hybrid() noexcept = default; | ||||||
|  | 
 | ||||||
|  |                 size_t size() const final { | ||||||
|                     return m_main.size() + m_extra.size(); |                     return m_main.size() + m_extra.size(); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 size_t used_memory() const override final { |                 size_t used_memory() const final { | ||||||
|                     return m_main.used_memory() + m_extra.used_memory(); |                     return m_main.used_memory() + m_extra.used_memory(); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
| @ -150,7 +154,7 @@ namespace osmium { | |||||||
|                     m_main.set(id, value); |                     m_main.set(id, value); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void set(const TId id, const TValue value) override final { |                 void set(const TId id, const TValue value) final { | ||||||
|                     m_extra.set(id, value); |                     m_extra.set(id, value); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
| @ -175,17 +179,17 @@ namespace osmium { | |||||||
|                     m_main.sort(); |                     m_main.sort(); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void dump_as_list(const int fd) override final { |                 void dump_as_list(const int fd) final { | ||||||
|                     consolidate(); |                     consolidate(); | ||||||
|                     m_main.dump_as_list(fd); |                     m_main.dump_as_list(fd); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void clear() override final { |                 void clear() final { | ||||||
|                     m_main.clear(); |                     m_main.clear(); | ||||||
|                     m_extra.clear(); |                     m_extra.clear(); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void sort() override final { |                 void sort() final { | ||||||
|                     m_main.sort(); |                     m_main.sort(); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -78,13 +78,13 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|                 SparseMemMultimap() = default; |                 SparseMemMultimap() = default; | ||||||
| 
 | 
 | ||||||
|                 ~SparseMemMultimap() noexcept override final = default; |                 ~SparseMemMultimap() noexcept final = default; | ||||||
| 
 | 
 | ||||||
|                 void unsorted_set(const TId id, const TValue value) { |                 void unsorted_set(const TId id, const TValue value) { | ||||||
|                     m_elements.emplace(id, value); |                     m_elements.emplace(id, value); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void set(const TId id, const TValue value) override final { |                 void set(const TId id, const TValue value) final { | ||||||
|                     m_elements.emplace(id, value); |                     m_elements.emplace(id, value); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
| @ -114,15 +114,15 @@ namespace osmium { | |||||||
|                     return m_elements.end(); |                     return m_elements.end(); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 size_t size() const override final { |                 size_t size() const final { | ||||||
|                     return m_elements.size(); |                     return m_elements.size(); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 size_t used_memory() const override final { |                 size_t used_memory() const final { | ||||||
|                     return element_size * m_elements.size(); |                     return element_size * m_elements.size(); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void clear() override final { |                 void clear() final { | ||||||
|                     m_elements.clear(); |                     m_elements.clear(); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
| @ -130,12 +130,12 @@ namespace osmium { | |||||||
|                     // intentionally left blank
 |                     // intentionally left blank
 | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void dump_as_list(const int fd) override final { |                 void dump_as_list(const int fd) final { | ||||||
|                     std::vector<element_type> v; |                     std::vector<element_type> v; | ||||||
|  |                     v.reserve(m_elements.size()); | ||||||
|                     for (const auto& element : m_elements) { |                     for (const auto& element : m_elements) { | ||||||
|                         v.emplace_back(element.first, element.second); |                         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()); |                     std::sort(v.begin(), v.end()); | ||||||
|                     osmium::io::detail::reliable_write(fd, reinterpret_cast<const char*>(v.data()), sizeof(element_type) * v.size()); |                     osmium::io::detail::reliable_write(fd, reinterpret_cast<const char*>(v.data()), sizeof(element_type) * v.size()); | ||||||
|                 } |                 } | ||||||
|  | |||||||
| @ -47,5 +47,6 @@ DEALINGS IN THE SOFTWARE. | |||||||
| 
 | 
 | ||||||
| #include <osmium/io/pbf_input.hpp> // IWYU pragma: export
 | #include <osmium/io/pbf_input.hpp> // IWYU pragma: export
 | ||||||
| #include <osmium/io/xml_input.hpp> // IWYU pragma: export
 | #include <osmium/io/xml_input.hpp> // IWYU pragma: export
 | ||||||
|  | #include <osmium/io/o5m_input.hpp> // IWYU pragma: export
 | ||||||
| 
 | 
 | ||||||
| #endif // OSMIUM_IO_ANY_INPUT_HPP
 | #endif // OSMIUM_IO_ANY_INPUT_HPP
 | ||||||
|  | |||||||
| @ -55,7 +55,9 @@ DEALINGS IN THE SOFTWARE. | |||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #include <osmium/io/compression.hpp> | #include <osmium/io/compression.hpp> | ||||||
|  | #include <osmium/io/error.hpp> | ||||||
| #include <osmium/io/file_compression.hpp> | #include <osmium/io/file_compression.hpp> | ||||||
|  | #include <osmium/io/writer_options.hpp> | ||||||
| #include <osmium/util/cast.hpp> | #include <osmium/util/cast.hpp> | ||||||
| #include <osmium/util/compatibility.hpp> | #include <osmium/util/compatibility.hpp> | ||||||
| 
 | 
 | ||||||
| @ -65,13 +67,13 @@ namespace osmium { | |||||||
|      * Exception thrown when there are problems compressing or |      * Exception thrown when there are problems compressing or | ||||||
|      * decompressing bzip2 files. |      * decompressing bzip2 files. | ||||||
|      */ |      */ | ||||||
|     struct bzip2_error : public std::runtime_error { |     struct bzip2_error : public io_error { | ||||||
| 
 | 
 | ||||||
|         int bzip2_error_code; |         int bzip2_error_code; | ||||||
|         int system_errno; |         int system_errno; | ||||||
| 
 | 
 | ||||||
|         bzip2_error(const std::string& what, int error_code) : |         bzip2_error(const std::string& what, int error_code) : | ||||||
|             std::runtime_error(what), |             io_error(what), | ||||||
|             bzip2_error_code(error_code), |             bzip2_error_code(error_code), | ||||||
|             system_errno(error_code == BZ_IO_ERROR ? errno : 0) { |             system_errno(error_code == BZ_IO_ERROR ? errno : 0) { | ||||||
|         } |         } | ||||||
| @ -105,8 +107,8 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|         public: |         public: | ||||||
| 
 | 
 | ||||||
|             explicit Bzip2Compressor(int fd) : |             explicit Bzip2Compressor(int fd, fsync sync) : | ||||||
|                 Compressor(), |                 Compressor(sync), | ||||||
|                 m_file(fdopen(dup(fd), "wb")), |                 m_file(fdopen(dup(fd), "wb")), | ||||||
|                 m_bzerror(BZ_OK), |                 m_bzerror(BZ_OK), | ||||||
|                 m_bzfile(::BZ2_bzWriteOpen(&m_bzerror, m_file, 6, 0, 0)) { |                 m_bzfile(::BZ2_bzWriteOpen(&m_bzerror, m_file, 6, 0, 0)) { | ||||||
| @ -115,11 +117,15 @@ namespace osmium { | |||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             ~Bzip2Compressor() override final { |             ~Bzip2Compressor() noexcept final { | ||||||
|                 close(); |                 try { | ||||||
|  |                     close(); | ||||||
|  |                 } catch (...) { | ||||||
|  |                     // Ignore any exceptions because destructor must not throw.
 | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             void write(const std::string& data) override final { |             void write(const std::string& data) final { | ||||||
|                 int error; |                 int error; | ||||||
|                 ::BZ2_bzWrite(&error, m_bzfile, const_cast<char*>(data.data()), static_cast_with_assert<int>(data.size())); |                 ::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) { |                 if (error != BZ_OK && error != BZ_STREAM_END) { | ||||||
| @ -127,13 +133,18 @@ namespace osmium { | |||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             void close() override final { |             void close() final { | ||||||
|                 if (m_bzfile) { |                 if (m_bzfile) { | ||||||
|                     int error; |                     int error; | ||||||
|                     ::BZ2_bzWriteClose(&error, m_bzfile, 0, nullptr, nullptr); |                     ::BZ2_bzWriteClose(&error, m_bzfile, 0, nullptr, nullptr); | ||||||
|                     m_bzfile = nullptr; |                     m_bzfile = nullptr; | ||||||
|                     if (m_file) { |                     if (m_file) { | ||||||
|                         fclose(m_file); |                         if (do_fsync()) { | ||||||
|  |                             osmium::io::detail::reliable_fsync(::fileno(m_file)); | ||||||
|  |                         } | ||||||
|  |                         if (fclose(m_file) != 0) { | ||||||
|  |                             throw std::system_error(errno, std::system_category(), "Close failed"); | ||||||
|  |                         } | ||||||
|                     } |                     } | ||||||
|                     if (error != BZ_OK) { |                     if (error != BZ_OK) { | ||||||
|                         detail::throw_bzip2_error(m_bzfile, "write close failed", error); |                         detail::throw_bzip2_error(m_bzfile, "write close failed", error); | ||||||
| @ -152,7 +163,7 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|         public: |         public: | ||||||
| 
 | 
 | ||||||
|             Bzip2Decompressor(int fd) : |             explicit Bzip2Decompressor(int fd) : | ||||||
|                 Decompressor(), |                 Decompressor(), | ||||||
|                 m_file(fdopen(dup(fd), "rb")), |                 m_file(fdopen(dup(fd), "rb")), | ||||||
|                 m_bzerror(BZ_OK), |                 m_bzerror(BZ_OK), | ||||||
| @ -162,11 +173,15 @@ namespace osmium { | |||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             ~Bzip2Decompressor() override final { |             ~Bzip2Decompressor() noexcept final { | ||||||
|                 close(); |                 try { | ||||||
|  |                     close(); | ||||||
|  |                 } catch (...) { | ||||||
|  |                     // Ignore any exceptions because destructor must not throw.
 | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             std::string read() override final { |             std::string read() final { | ||||||
|                 std::string buffer; |                 std::string buffer; | ||||||
| 
 | 
 | ||||||
|                 if (!m_stream_end) { |                 if (!m_stream_end) { | ||||||
| @ -203,13 +218,15 @@ namespace osmium { | |||||||
|                 return buffer; |                 return buffer; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             void close() override final { |             void close() final { | ||||||
|                 if (m_bzfile) { |                 if (m_bzfile) { | ||||||
|                     int error; |                     int error; | ||||||
|                     ::BZ2_bzReadClose(&error, m_bzfile); |                     ::BZ2_bzReadClose(&error, m_bzfile); | ||||||
|                     m_bzfile = nullptr; |                     m_bzfile = nullptr; | ||||||
|                     if (m_file) { |                     if (m_file) { | ||||||
|                         fclose(m_file); |                         if (fclose(m_file) != 0) { | ||||||
|  |                             throw std::system_error(errno, std::system_category(), "Close failed"); | ||||||
|  |                         } | ||||||
|                     } |                     } | ||||||
|                     if (error != BZ_OK) { |                     if (error != BZ_OK) { | ||||||
|                         detail::throw_bzip2_error(m_bzfile, "read close failed", error); |                         detail::throw_bzip2_error(m_bzfile, "read close failed", error); | ||||||
| @ -240,11 +257,15 @@ namespace osmium { | |||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             ~Bzip2BufferDecompressor() override final { |             ~Bzip2BufferDecompressor() noexcept final { | ||||||
|                 BZ2_bzDecompressEnd(&m_bzstream); |                 try { | ||||||
|  |                     close(); | ||||||
|  |                 } catch (...) { | ||||||
|  |                     // Ignore any exceptions because destructor must not throw.
 | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             std::string read() override final { |             std::string read() final { | ||||||
|                 std::string output; |                 std::string output; | ||||||
| 
 | 
 | ||||||
|                 if (m_buffer) { |                 if (m_buffer) { | ||||||
| @ -270,22 +291,28 @@ namespace osmium { | |||||||
|                 return output; |                 return output; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  |             void close() final { | ||||||
|  |                 BZ2_bzDecompressEnd(&m_bzstream); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|         }; // class Bzip2BufferDecompressor
 |         }; // class Bzip2BufferDecompressor
 | ||||||
| 
 | 
 | ||||||
|         namespace { |         namespace detail { | ||||||
| 
 | 
 | ||||||
| // we want the register_compression() function to run, setting the variable
 |             // we want the register_compression() function to run, setting
 | ||||||
| // is only a side-effect, it will never be used
 |             // the variable is only a side-effect, it will never be used
 | ||||||
| #pragma GCC diagnostic push |  | ||||||
| #pragma GCC diagnostic ignored "-Wunused-variable" |  | ||||||
|             const bool registered_bzip2_compression = osmium::io::CompressionFactory::instance().register_compression(osmium::io::file_compression::bzip2, |             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, fsync sync) { return new osmium::io::Bzip2Compressor(fd, sync); }, | ||||||
|                 [](int fd) { return new osmium::io::Bzip2Decompressor(fd); }, |                 [](int fd) { return new osmium::io::Bzip2Decompressor(fd); }, | ||||||
|                 [](const char* buffer, size_t size) { return new osmium::io::Bzip2BufferDecompressor(buffer, size); } |                 [](const char* buffer, size_t size) { return new osmium::io::Bzip2BufferDecompressor(buffer, size); } | ||||||
|             ); |             ); | ||||||
| #pragma GCC diagnostic pop |  | ||||||
| 
 | 
 | ||||||
|         } // anonymous namespace
 |             // dummy function to silence the unused variable warning from above
 | ||||||
|  |             inline bool get_registered_bzip2_compression() noexcept { | ||||||
|  |                 return registered_bzip2_compression; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |         } // namespace detail
 | ||||||
| 
 | 
 | ||||||
|     } // namespace io
 |     } // namespace io
 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -40,6 +40,7 @@ DEALINGS IN THE SOFTWARE. | |||||||
| #include <stdexcept> | #include <stdexcept> | ||||||
| #include <string> | #include <string> | ||||||
| #include <system_error> | #include <system_error> | ||||||
|  | #include <tuple> | ||||||
| #include <utility> | #include <utility> | ||||||
| 
 | 
 | ||||||
| #ifndef _MSC_VER | #ifndef _MSC_VER | ||||||
| @ -49,7 +50,9 @@ DEALINGS IN THE SOFTWARE. | |||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #include <osmium/io/detail/read_write.hpp> | #include <osmium/io/detail/read_write.hpp> | ||||||
|  | #include <osmium/io/error.hpp> | ||||||
| #include <osmium/io/file_compression.hpp> | #include <osmium/io/file_compression.hpp> | ||||||
|  | #include <osmium/io/writer_options.hpp> | ||||||
| #include <osmium/util/compatibility.hpp> | #include <osmium/util/compatibility.hpp> | ||||||
| 
 | 
 | ||||||
| namespace osmium { | namespace osmium { | ||||||
| @ -58,11 +61,21 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|         class Compressor { |         class Compressor { | ||||||
| 
 | 
 | ||||||
|  |             fsync m_fsync; | ||||||
|  | 
 | ||||||
|  |         protected: | ||||||
|  | 
 | ||||||
|  |             bool do_fsync() const { | ||||||
|  |                 return m_fsync == fsync::yes; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|         public: |         public: | ||||||
| 
 | 
 | ||||||
|             Compressor() = default; |             explicit Compressor(fsync sync) : | ||||||
|  |                 m_fsync(sync) { | ||||||
|  |             } | ||||||
| 
 | 
 | ||||||
|             virtual ~Compressor() { |             virtual ~Compressor() noexcept { | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             virtual void write(const std::string& data) = 0; |             virtual void write(const std::string& data) = 0; | ||||||
| @ -85,13 +98,12 @@ namespace osmium { | |||||||
|             Decompressor(Decompressor&&) = delete; |             Decompressor(Decompressor&&) = delete; | ||||||
|             Decompressor& operator=(Decompressor&&) = delete; |             Decompressor& operator=(Decompressor&&) = delete; | ||||||
| 
 | 
 | ||||||
|             virtual ~Decompressor() { |             virtual ~Decompressor() noexcept { | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             virtual std::string read() = 0; |             virtual std::string read() = 0; | ||||||
| 
 | 
 | ||||||
|             virtual void close() { |             virtual void close() = 0; | ||||||
|             } |  | ||||||
| 
 | 
 | ||||||
|         }; // class Decompressor
 |         }; // class Decompressor
 | ||||||
| 
 | 
 | ||||||
| @ -106,13 +118,16 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|         public: |         public: | ||||||
| 
 | 
 | ||||||
|             typedef std::function<osmium::io::Compressor*(int)> create_compressor_type; |             typedef std::function<osmium::io::Compressor*(int, fsync)> create_compressor_type; | ||||||
|             typedef std::function<osmium::io::Decompressor*(int)> create_decompressor_type_fd; |             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; |             typedef std::function<osmium::io::Decompressor*(const char*, size_t)> create_decompressor_type_buffer; | ||||||
| 
 | 
 | ||||||
|         private: |         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; |             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; |             compression_map_type m_callbacks; | ||||||
| 
 | 
 | ||||||
| @ -128,7 +143,7 @@ namespace osmium { | |||||||
|                 std::string error_message {"Support for compression '"}; |                 std::string error_message {"Support for compression '"}; | ||||||
|                 error_message += as_string(compression); |                 error_message += as_string(compression); | ||||||
|                 error_message += "' not compiled into this binary."; |                 error_message += "' not compiled into this binary."; | ||||||
|                 throw std::runtime_error(error_message); |                 throw unsupported_file_format_error(error_message); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|         public: |         public: | ||||||
| @ -144,15 +159,20 @@ namespace osmium { | |||||||
|                 create_decompressor_type_fd create_decompressor_fd, |                 create_decompressor_type_fd create_decompressor_fd, | ||||||
|                 create_decompressor_type_buffer create_decompressor_buffer) { |                 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)); |                 compression_map_type::value_type cc(compression, | ||||||
|  |                                                     std::make_tuple(create_compressor, | ||||||
|  |                                                                     create_decompressor_fd, | ||||||
|  |                                                                     create_decompressor_buffer)); | ||||||
|  | 
 | ||||||
|                 return m_callbacks.insert(cc).second; |                 return m_callbacks.insert(cc).second; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             std::unique_ptr<osmium::io::Compressor> create_compressor(osmium::io::file_compression compression, int fd) { |             template <typename... TArgs> | ||||||
|  |             std::unique_ptr<osmium::io::Compressor> create_compressor(osmium::io::file_compression compression, TArgs&&... args) { | ||||||
|                 auto it = m_callbacks.find(compression); |                 auto it = m_callbacks.find(compression); | ||||||
| 
 | 
 | ||||||
|                 if (it != m_callbacks.end()) { |                 if (it != m_callbacks.end()) { | ||||||
|                     return std::unique_ptr<osmium::io::Compressor>(std::get<0>(it->second)(fd)); |                     return std::unique_ptr<osmium::io::Compressor>(std::get<0>(it->second)(std::forward<TArgs>(args)...)); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 error(compression); |                 error(compression); | ||||||
| @ -186,23 +206,31 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|         public: |         public: | ||||||
| 
 | 
 | ||||||
|             NoCompressor(int fd) : |             NoCompressor(int fd, fsync sync) : | ||||||
|                 Compressor(), |                 Compressor(sync), | ||||||
|                 m_fd(fd) { |                 m_fd(fd) { | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             ~NoCompressor() override final { |             ~NoCompressor() noexcept final { | ||||||
|                 close(); |                 try { | ||||||
|  |                     close(); | ||||||
|  |                 } catch (...) { | ||||||
|  |                     // Ignore any exceptions because destructor must not throw.
 | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             void write(const std::string& data) override final { |             void write(const std::string& data) final { | ||||||
|                 osmium::io::detail::reliable_write(m_fd, data.data(), data.size()); |                 osmium::io::detail::reliable_write(m_fd, data.data(), data.size()); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             void close() override final { |             void close() final { | ||||||
|                 if (m_fd >= 0) { |                 if (m_fd >= 0) { | ||||||
|                     ::close(m_fd); |                     int fd = m_fd; | ||||||
|                     m_fd = -1; |                     m_fd = -1; | ||||||
|  |                     if (do_fsync()) { | ||||||
|  |                         osmium::io::detail::reliable_fsync(fd); | ||||||
|  |                     } | ||||||
|  |                     osmium::io::detail::reliable_close(fd); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
| @ -216,7 +244,7 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|         public: |         public: | ||||||
| 
 | 
 | ||||||
|             NoDecompressor(int fd) : |             explicit NoDecompressor(int fd) : | ||||||
|                 Decompressor(), |                 Decompressor(), | ||||||
|                 m_fd(fd), |                 m_fd(fd), | ||||||
|                 m_buffer(nullptr), |                 m_buffer(nullptr), | ||||||
| @ -230,11 +258,15 @@ namespace osmium { | |||||||
|                 m_buffer_size(size) { |                 m_buffer_size(size) { | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             ~NoDecompressor() override final { |             ~NoDecompressor() noexcept final { | ||||||
|                 close(); |                 try { | ||||||
|  |                     close(); | ||||||
|  |                 } catch (...) { | ||||||
|  |                     // Ignore any exceptions because destructor must not throw.
 | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             std::string read() override final { |             std::string read() final { | ||||||
|                 std::string buffer; |                 std::string buffer; | ||||||
| 
 | 
 | ||||||
|                 if (m_buffer) { |                 if (m_buffer) { | ||||||
| @ -249,35 +281,38 @@ namespace osmium { | |||||||
|                     if (nread < 0) { |                     if (nread < 0) { | ||||||
|                         throw std::system_error(errno, std::system_category(), "Read failed"); |                         throw std::system_error(errno, std::system_category(), "Read failed"); | ||||||
|                     } |                     } | ||||||
|                     buffer.resize(nread); |                     buffer.resize(std::string::size_type(nread)); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 return buffer; |                 return buffer; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             void close() override final { |             void close() final { | ||||||
|                 if (m_fd >= 0) { |                 if (m_fd >= 0) { | ||||||
|                     ::close(m_fd); |                     int fd = m_fd; | ||||||
|                     m_fd = -1; |                     m_fd = -1; | ||||||
|  |                     osmium::io::detail::reliable_close(fd); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|         }; // class NoDecompressor
 |         }; // class NoDecompressor
 | ||||||
| 
 | 
 | ||||||
|         namespace { |         namespace detail { | ||||||
| 
 | 
 | ||||||
| // we want the register_compression() function to run, setting the variable
 |             // we want the register_compression() function to run, setting
 | ||||||
| // is only a side-effect, it will never be used
 |             // the variable is only a side-effect, it will never be used
 | ||||||
| #pragma GCC diagnostic push |  | ||||||
| #pragma GCC diagnostic ignored "-Wunused-variable" |  | ||||||
|             const bool registered_no_compression = osmium::io::CompressionFactory::instance().register_compression(osmium::io::file_compression::none, |             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, fsync sync) { return new osmium::io::NoCompressor(fd, sync); }, | ||||||
|                 [](int fd) { return new osmium::io::NoDecompressor(fd); }, |                 [](int fd) { return new osmium::io::NoDecompressor(fd); }, | ||||||
|                 [](const char* buffer, size_t size) { return new osmium::io::NoDecompressor(buffer, size); } |                 [](const char* buffer, size_t size) { return new osmium::io::NoDecompressor(buffer, size); } | ||||||
|             ); |             ); | ||||||
| #pragma GCC diagnostic pop |  | ||||||
| 
 | 
 | ||||||
|         } // anonymous namespace
 |             // dummy function to silence the unused variable warning from above
 | ||||||
|  |             inline bool get_registered_no_compression() noexcept { | ||||||
|  |                 return registered_no_compression; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |         } // namespace detail
 | ||||||
| 
 | 
 | ||||||
|     } // namespace io
 |     } // namespace io
 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -33,7 +33,6 @@ DEALINGS IN THE SOFTWARE. | |||||||
| 
 | 
 | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| #include <chrono> |  | ||||||
| #include <cinttypes> | #include <cinttypes> | ||||||
| #include <cstddef> | #include <cstddef> | ||||||
| #include <cstdint> | #include <cstdint> | ||||||
| @ -41,14 +40,10 @@ DEALINGS IN THE SOFTWARE. | |||||||
| #include <future> | #include <future> | ||||||
| #include <iterator> | #include <iterator> | ||||||
| #include <memory> | #include <memory> | ||||||
| #include <ratio> |  | ||||||
| #include <string> | #include <string> | ||||||
| #include <thread> | #include <thread> | ||||||
| #include <utility> | #include <utility> | ||||||
| 
 | 
 | ||||||
| #include <utf8.h> |  | ||||||
| 
 |  | ||||||
| #include <osmium/handler.hpp> |  | ||||||
| #include <osmium/io/detail/output_format.hpp> | #include <osmium/io/detail/output_format.hpp> | ||||||
| #include <osmium/io/file_format.hpp> | #include <osmium/io/file_format.hpp> | ||||||
| #include <osmium/memory/buffer.hpp> | #include <osmium/memory/buffer.hpp> | ||||||
| @ -87,65 +82,32 @@ namespace osmium { | |||||||
|             constexpr const char* color_white   = "\x1b[37m"; |             constexpr const char* color_white   = "\x1b[37m"; | ||||||
|             constexpr const char* color_reset   = "\x1b[0m"; |             constexpr const char* color_reset   = "\x1b[0m"; | ||||||
| 
 | 
 | ||||||
|  |             struct debug_output_options { | ||||||
|  | 
 | ||||||
|  |                 /// Should metadata of objects be added?
 | ||||||
|  |                 bool add_metadata; | ||||||
|  | 
 | ||||||
|  |                 /// Output with ANSI colors?
 | ||||||
|  |                 bool use_color; | ||||||
|  | 
 | ||||||
|  |             }; | ||||||
|  | 
 | ||||||
|             /**
 |             /**
 | ||||||
|              * Writes out one buffer with OSM data in Debug format. |              * Writes out one buffer with OSM data in Debug format. | ||||||
|              */ |              */ | ||||||
|             class DebugOutputBlock : public osmium::handler::Handler { |             class DebugOutputBlock : public OutputBlock { | ||||||
| 
 | 
 | ||||||
|                 static constexpr size_t tmp_buffer_size = 50; |                 debug_output_options m_options; | ||||||
| 
 | 
 | ||||||
|                 std::shared_ptr<osmium::memory::Buffer> m_input_buffer; |                 const char* m_utf8_prefix = ""; | ||||||
| 
 |                 const char* m_utf8_suffix = ""; | ||||||
|                 std::shared_ptr<std::string> m_out; |  | ||||||
| 
 |  | ||||||
|                 char m_tmp_buffer[tmp_buffer_size+1]; |  | ||||||
| 
 |  | ||||||
|                 bool m_add_metadata; |  | ||||||
|                 bool m_use_color; |  | ||||||
| 
 |  | ||||||
|                 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 char* data) { |                 void append_encoded_string(const char* data) { | ||||||
|                     const char* end = data + std::strlen(data); |                     append_debug_encoded_string(*m_out, data, m_utf8_prefix, m_utf8_suffix); | ||||||
| 
 |  | ||||||
|                     while (data != end) { |  | ||||||
|                         const char* last = data; |  | ||||||
|                         uint32_t c = utf8::next(data, end); |  | ||||||
| 
 |  | ||||||
|                         // 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
 |  | ||||||
|                         // non-printing characters.
 |  | ||||||
|                         if ((0x0020 <= c && c <= 0x0021) || |  | ||||||
|                             (0x0023 <= c && c <= 0x003b) || |  | ||||||
|                             (0x003d == c) || |  | ||||||
|                             (0x003f <= c && c <= 0x007e) || |  | ||||||
|                             (0x00a1 <= c && c <= 0x00ac) || |  | ||||||
|                             (0x00ae <= c && c <= 0x05ff)) { |  | ||||||
|                             m_out->append(last, data); |  | ||||||
|                         } else { |  | ||||||
|                             write_color(color_red); |  | ||||||
|                             output_formatted("<U+%04X>", c); |  | ||||||
|                             write_color(color_blue); |  | ||||||
|                         } |  | ||||||
|                     } |  | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void write_color(const char* color) { |                 void write_color(const char* color) { | ||||||
|                     if (m_use_color) { |                     if (m_options.use_color) { | ||||||
|                         *m_out += color; |                         *m_out += color; | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
| @ -177,15 +139,38 @@ namespace osmium { | |||||||
|                     *m_out += ": "; |                     *m_out += ": "; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|  |                 void write_comment_field(const char* name) { | ||||||
|  |                     write_color(color_cyan); | ||||||
|  |                     *m_out += name; | ||||||
|  |                     write_color(color_reset); | ||||||
|  |                     *m_out += ": "; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 void write_counter(int width, int n) { | ||||||
|  |                     write_color(color_white); | ||||||
|  |                     output_formatted("    %0*d: ", width, n++); | ||||||
|  |                     write_color(color_reset); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|                 void write_error(const char* msg) { |                 void write_error(const char* msg) { | ||||||
|                     write_color(color_red); |                     write_color(color_red); | ||||||
|                     *m_out += msg; |                     *m_out += msg; | ||||||
|                     write_color(color_reset); |                     write_color(color_reset); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|  |                 void write_timestamp(const osmium::Timestamp& timestamp) { | ||||||
|  |                     if (timestamp.valid()) { | ||||||
|  |                         *m_out += timestamp.to_iso(); | ||||||
|  |                         output_formatted(" (%d)", timestamp.seconds_since_epoch()); | ||||||
|  |                     } else { | ||||||
|  |                         write_error("NOT SET"); | ||||||
|  |                     } | ||||||
|  |                     *m_out += '\n'; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|                 void write_meta(const osmium::OSMObject& object) { |                 void write_meta(const osmium::OSMObject& object) { | ||||||
|                     output_formatted("%" PRId64 "\n", object.id()); |                     output_formatted("%" PRId64 "\n", object.id()); | ||||||
|                     if (m_add_metadata) { |                     if (m_options.add_metadata) { | ||||||
|                         write_fieldname("version"); |                         write_fieldname("version"); | ||||||
|                         output_formatted("  %d", object.version()); |                         output_formatted("  %d", object.version()); | ||||||
|                         if (object.visible()) { |                         if (object.visible()) { | ||||||
| @ -196,8 +181,7 @@ namespace osmium { | |||||||
|                         write_fieldname("changeset"); |                         write_fieldname("changeset"); | ||||||
|                         output_formatted("%d\n", object.changeset()); |                         output_formatted("%d\n", object.changeset()); | ||||||
|                         write_fieldname("timestamp"); |                         write_fieldname("timestamp"); | ||||||
|                         *m_out += object.timestamp().to_iso(); |                         write_timestamp(object.timestamp()); | ||||||
|                         output_formatted(" (%d)\n", object.timestamp()); |  | ||||||
|                         write_fieldname("user"); |                         write_fieldname("user"); | ||||||
|                         output_formatted("     %d ", object.uid()); |                         output_formatted("     %d ", object.uid()); | ||||||
|                         write_string(object.user()); |                         write_string(object.user()); | ||||||
| @ -211,14 +195,14 @@ namespace osmium { | |||||||
|                         *m_out += padding; |                         *m_out += padding; | ||||||
|                         output_formatted("     %d\n", tags.size()); |                         output_formatted("     %d\n", tags.size()); | ||||||
| 
 | 
 | ||||||
|                         osmium::max_op<int> max; |                         osmium::max_op<size_t> max; | ||||||
|                         for (const auto& tag : tags) { |                         for (const auto& tag : tags) { | ||||||
|                             max.update(std::strlen(tag.key())); |                             max.update(std::strlen(tag.key())); | ||||||
|                         } |                         } | ||||||
|                         for (const auto& tag : tags) { |                         for (const auto& tag : tags) { | ||||||
|                             *m_out += "    "; |                             *m_out += "    "; | ||||||
|                             write_string(tag.key()); |                             write_string(tag.key()); | ||||||
|                             int spacing = max() - std::strlen(tag.key()); |                             auto spacing = max() - std::strlen(tag.key()); | ||||||
|                             while (spacing--) { |                             while (spacing--) { | ||||||
|                                 *m_out += " "; |                                 *m_out += " "; | ||||||
|                             } |                             } | ||||||
| @ -255,12 +239,11 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|             public: |             public: | ||||||
| 
 | 
 | ||||||
|                 explicit DebugOutputBlock(osmium::memory::Buffer&& buffer, bool add_metadata, bool use_color) : |                 DebugOutputBlock(osmium::memory::Buffer&& buffer, const debug_output_options& options) : | ||||||
|                     m_input_buffer(std::make_shared<osmium::memory::Buffer>(std::move(buffer))), |                     OutputBlock(std::move(buffer)), | ||||||
|                     m_out(std::make_shared<std::string>()), |                     m_options(options), | ||||||
|                     m_tmp_buffer(), |                     m_utf8_prefix(options.use_color ? color_red  : ""), | ||||||
|                     m_add_metadata(add_metadata), |                     m_utf8_suffix(options.use_color ? color_blue : "") { | ||||||
|                     m_use_color(use_color) { |  | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 DebugOutputBlock(const DebugOutputBlock&) = default; |                 DebugOutputBlock(const DebugOutputBlock&) = default; | ||||||
| @ -269,13 +252,15 @@ namespace osmium { | |||||||
|                 DebugOutputBlock(DebugOutputBlock&&) = default; |                 DebugOutputBlock(DebugOutputBlock&&) = default; | ||||||
|                 DebugOutputBlock& operator=(DebugOutputBlock&&) = default; |                 DebugOutputBlock& operator=(DebugOutputBlock&&) = default; | ||||||
| 
 | 
 | ||||||
|                 ~DebugOutputBlock() = default; |                 ~DebugOutputBlock() noexcept = default; | ||||||
| 
 | 
 | ||||||
|                 std::string operator()() { |                 std::string operator()() { | ||||||
|                     osmium::apply(m_input_buffer->cbegin(), m_input_buffer->cend(), *this); |                     osmium::apply(m_input_buffer->cbegin(), m_input_buffer->cend(), *this); | ||||||
| 
 | 
 | ||||||
|                     std::string out; |                     std::string out; | ||||||
|                     std::swap(out, *m_out); |                     using std::swap; | ||||||
|  |                     swap(out, *m_out); | ||||||
|  | 
 | ||||||
|                     return out; |                     return out; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
| @ -313,7 +298,8 @@ namespace osmium { | |||||||
|                     int width = int(log10(way.nodes().size())) + 1; |                     int width = int(log10(way.nodes().size())) + 1; | ||||||
|                     int n = 0; |                     int n = 0; | ||||||
|                     for (const auto& node_ref : way.nodes()) { |                     for (const auto& node_ref : way.nodes()) { | ||||||
|                         output_formatted("    %0*d: %10" PRId64, width, n++, node_ref.ref()); |                         write_counter(width, n++); | ||||||
|  |                         output_formatted("%10" PRId64, node_ref.ref()); | ||||||
|                         if (node_ref.location().valid()) { |                         if (node_ref.location().valid()) { | ||||||
|                             output_formatted(" (%.7f,%.7f)", node_ref.location().lon_without_check(), node_ref.location().lat_without_check()); |                             output_formatted(" (%.7f,%.7f)", node_ref.location().lon_without_check(), node_ref.location().lat_without_check()); | ||||||
|                         } |                         } | ||||||
| @ -335,7 +321,7 @@ namespace osmium { | |||||||
|                     int width = int(log10(relation.members().size())) + 1; |                     int width = int(log10(relation.members().size())) + 1; | ||||||
|                     int n = 0; |                     int n = 0; | ||||||
|                     for (const auto& member : relation.members()) { |                     for (const auto& member : relation.members()) { | ||||||
|                         output_formatted("    %0*d: ", width, n++); |                         write_counter(width, n++); | ||||||
|                         *m_out += short_typename[item_type_to_nwr_index(member.type())]; |                         *m_out += short_typename[item_type_to_nwr_index(member.type())]; | ||||||
|                         output_formatted(" %10" PRId64 " ", member.ref()); |                         output_formatted(" %10" PRId64 " ", member.ref()); | ||||||
|                         write_string(member.role()); |                         write_string(member.role()); | ||||||
| @ -348,24 +334,26 @@ namespace osmium { | |||||||
|                 void changeset(const osmium::Changeset& changeset) { |                 void changeset(const osmium::Changeset& changeset) { | ||||||
|                     write_object_type("changeset"); |                     write_object_type("changeset"); | ||||||
|                     output_formatted("%d\n", changeset.id()); |                     output_formatted("%d\n", changeset.id()); | ||||||
|  | 
 | ||||||
|                     write_fieldname("num changes"); |                     write_fieldname("num changes"); | ||||||
|                     output_formatted("%d", changeset.num_changes()); |                     output_formatted("%d", changeset.num_changes()); | ||||||
|                     if (changeset.num_changes() == 0) { |                     if (changeset.num_changes() == 0) { | ||||||
|                         write_error(" NO CHANGES!"); |                         write_error(" NO CHANGES!"); | ||||||
|                     } |                     } | ||||||
|                     *m_out += '\n'; |                     *m_out += '\n'; | ||||||
|  | 
 | ||||||
|                     write_fieldname("created at"); |                     write_fieldname("created at"); | ||||||
|                     *m_out += ' '; |                     *m_out += ' '; | ||||||
|                     *m_out += changeset.created_at().to_iso(); |                     write_timestamp(changeset.created_at()); | ||||||
|                     output_formatted(" (%d)\n", changeset.created_at()); | 
 | ||||||
|                     write_fieldname("closed at"); |                     write_fieldname("closed at"); | ||||||
|                     *m_out += "  "; |                     *m_out += "  "; | ||||||
|                     if (changeset.closed()) { |                     if (changeset.closed()) { | ||||||
|                         *m_out += changeset.closed_at().to_iso(); |                         write_timestamp(changeset.closed_at()); | ||||||
|                         output_formatted(" (%d)\n", changeset.closed_at()); |  | ||||||
|                     } else { |                     } else { | ||||||
|                         write_error("OPEN!\n"); |                         write_error("OPEN!\n"); | ||||||
|                     } |                     } | ||||||
|  | 
 | ||||||
|                     write_fieldname("user"); |                     write_fieldname("user"); | ||||||
|                     output_formatted("       %d ", changeset.uid()); |                     output_formatted("       %d ", changeset.uid()); | ||||||
|                     write_string(changeset.user()); |                     write_string(changeset.user()); | ||||||
| @ -374,51 +362,73 @@ namespace osmium { | |||||||
|                     write_box(changeset.bounds()); |                     write_box(changeset.bounds()); | ||||||
|                     write_tags(changeset.tags(), "  "); |                     write_tags(changeset.tags(), "  "); | ||||||
| 
 | 
 | ||||||
|  |                     if (changeset.num_comments() > 0) { | ||||||
|  |                         write_fieldname("comments"); | ||||||
|  |                         output_formatted("   %d\n", changeset.num_comments()); | ||||||
|  | 
 | ||||||
|  |                         int width = int(log10(changeset.num_comments())) + 1; | ||||||
|  |                         int n = 0; | ||||||
|  |                         for (const auto& comment : changeset.discussion()) { | ||||||
|  |                             write_counter(width, n++); | ||||||
|  | 
 | ||||||
|  |                             write_comment_field("date"); | ||||||
|  |                             write_timestamp(comment.date()); | ||||||
|  |                             output_formatted("      %*s", width, ""); | ||||||
|  | 
 | ||||||
|  |                             write_comment_field("user"); | ||||||
|  |                             output_formatted("%d ", comment.uid()); | ||||||
|  |                             write_string(comment.user()); | ||||||
|  |                             output_formatted("\n      %*s", width, ""); | ||||||
|  | 
 | ||||||
|  |                             write_comment_field("text"); | ||||||
|  |                             write_string(comment.text()); | ||||||
|  |                             *m_out += '\n'; | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|                     *m_out += '\n'; |                     *m_out += '\n'; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|             }; // DebugOutputBlock
 |             }; // class DebugOutputBlock
 | ||||||
| 
 | 
 | ||||||
|             class DebugOutputFormat : public osmium::io::detail::OutputFormat { |             class DebugOutputFormat : public osmium::io::detail::OutputFormat { | ||||||
| 
 | 
 | ||||||
|                 bool m_add_metadata; |                 debug_output_options m_options; | ||||||
|                 bool m_use_color; |  | ||||||
| 
 |  | ||||||
|             public: |  | ||||||
| 
 |  | ||||||
|                 DebugOutputFormat(const osmium::io::File& file, data_queue_type& output_queue) : |  | ||||||
|                     OutputFormat(file, output_queue), |  | ||||||
|                     m_add_metadata(file.get("add_metadata") != "false"), |  | ||||||
|                     m_use_color(file.get("color") == "true") { |  | ||||||
|                 } |  | ||||||
| 
 |  | ||||||
|                 DebugOutputFormat(const DebugOutputFormat&) = delete; |  | ||||||
|                 DebugOutputFormat& operator=(const DebugOutputFormat&) = delete; |  | ||||||
| 
 |  | ||||||
|                 void write_buffer(osmium::memory::Buffer&& buffer) override final { |  | ||||||
|                     m_output_queue.push(osmium::thread::Pool::instance().submit(DebugOutputBlock{std::move(buffer), m_add_metadata, m_use_color})); |  | ||||||
|                 } |  | ||||||
| 
 | 
 | ||||||
|                 void write_fieldname(std::string& out, const char* name) { |                 void write_fieldname(std::string& out, const char* name) { | ||||||
|                     out += "  "; |                     out += "  "; | ||||||
|                     if (m_use_color) { |                     if (m_options.use_color) { | ||||||
|                         out += color_cyan; |                         out += color_cyan; | ||||||
|                     } |                     } | ||||||
|                     out += name; |                     out += name; | ||||||
|                     if (m_use_color) { |                     if (m_options.use_color) { | ||||||
|                         out += color_reset; |                         out += color_reset; | ||||||
|                     } |                     } | ||||||
|                     out += ": "; |                     out += ": "; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void write_header(const osmium::io::Header& header) override final { |             public: | ||||||
|  | 
 | ||||||
|  |                 DebugOutputFormat(const osmium::io::File& file, future_string_queue_type& output_queue) : | ||||||
|  |                     OutputFormat(output_queue), | ||||||
|  |                     m_options() { | ||||||
|  |                     m_options.add_metadata = file.is_not_false("add_metadata"); | ||||||
|  |                     m_options.use_color    = file.is_true("color"); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 DebugOutputFormat(const DebugOutputFormat&) = delete; | ||||||
|  |                 DebugOutputFormat& operator=(const DebugOutputFormat&) = delete; | ||||||
|  | 
 | ||||||
|  |                 ~DebugOutputFormat() noexcept final = default; | ||||||
|  | 
 | ||||||
|  |                 void write_header(const osmium::io::Header& header) final { | ||||||
|                     std::string out; |                     std::string out; | ||||||
| 
 | 
 | ||||||
|                     if (m_use_color) { |                     if (m_options.use_color) { | ||||||
|                         out += color_bold; |                         out += color_bold; | ||||||
|                     } |                     } | ||||||
|                     out += "header\n"; |                     out += "header\n"; | ||||||
|                     if (m_use_color) { |                     if (m_options.use_color) { | ||||||
|                         out += color_reset; |                         out += color_reset; | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
| @ -445,33 +455,26 @@ namespace osmium { | |||||||
|                     } |                     } | ||||||
|                     out += "\n=============================================\n\n"; |                     out += "\n=============================================\n\n"; | ||||||
| 
 | 
 | ||||||
|                     std::promise<std::string> promise; |                     send_to_output_queue(std::move(out)); | ||||||
|                     m_output_queue.push(promise.get_future()); |  | ||||||
|                     promise.set_value(std::move(out)); |  | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void close() override final { |                 void write_buffer(osmium::memory::Buffer&& buffer) final { | ||||||
|                     std::string out; |                     m_output_queue.push(osmium::thread::Pool::instance().submit(DebugOutputBlock{std::move(buffer), m_options})); | ||||||
|                     std::promise<std::string> promise; |  | ||||||
|                     m_output_queue.push(promise.get_future()); |  | ||||||
|                     promise.set_value(out); |  | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|             }; // class DebugOutputFormat
 |             }; // class DebugOutputFormat
 | ||||||
| 
 | 
 | ||||||
|             namespace { |             // we want the register_output_format() function to run, setting
 | ||||||
|  |             // the variable is only a side-effect, it will never be used
 | ||||||
|  |             const bool registered_debug_output = osmium::io::detail::OutputFormatFactory::instance().register_output_format(osmium::io::file_format::debug, | ||||||
|  |                 [](const osmium::io::File& file, future_string_queue_type& output_queue) { | ||||||
|  |                     return new osmium::io::detail::DebugOutputFormat(file, output_queue); | ||||||
|  |             }); | ||||||
| 
 | 
 | ||||||
| // we want the register_output_format() function to run, setting the variable
 |             // dummy function to silence the unused variable warning from above
 | ||||||
| // is only a side-effect, it will never be used
 |             inline bool get_registered_debug_output() noexcept { | ||||||
| #pragma GCC diagnostic push |                 return registered_debug_output; | ||||||
| #pragma GCC diagnostic ignored "-Wunused-variable" |             } | ||||||
|                 const bool registered_debug_output = osmium::io::detail::OutputFormatFactory::instance().register_output_format(osmium::io::file_format::debug, |  | ||||||
|                     [](const osmium::io::File& file, data_queue_type& output_queue) { |  | ||||||
|                         return new osmium::io::detail::DebugOutputFormat(file, output_queue); |  | ||||||
|                 }); |  | ||||||
| #pragma GCC diagnostic pop |  | ||||||
| 
 |  | ||||||
|             } // anonymous namespace
 |  | ||||||
| 
 | 
 | ||||||
|         } // namespace detail
 |         } // namespace detail
 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -33,13 +33,16 @@ DEALINGS IN THE SOFTWARE. | |||||||
| 
 | 
 | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
|  | #include <exception> | ||||||
| #include <functional> | #include <functional> | ||||||
|  | #include <future> | ||||||
| #include <map> | #include <map> | ||||||
| #include <memory> | #include <memory> | ||||||
| #include <stdexcept> | #include <stdexcept> | ||||||
| #include <string> | #include <string> | ||||||
| #include <utility> | #include <utility> | ||||||
| 
 | 
 | ||||||
|  | #include <osmium/io/detail/queue_util.hpp> | ||||||
| #include <osmium/io/file.hpp> | #include <osmium/io/file.hpp> | ||||||
| #include <osmium/io/file_format.hpp> | #include <osmium/io/file_format.hpp> | ||||||
| #include <osmium/io/header.hpp> | #include <osmium/io/header.hpp> | ||||||
| @ -48,106 +51,156 @@ DEALINGS IN THE SOFTWARE. | |||||||
| 
 | 
 | ||||||
| namespace osmium { | namespace osmium { | ||||||
| 
 | 
 | ||||||
|     namespace thread { |  | ||||||
|         template <typename T> class Queue; |  | ||||||
|     } // namespace thread
 |  | ||||||
| 
 |  | ||||||
|     namespace io { |     namespace io { | ||||||
| 
 | 
 | ||||||
|         namespace detail { |         namespace detail { | ||||||
| 
 | 
 | ||||||
|             /**
 |             class Parser { | ||||||
|              * Virtual base class for all classes reading OSM files in different | 
 | ||||||
|              * formats. |                 future_buffer_queue_type& m_output_queue; | ||||||
|              * |                 std::promise<osmium::io::Header>& m_header_promise; | ||||||
|              * Do not use this class or derived classes directly. Use the |                 queue_wrapper<std::string> m_input_queue; | ||||||
|              * osmium::io::Reader class instead. |                 osmium::osm_entity_bits::type m_read_types; | ||||||
|              */ |                 bool m_header_is_done; | ||||||
|             class InputFormat { |  | ||||||
| 
 | 
 | ||||||
|             protected: |             protected: | ||||||
| 
 | 
 | ||||||
|                 osmium::io::File m_file; |                 std::string get_input() { | ||||||
|                 osmium::osm_entity_bits::type m_read_which_entities; |                     return m_input_queue.pop(); | ||||||
|                 osmium::io::Header m_header; |  | ||||||
| 
 |  | ||||||
|                 explicit InputFormat(const osmium::io::File& file, osmium::osm_entity_bits::type read_which_entities) : |  | ||||||
|                     m_file(file), |  | ||||||
|                     m_read_which_entities(read_which_entities) { |  | ||||||
|                     m_header.set_has_multiple_object_versions(m_file.has_multiple_object_versions()); |  | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 InputFormat(const InputFormat&) = delete; |                 bool input_done() const { | ||||||
|                 InputFormat(InputFormat&&) = delete; |                     return m_input_queue.has_reached_end_of_data(); | ||||||
|  |                 } | ||||||
| 
 | 
 | ||||||
|                 InputFormat& operator=(const InputFormat&) = delete; |                 osmium::osm_entity_bits::type read_types() const { | ||||||
|                 InputFormat& operator=(InputFormat&&) = delete; |                     return m_read_types; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 bool header_is_done() const { | ||||||
|  |                     return m_header_is_done; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 void set_header_value(const osmium::io::Header& header) { | ||||||
|  |                     if (!m_header_is_done) { | ||||||
|  |                         m_header_is_done = true; | ||||||
|  |                         m_header_promise.set_value(header); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 void set_header_exception(const std::exception_ptr& exception) { | ||||||
|  |                     if (!m_header_is_done) { | ||||||
|  |                         m_header_is_done = true; | ||||||
|  |                         m_header_promise.set_exception(exception); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 /**
 | ||||||
|  |                  * Wrap the buffer into a future and add it to the output queue. | ||||||
|  |                  */ | ||||||
|  |                 void send_to_output_queue(osmium::memory::Buffer&& buffer) { | ||||||
|  |                     add_to_queue(m_output_queue, std::move(buffer)); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 void send_to_output_queue(std::future<osmium::memory::Buffer>&& future) { | ||||||
|  |                     m_output_queue.push(std::move(future)); | ||||||
|  |                 } | ||||||
| 
 | 
 | ||||||
|             public: |             public: | ||||||
| 
 | 
 | ||||||
|                 virtual ~InputFormat() { |                 Parser(future_string_queue_type& input_queue, | ||||||
|  |                        future_buffer_queue_type& output_queue, | ||||||
|  |                        std::promise<osmium::io::Header>& header_promise, | ||||||
|  |                        osmium::osm_entity_bits::type read_types) : | ||||||
|  |                     m_output_queue(output_queue), | ||||||
|  |                     m_header_promise(header_promise), | ||||||
|  |                     m_input_queue(input_queue), | ||||||
|  |                     m_read_types(read_types), | ||||||
|  |                     m_header_is_done(false) { | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 virtual osmium::memory::Buffer read() = 0; |                 Parser(const Parser&) = delete; | ||||||
|  |                 Parser& operator=(const Parser&) = delete; | ||||||
| 
 | 
 | ||||||
|                 virtual void close() { |                 Parser(Parser&&) = delete; | ||||||
|  |                 Parser& operator=(Parser&&) = delete; | ||||||
|  | 
 | ||||||
|  |                 virtual ~Parser() noexcept = default; | ||||||
|  | 
 | ||||||
|  |                 virtual void run() = 0; | ||||||
|  | 
 | ||||||
|  |                 void parse() { | ||||||
|  |                     try { | ||||||
|  |                         run(); | ||||||
|  |                     } catch (...) { | ||||||
|  |                         std::exception_ptr exception = std::current_exception(); | ||||||
|  |                         set_header_exception(exception); | ||||||
|  |                         add_to_queue(m_output_queue, std::move(exception)); | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     add_end_of_data_to_queue(m_output_queue); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 virtual osmium::io::Header header() { |             }; // class Parser
 | ||||||
|                     return m_header; |  | ||||||
|                 } |  | ||||||
| 
 |  | ||||||
|             }; // class InputFormat
 |  | ||||||
| 
 | 
 | ||||||
|             /**
 |             /**
 | ||||||
|              * This factory class is used to create objects that read OSM data |              * This factory class is used to create objects that decode OSM | ||||||
|              * written in a specified format. |              * data written in a specified format. | ||||||
|              * |              * | ||||||
|              * Do not use this class directly. Instead use the osmium::io::Reader |              * Do not use this class directly. Use the osmium::io::Reader | ||||||
|              * class. |              * class instead. | ||||||
|              */ |              */ | ||||||
|             class InputFormatFactory { |             class ParserFactory { | ||||||
| 
 | 
 | ||||||
|             public: |             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; |                 typedef std::function< | ||||||
|  |                             std::unique_ptr<Parser>( | ||||||
|  |                                 future_string_queue_type&, | ||||||
|  |                                 future_buffer_queue_type&, | ||||||
|  |                                 std::promise<osmium::io::Header>& header_promise, | ||||||
|  |                                 osmium::osm_entity_bits::type read_which_entities | ||||||
|  |                             ) | ||||||
|  |                         > create_parser_type; | ||||||
| 
 | 
 | ||||||
|             private: |             private: | ||||||
| 
 | 
 | ||||||
|                 typedef std::map<osmium::io::file_format, create_input_type> map_type; |                 typedef std::map<osmium::io::file_format, create_parser_type> map_type; | ||||||
| 
 | 
 | ||||||
|                 map_type m_callbacks; |                 map_type m_callbacks; | ||||||
| 
 | 
 | ||||||
|                 InputFormatFactory() : |                 ParserFactory() : | ||||||
|                     m_callbacks() { |                     m_callbacks() { | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|             public: |             public: | ||||||
| 
 | 
 | ||||||
|                 static InputFormatFactory& instance() { |                 static ParserFactory& instance() { | ||||||
|                     static InputFormatFactory factory; |                     static ParserFactory factory; | ||||||
|                     return factory; |                     return factory; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 bool register_input_format(osmium::io::file_format format, create_input_type create_function) { |                 bool register_parser(osmium::io::file_format format, create_parser_type create_function) { | ||||||
|                     if (! m_callbacks.insert(map_type::value_type(format, create_function)).second) { |                     if (! m_callbacks.insert(map_type::value_type(format, create_function)).second) { | ||||||
|                         return false; |                         return false; | ||||||
|                     } |                     } | ||||||
|                     return true; |                     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) { |                 create_parser_type get_creator_function(const osmium::io::File& file) { | ||||||
|                     file.check(); |  | ||||||
| 
 |  | ||||||
|                     auto it = m_callbacks.find(file.format()); |                     auto it = m_callbacks.find(file.format()); | ||||||
|                     if (it != m_callbacks.end()) { |                     if (it == m_callbacks.end()) { | ||||||
|                         return std::unique_ptr<osmium::io::detail::InputFormat>((it->second)(file, read_which_entities, input_queue)); |                         throw unsupported_file_format_error( | ||||||
|  |                                 std::string("Can not open file '") + | ||||||
|  |                                 file.filename() + | ||||||
|  |                                 "' with type '" + | ||||||
|  |                                 as_string(file.format()) + | ||||||
|  |                                 "'. No support for reading this format in this program."); | ||||||
|                     } |                     } | ||||||
| 
 |                     return it->second; | ||||||
|                     throw std::runtime_error(std::string("Support for input format '") + as_string(file.format()) + "' not compiled into this binary."); |  | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|             }; // class InputFormatFactory
 |             }; // class ParserFactory
 | ||||||
| 
 | 
 | ||||||
|         } // namespace detail
 |         } // namespace detail
 | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										636
									
								
								third_party/libosmium/include/osmium/io/detail/o5m_input_format.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										636
									
								
								third_party/libosmium/include/osmium/io/detail/o5m_input_format.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,636 @@ | |||||||
|  | #ifndef OSMIUM_IO_DETAIL_O5M_INPUT_FORMAT_HPP | ||||||
|  | #define OSMIUM_IO_DETAIL_O5M_INPUT_FORMAT_HPP | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  | 
 | ||||||
|  | This file is part of Osmium (http://osmcode.org/libosmium).
 | ||||||
|  | 
 | ||||||
|  | Copyright 2013-2015 Jochen Topf <jochen@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 <cstdint> | ||||||
|  | #include <cstring> | ||||||
|  | #include <future> | ||||||
|  | #include <memory> | ||||||
|  | #include <string> | ||||||
|  | #include <utility> | ||||||
|  | 
 | ||||||
|  | #include <protozero/varint.hpp> | ||||||
|  | 
 | ||||||
|  | #include <osmium/builder/builder.hpp> | ||||||
|  | #include <osmium/builder/osm_object_builder.hpp> | ||||||
|  | #include <osmium/io/detail/input_format.hpp> | ||||||
|  | #include <osmium/io/detail/queue_util.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/util.hpp> | ||||||
|  | #include <osmium/util/cast.hpp> | ||||||
|  | #include <osmium/util/delta.hpp> | ||||||
|  | 
 | ||||||
|  | namespace osmium { | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Exception thrown when the o5m deocder failed. The exception contains | ||||||
|  |      * (if available) information about the place where the error happened | ||||||
|  |      * and the type of error. | ||||||
|  |      */ | ||||||
|  |     struct o5m_error : public io_error { | ||||||
|  | 
 | ||||||
|  |         explicit o5m_error(const char* what) : | ||||||
|  |             io_error(std::string("o5m format error: ") + what) { | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     }; // struct o5m_error
 | ||||||
|  | 
 | ||||||
|  |     namespace io { | ||||||
|  | 
 | ||||||
|  |         namespace detail { | ||||||
|  | 
 | ||||||
|  |             // Implementation of the o5m/o5c file formats according to the
 | ||||||
|  |             // description at http://wiki.openstreetmap.org/wiki/O5m .
 | ||||||
|  | 
 | ||||||
|  |             class ReferenceTable { | ||||||
|  | 
 | ||||||
|  |                 // The following settings are from the o5m description:
 | ||||||
|  | 
 | ||||||
|  |                 // The maximum number of entries in this table.
 | ||||||
|  |                 const uint64_t number_of_entries = 15000; | ||||||
|  | 
 | ||||||
|  |                 // The size of one entry in the table.
 | ||||||
|  |                 const unsigned int entry_size = 256; | ||||||
|  | 
 | ||||||
|  |                 // The maximum length of a string in the table including
 | ||||||
|  |                 // two \0 bytes.
 | ||||||
|  |                 const unsigned int max_length = 250 + 2; | ||||||
|  | 
 | ||||||
|  |                 // The data is stored in this string. It is default constructed
 | ||||||
|  |                 // and then resized on demand the first time something is added.
 | ||||||
|  |                 // This is done because the ReferenceTable is in a O5mParser
 | ||||||
|  |                 // object which will be copied from one thread to another. This
 | ||||||
|  |                 // way the string is still small when it is copied.
 | ||||||
|  |                 std::string m_table; | ||||||
|  | 
 | ||||||
|  |                 unsigned int current_entry = 0; | ||||||
|  | 
 | ||||||
|  |             public: | ||||||
|  | 
 | ||||||
|  |                 void clear() { | ||||||
|  |                     current_entry = 0; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 void add(const char* string, size_t size) { | ||||||
|  |                     if (m_table.empty()) { | ||||||
|  |                         m_table.resize(entry_size * number_of_entries); | ||||||
|  |                     } | ||||||
|  |                     if (size <= max_length) { | ||||||
|  |                         std::copy_n(string, size, &m_table[current_entry * entry_size]); | ||||||
|  |                         if (++current_entry == number_of_entries) { | ||||||
|  |                             current_entry = 0; | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 const char* get(uint64_t index) const { | ||||||
|  |                     if (m_table.empty() || index == 0 || index > number_of_entries) { | ||||||
|  |                         throw o5m_error("reference to non-existing string in table"); | ||||||
|  |                     } | ||||||
|  |                     auto entry = (current_entry + number_of_entries - index) % number_of_entries; | ||||||
|  |                     return &m_table[entry * entry_size]; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |             }; // class ReferenceTable
 | ||||||
|  | 
 | ||||||
|  |             class O5mParser : public Parser { | ||||||
|  | 
 | ||||||
|  |                 static constexpr int buffer_size = 2 * 1000 * 1000; | ||||||
|  | 
 | ||||||
|  |                 osmium::io::Header m_header; | ||||||
|  | 
 | ||||||
|  |                 osmium::memory::Buffer m_buffer; | ||||||
|  | 
 | ||||||
|  |                 std::string m_input; | ||||||
|  | 
 | ||||||
|  |                 const char* m_data; | ||||||
|  |                 const char* m_end; | ||||||
|  | 
 | ||||||
|  |                 ReferenceTable m_reference_table; | ||||||
|  | 
 | ||||||
|  |                 static int64_t zvarint(const char** data, const char* end) { | ||||||
|  |                     return protozero::decode_zigzag64(protozero::decode_varint(data, end)); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 bool ensure_bytes_available(size_t need_bytes) { | ||||||
|  |                     if ((m_end - m_data) >= long(need_bytes)) { | ||||||
|  |                         return true; | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     if (input_done() && (m_input.size() < need_bytes)) { | ||||||
|  |                         return false; | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     m_input.erase(0, m_data - m_input.data()); | ||||||
|  | 
 | ||||||
|  |                     while (m_input.size() < need_bytes) { | ||||||
|  |                         std::string data = get_input(); | ||||||
|  |                         if (input_done()) { | ||||||
|  |                             return false; | ||||||
|  |                         } | ||||||
|  |                         m_input.append(data); | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     m_data = m_input.data(); | ||||||
|  |                     m_end = m_input.data() + m_input.size(); | ||||||
|  | 
 | ||||||
|  |                     return true; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 void check_header_magic() { | ||||||
|  |                     static const unsigned char header_magic[] = { 0xff, 0xe0, 0x04, 'o', '5' }; | ||||||
|  | 
 | ||||||
|  |                     if (std::strncmp(reinterpret_cast<const char*>(header_magic), m_data, sizeof(header_magic))) { | ||||||
|  |                         throw o5m_error("wrong header magic"); | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     m_data += sizeof(header_magic); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 void check_file_type() { | ||||||
|  |                     if (*m_data == 'm') {         // o5m data file
 | ||||||
|  |                         m_header.set_has_multiple_object_versions(false); | ||||||
|  |                     } else if (*m_data == 'c') {  // o5c change file
 | ||||||
|  |                         m_header.set_has_multiple_object_versions(true); | ||||||
|  |                     } else { | ||||||
|  |                         throw o5m_error("wrong header magic"); | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     m_data++; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 void check_file_format_version() { | ||||||
|  |                     if (*m_data != '2') { | ||||||
|  |                         throw o5m_error("wrong header magic"); | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     m_data++; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 void decode_header() { | ||||||
|  |                     if (! ensure_bytes_available(7)) { // overall length of header
 | ||||||
|  |                         throw o5m_error("file too short (incomplete header info)"); | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     check_header_magic(); | ||||||
|  |                     check_file_type(); | ||||||
|  |                     check_file_format_version(); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 void mark_header_as_done() { | ||||||
|  |                     set_header_value(m_header); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 osmium::util::DeltaDecode<osmium::object_id_type> m_delta_id; | ||||||
|  | 
 | ||||||
|  |                 osmium::util::DeltaDecode<int64_t> m_delta_timestamp; | ||||||
|  |                 osmium::util::DeltaDecode<osmium::changeset_id_type> m_delta_changeset; | ||||||
|  |                 osmium::util::DeltaDecode<int64_t> m_delta_lon; | ||||||
|  |                 osmium::util::DeltaDecode<int64_t> m_delta_lat; | ||||||
|  | 
 | ||||||
|  |                 osmium::util::DeltaDecode<osmium::object_id_type> m_delta_way_node_id; | ||||||
|  |                 osmium::util::DeltaDecode<osmium::object_id_type> m_delta_member_ids[3]; | ||||||
|  | 
 | ||||||
|  |                 void reset() { | ||||||
|  |                     m_reference_table.clear(); | ||||||
|  | 
 | ||||||
|  |                     m_delta_id.clear(); | ||||||
|  |                     m_delta_timestamp.clear(); | ||||||
|  |                     m_delta_changeset.clear(); | ||||||
|  |                     m_delta_lon.clear(); | ||||||
|  |                     m_delta_lat.clear(); | ||||||
|  | 
 | ||||||
|  |                     m_delta_way_node_id.clear(); | ||||||
|  |                     m_delta_member_ids[0].clear(); | ||||||
|  |                     m_delta_member_ids[1].clear(); | ||||||
|  |                     m_delta_member_ids[2].clear(); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 const char* decode_string(const char** dataptr, const char* const end) { | ||||||
|  |                     if (**dataptr == 0x00) { // get inline string
 | ||||||
|  |                         (*dataptr)++; | ||||||
|  |                         if (*dataptr == end) { | ||||||
|  |                             throw o5m_error("string format error"); | ||||||
|  |                         } | ||||||
|  |                         return *dataptr; | ||||||
|  |                     } else { // get from reference table
 | ||||||
|  |                         auto index = protozero::decode_varint(dataptr, end); | ||||||
|  |                         return m_reference_table.get(index); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 std::pair<osmium::user_id_type, const char*> decode_user(const char** dataptr, const char* const end) { | ||||||
|  |                     bool update_pointer = (**dataptr == 0x00); | ||||||
|  |                     const char* data = decode_string(dataptr, end); | ||||||
|  |                     const char* start = data; | ||||||
|  | 
 | ||||||
|  |                     auto uid = protozero::decode_varint(&data, end); | ||||||
|  | 
 | ||||||
|  |                     if (data == end) { | ||||||
|  |                         throw o5m_error("missing user name"); | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     const char* user = ++data; | ||||||
|  | 
 | ||||||
|  |                     if (uid == 0 && update_pointer) { | ||||||
|  |                         m_reference_table.add("\0\0", 2); | ||||||
|  |                         *dataptr = data; | ||||||
|  |                         return std::make_pair(0, ""); | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     while (*data++) { | ||||||
|  |                         if (data == end) { | ||||||
|  |                             throw o5m_error("no null byte in user name"); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     if (update_pointer) { | ||||||
|  |                         m_reference_table.add(start, data - start); | ||||||
|  |                         *dataptr = data; | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     return std::make_pair(static_cast_with_assert<osmium::user_id_type>(uid), user); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 void decode_tags(osmium::builder::Builder* builder, const char** dataptr, const char* const end) { | ||||||
|  |                     osmium::builder::TagListBuilder tl_builder(m_buffer, builder); | ||||||
|  | 
 | ||||||
|  |                     while(*dataptr != end) { | ||||||
|  |                         bool update_pointer = (**dataptr == 0x00); | ||||||
|  |                         const char* data = decode_string(dataptr, end); | ||||||
|  |                         const char* start = data; | ||||||
|  | 
 | ||||||
|  |                         while (*data++) { | ||||||
|  |                             if (data == end) { | ||||||
|  |                                 throw o5m_error("no null byte in tag key"); | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  | 
 | ||||||
|  |                         const char* value = data; | ||||||
|  |                         while (*data++) { | ||||||
|  |                             if (data == end) { | ||||||
|  |                                 throw o5m_error("no null byte in tag value"); | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  | 
 | ||||||
|  |                         if (update_pointer) { | ||||||
|  |                             m_reference_table.add(start, data - start); | ||||||
|  |                             *dataptr = data; | ||||||
|  |                         } | ||||||
|  | 
 | ||||||
|  |                         tl_builder.add_tag(start, value); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 const char* decode_info(osmium::OSMObject& object, const char** dataptr, const char* const end) { | ||||||
|  |                     const char* user = ""; | ||||||
|  | 
 | ||||||
|  |                     if (**dataptr == 0x00) { // no info section
 | ||||||
|  |                         ++*dataptr; | ||||||
|  |                     } else { // has info section
 | ||||||
|  |                         object.set_version(static_cast_with_assert<object_version_type>(protozero::decode_varint(dataptr, end))); | ||||||
|  |                         auto timestamp = m_delta_timestamp.update(zvarint(dataptr, end)); | ||||||
|  |                         if (timestamp != 0) { // has timestamp
 | ||||||
|  |                             object.set_timestamp(timestamp); | ||||||
|  |                             object.set_changeset(m_delta_changeset.update(zvarint(dataptr, end))); | ||||||
|  |                             if (*dataptr != end) { | ||||||
|  |                                 auto uid_user = decode_user(dataptr, end); | ||||||
|  |                                 object.set_uid(uid_user.first); | ||||||
|  |                                 user = uid_user.second; | ||||||
|  |                             } else { | ||||||
|  |                                 object.set_uid(user_id_type(0)); | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     return user; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 void decode_node(const char* data, const char* const end) { | ||||||
|  |                     osmium::builder::NodeBuilder builder(m_buffer); | ||||||
|  |                     osmium::Node& node = builder.object(); | ||||||
|  | 
 | ||||||
|  |                     node.set_id(m_delta_id.update(zvarint(&data, end))); | ||||||
|  | 
 | ||||||
|  |                     builder.add_user(decode_info(node, &data, end)); | ||||||
|  | 
 | ||||||
|  |                     if (data == end) { | ||||||
|  |                         // no location, object is deleted
 | ||||||
|  |                         builder.object().set_visible(false); | ||||||
|  |                         builder.object().set_location(osmium::Location{}); | ||||||
|  |                     } else { | ||||||
|  |                         auto lon = m_delta_lon.update(zvarint(&data, end)); | ||||||
|  |                         auto lat = m_delta_lat.update(zvarint(&data, end)); | ||||||
|  |                         builder.object().set_location(osmium::Location{lon, lat}); | ||||||
|  | 
 | ||||||
|  |                         if (data != end) { | ||||||
|  |                             decode_tags(&builder, &data, end); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     m_buffer.commit(); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 void decode_way(const char* data, const char* const end) { | ||||||
|  |                     osmium::builder::WayBuilder builder(m_buffer); | ||||||
|  |                     osmium::Way& way = builder.object(); | ||||||
|  | 
 | ||||||
|  |                     way.set_id(m_delta_id.update(zvarint(&data, end))); | ||||||
|  | 
 | ||||||
|  |                     builder.add_user(decode_info(way, &data, end)); | ||||||
|  | 
 | ||||||
|  |                     if (data == end) { | ||||||
|  |                         // no reference section, object is deleted
 | ||||||
|  |                         builder.object().set_visible(false); | ||||||
|  |                     } else { | ||||||
|  |                         auto reference_section_length = protozero::decode_varint(&data, end); | ||||||
|  |                         if (reference_section_length > 0) { | ||||||
|  |                             const char* const end_refs = data + reference_section_length; | ||||||
|  |                             if (end_refs > end) { | ||||||
|  |                                 throw o5m_error("way nodes ref section too long"); | ||||||
|  |                             } | ||||||
|  | 
 | ||||||
|  |                             osmium::builder::WayNodeListBuilder wn_builder(m_buffer, &builder); | ||||||
|  | 
 | ||||||
|  |                             while (data < end_refs) { | ||||||
|  |                                 wn_builder.add_node_ref(m_delta_way_node_id.update(zvarint(&data, end))); | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  | 
 | ||||||
|  |                         if (data != end) { | ||||||
|  |                             decode_tags(&builder, &data, end); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     m_buffer.commit(); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 osmium::item_type decode_member_type(char c) { | ||||||
|  |                     if (c < '0' || c > '2') { | ||||||
|  |                         throw o5m_error("unknown member type"); | ||||||
|  |                     } | ||||||
|  |                     return osmium::nwr_index_to_item_type(c - '0'); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 std::pair<osmium::item_type, const char*> decode_role(const char** dataptr, const char* const end) { | ||||||
|  |                     bool update_pointer = (**dataptr == 0x00); | ||||||
|  |                     const char* data = decode_string(dataptr, end); | ||||||
|  |                     const char* start = data; | ||||||
|  | 
 | ||||||
|  |                     auto member_type = decode_member_type(*data++); | ||||||
|  |                     if (data == end) { | ||||||
|  |                         throw o5m_error("missing role"); | ||||||
|  |                     } | ||||||
|  |                     const char* role = data; | ||||||
|  | 
 | ||||||
|  |                     while (*data++) { | ||||||
|  |                         if (data == end) { | ||||||
|  |                             throw o5m_error("no null byte in role"); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     if (update_pointer) { | ||||||
|  |                         m_reference_table.add(start, data - start); | ||||||
|  |                         *dataptr = data; | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     return std::make_pair(member_type, role); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 void decode_relation(const char* data, const char* const end) { | ||||||
|  |                     osmium::builder::RelationBuilder builder(m_buffer); | ||||||
|  |                     osmium::Relation& relation = builder.object(); | ||||||
|  | 
 | ||||||
|  |                     relation.set_id(m_delta_id.update(zvarint(&data, end))); | ||||||
|  | 
 | ||||||
|  |                     builder.add_user(decode_info(relation, &data, end)); | ||||||
|  | 
 | ||||||
|  |                     if (data == end) { | ||||||
|  |                         // no reference section, object is deleted
 | ||||||
|  |                         builder.object().set_visible(false); | ||||||
|  |                     } else { | ||||||
|  |                         auto reference_section_length = protozero::decode_varint(&data, end); | ||||||
|  |                         if (reference_section_length > 0) { | ||||||
|  |                             const char* const end_refs = data + reference_section_length; | ||||||
|  |                             if (end_refs > end) { | ||||||
|  |                                 throw o5m_error("relation format error"); | ||||||
|  |                             } | ||||||
|  | 
 | ||||||
|  |                             osmium::builder::RelationMemberListBuilder rml_builder(m_buffer, &builder); | ||||||
|  | 
 | ||||||
|  |                             while (data < end_refs) { | ||||||
|  |                                 auto delta_id = zvarint(&data, end); | ||||||
|  |                                 if (data == end) { | ||||||
|  |                                     throw o5m_error("relation member format error"); | ||||||
|  |                                 } | ||||||
|  |                                 auto type_role = decode_role(&data, end); | ||||||
|  |                                 auto i = osmium::item_type_to_nwr_index(type_role.first); | ||||||
|  |                                 auto ref = m_delta_member_ids[i].update(delta_id); | ||||||
|  |                                 rml_builder.add_member(type_role.first, ref, type_role.second); | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  | 
 | ||||||
|  |                         if (data != end) { | ||||||
|  |                             decode_tags(&builder, &data, end); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     m_buffer.commit(); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 void decode_bbox(const char* data, const char* const end) { | ||||||
|  |                     auto sw_lon = zvarint(&data, end); | ||||||
|  |                     auto sw_lat = zvarint(&data, end); | ||||||
|  |                     auto ne_lon = zvarint(&data, end); | ||||||
|  |                     auto ne_lat = zvarint(&data, end); | ||||||
|  | 
 | ||||||
|  |                     m_header.add_box(osmium::Box{osmium::Location{sw_lon, sw_lat}, | ||||||
|  |                                                  osmium::Location{ne_lon, ne_lat}}); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 void decode_timestamp(const char* data, const char* const end) { | ||||||
|  |                     auto timestamp = osmium::Timestamp(zvarint(&data, end)).to_iso(); | ||||||
|  |                     m_header.set("o5m_timestamp", timestamp); | ||||||
|  |                     m_header.set("timestamp", timestamp); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 void flush() { | ||||||
|  |                     osmium::memory::Buffer buffer(buffer_size); | ||||||
|  |                     using std::swap; | ||||||
|  |                     swap(m_buffer, buffer); | ||||||
|  |                     send_to_output_queue(std::move(buffer)); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 enum class dataset_type : unsigned char { | ||||||
|  |                     node         = 0x10, | ||||||
|  |                     way          = 0x11, | ||||||
|  |                     relation     = 0x12, | ||||||
|  |                     bounding_box = 0xdb, | ||||||
|  |                     timestamp    = 0xdc, | ||||||
|  |                     header       = 0xe0, | ||||||
|  |                     sync         = 0xee, | ||||||
|  |                     jump         = 0xef, | ||||||
|  |                     reset        = 0xff | ||||||
|  |                 }; | ||||||
|  | 
 | ||||||
|  |                 void decode_data() { | ||||||
|  |                     while (ensure_bytes_available(1)) { | ||||||
|  |                         dataset_type ds_type = dataset_type(*m_data++); | ||||||
|  |                         if (ds_type > dataset_type::jump) { | ||||||
|  |                             if (ds_type == dataset_type::reset) { | ||||||
|  |                                 reset(); | ||||||
|  |                             } | ||||||
|  |                         } else { | ||||||
|  |                             ensure_bytes_available(protozero::max_varint_length); | ||||||
|  | 
 | ||||||
|  |                             uint64_t length = 0; | ||||||
|  |                             try { | ||||||
|  |                                 length = protozero::decode_varint(&m_data, m_end); | ||||||
|  |                             } catch (protozero::end_of_buffer_exception&) { | ||||||
|  |                                 throw o5m_error("premature end of file"); | ||||||
|  |                             } | ||||||
|  | 
 | ||||||
|  |                             if (! ensure_bytes_available(length)) { | ||||||
|  |                                 throw o5m_error("premature end of file"); | ||||||
|  |                             } | ||||||
|  | 
 | ||||||
|  |                             switch (ds_type) { | ||||||
|  |                                 case dataset_type::node: | ||||||
|  |                                     mark_header_as_done(); | ||||||
|  |                                     if (read_types() & osmium::osm_entity_bits::node) { | ||||||
|  |                                         decode_node(m_data, m_data + length); | ||||||
|  |                                     } | ||||||
|  |                                     break; | ||||||
|  |                                 case dataset_type::way: | ||||||
|  |                                     mark_header_as_done(); | ||||||
|  |                                     if (read_types() & osmium::osm_entity_bits::way) { | ||||||
|  |                                         decode_way(m_data, m_data + length); | ||||||
|  |                                     } | ||||||
|  |                                     break; | ||||||
|  |                                 case dataset_type::relation: | ||||||
|  |                                     mark_header_as_done(); | ||||||
|  |                                     if (read_types() & osmium::osm_entity_bits::relation) { | ||||||
|  |                                         decode_relation(m_data, m_data + length); | ||||||
|  |                                     } | ||||||
|  |                                     break; | ||||||
|  |                                 case dataset_type::bounding_box: | ||||||
|  |                                     decode_bbox(m_data, m_data + length); | ||||||
|  |                                     break; | ||||||
|  |                                 case dataset_type::timestamp: | ||||||
|  |                                     decode_timestamp(m_data, m_data + length); | ||||||
|  |                                     break; | ||||||
|  |                                 default: | ||||||
|  |                                     // ignore unknown datasets
 | ||||||
|  |                                     break; | ||||||
|  |                             } | ||||||
|  | 
 | ||||||
|  |                             if (read_types() == osmium::osm_entity_bits::nothing && header_is_done()) { | ||||||
|  |                                 break; | ||||||
|  |                             } | ||||||
|  | 
 | ||||||
|  |                             m_data += length; | ||||||
|  | 
 | ||||||
|  |                             if (m_buffer.committed() > buffer_size / 10 * 9) { | ||||||
|  |                                 flush(); | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     if (m_buffer.committed()) { | ||||||
|  |                         flush(); | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     mark_header_as_done(); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |             public: | ||||||
|  | 
 | ||||||
|  |                 O5mParser(future_string_queue_type& input_queue, | ||||||
|  |                           future_buffer_queue_type& output_queue, | ||||||
|  |                           std::promise<osmium::io::Header>& header_promise, | ||||||
|  |                           osmium::osm_entity_bits::type read_types) : | ||||||
|  |                     Parser(input_queue, output_queue, header_promise, read_types), | ||||||
|  |                     m_header(), | ||||||
|  |                     m_buffer(buffer_size), | ||||||
|  |                     m_input(), | ||||||
|  |                     m_data(m_input.data()), | ||||||
|  |                     m_end(m_data) { | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 ~O5mParser() noexcept final = default; | ||||||
|  | 
 | ||||||
|  |                 void run() final { | ||||||
|  |                     osmium::thread::set_thread_name("_osmium_o5m_in"); | ||||||
|  | 
 | ||||||
|  |                     decode_header(); | ||||||
|  |                     decode_data(); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |             }; // class O5mParser
 | ||||||
|  | 
 | ||||||
|  |             // we want the register_parser() function to run, setting
 | ||||||
|  |             // the variable is only a side-effect, it will never be used
 | ||||||
|  |             const bool registered_o5m_parser = ParserFactory::instance().register_parser( | ||||||
|  |                 file_format::o5m, | ||||||
|  |                 [](future_string_queue_type& input_queue, | ||||||
|  |                     future_buffer_queue_type& output_queue, | ||||||
|  |                     std::promise<osmium::io::Header>& header_promise, | ||||||
|  |                     osmium::osm_entity_bits::type read_which_entities) { | ||||||
|  |                     return std::unique_ptr<Parser>(new O5mParser(input_queue, output_queue, header_promise, read_which_entities)); | ||||||
|  |             }); | ||||||
|  | 
 | ||||||
|  |             // dummy function to silence the unused variable warning from above
 | ||||||
|  |             inline bool get_registered_o5m_parser() noexcept { | ||||||
|  |                 return registered_o5m_parser; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |         } // namespace detail
 | ||||||
|  | 
 | ||||||
|  |     } // namespace io
 | ||||||
|  | 
 | ||||||
|  | } // namespace osmium
 | ||||||
|  | 
 | ||||||
|  | #endif // OSMIUM_IO_DETAIL_O5M_INPUT_FORMAT_HPP
 | ||||||
| @ -33,7 +33,6 @@ DEALINGS IN THE SOFTWARE. | |||||||
| 
 | 
 | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| #include <chrono> |  | ||||||
| #include <cinttypes> | #include <cinttypes> | ||||||
| #include <cstddef> | #include <cstddef> | ||||||
| #include <cstdint> | #include <cstdint> | ||||||
| @ -41,14 +40,10 @@ DEALINGS IN THE SOFTWARE. | |||||||
| #include <future> | #include <future> | ||||||
| #include <iterator> | #include <iterator> | ||||||
| #include <memory> | #include <memory> | ||||||
| #include <ratio> |  | ||||||
| #include <string> | #include <string> | ||||||
| #include <thread> | #include <thread> | ||||||
| #include <utility> | #include <utility> | ||||||
| 
 | 
 | ||||||
| #include <utf8.h> |  | ||||||
| 
 |  | ||||||
| #include <osmium/handler.hpp> |  | ||||||
| #include <osmium/io/detail/output_format.hpp> | #include <osmium/io/detail/output_format.hpp> | ||||||
| #include <osmium/io/file_format.hpp> | #include <osmium/io/file_format.hpp> | ||||||
| #include <osmium/memory/buffer.hpp> | #include <osmium/memory/buffer.hpp> | ||||||
| @ -74,71 +69,27 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|         namespace detail { |         namespace detail { | ||||||
| 
 | 
 | ||||||
|  |             struct opl_output_options { | ||||||
|  | 
 | ||||||
|  |                 /// Should metadata of objects be added?
 | ||||||
|  |                 bool add_metadata; | ||||||
|  | 
 | ||||||
|  |             }; | ||||||
|  | 
 | ||||||
|             /**
 |             /**
 | ||||||
|              * Writes out one buffer with OSM data in OPL format. |              * Writes out one buffer with OSM data in OPL format. | ||||||
|              */ |              */ | ||||||
|             class OPLOutputBlock : public osmium::handler::Handler { |             class OPLOutputBlock : public OutputBlock { | ||||||
| 
 | 
 | ||||||
|                 static constexpr size_t tmp_buffer_size = 100; |                 opl_output_options m_options; | ||||||
| 
 |  | ||||||
|                 std::shared_ptr<osmium::memory::Buffer> m_input_buffer; |  | ||||||
| 
 |  | ||||||
|                 std::shared_ptr<std::string> m_out; |  | ||||||
| 
 |  | ||||||
|                 char m_tmp_buffer[tmp_buffer_size+1]; |  | ||||||
| 
 |  | ||||||
|                 bool m_add_metadata; |  | ||||||
| 
 |  | ||||||
|                 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 char* data) { |                 void append_encoded_string(const char* data) { | ||||||
|                     const char* end = data + std::strlen(data); |                     osmium::io::detail::append_utf8_encoded_string(*m_out, data); | ||||||
| 
 |  | ||||||
|                     while (data != end) { |  | ||||||
|                         const char* last = data; |  | ||||||
|                         uint32_t c = utf8::next(data, end); |  | ||||||
| 
 |  | ||||||
|                         // 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)) { |  | ||||||
|                             m_out->append(last, data); |  | ||||||
|                         } else { |  | ||||||
|                             *m_out += '%'; |  | ||||||
|                             if (c <= 0xff) { |  | ||||||
|                                 output_formatted("%02x", c); |  | ||||||
|                             } else { |  | ||||||
|                                 output_formatted("%04x", c); |  | ||||||
|                             } |  | ||||||
|                             *m_out += '%'; |  | ||||||
|                         } |  | ||||||
|                     } |  | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void write_meta(const osmium::OSMObject& object) { |                 void write_meta(const osmium::OSMObject& object) { | ||||||
|                     output_formatted("%" PRId64, object.id()); |                     output_formatted("%" PRId64, object.id()); | ||||||
|                     if (m_add_metadata) { |                     if (m_options.add_metadata) { | ||||||
|                         output_formatted(" v%d d", object.version()); |                         output_formatted(" v%d d", object.version()); | ||||||
|                         *m_out += (object.visible() ? 'V' : 'D'); |                         *m_out += (object.visible() ? 'V' : 'D'); | ||||||
|                         output_formatted(" c%d t", object.changeset()); |                         output_formatted(" c%d t", object.changeset()); | ||||||
| @ -160,7 +111,7 @@ namespace osmium { | |||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void write_location(const osmium::Location location, const char x, const char y) { |                 void write_location(const osmium::Location& location, const char x, const char y) { | ||||||
|                     if (location) { |                     if (location) { | ||||||
|                         output_formatted(" %c%.7f %c%.7f", x, location.lon_without_check(), y, location.lat_without_check()); |                         output_formatted(" %c%.7f %c%.7f", x, location.lon_without_check(), y, location.lat_without_check()); | ||||||
|                     } else { |                     } else { | ||||||
| @ -173,11 +124,9 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|             public: |             public: | ||||||
| 
 | 
 | ||||||
|                 explicit OPLOutputBlock(osmium::memory::Buffer&& buffer, bool add_metadata) : |                 OPLOutputBlock(osmium::memory::Buffer&& buffer, const opl_output_options& options) : | ||||||
|                     m_input_buffer(std::make_shared<osmium::memory::Buffer>(std::move(buffer))), |                     OutputBlock(std::move(buffer)), | ||||||
|                     m_out(std::make_shared<std::string>()), |                     m_options(options) { | ||||||
|                     m_tmp_buffer(), |  | ||||||
|                     m_add_metadata(add_metadata) { |  | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 OPLOutputBlock(const OPLOutputBlock&) = default; |                 OPLOutputBlock(const OPLOutputBlock&) = default; | ||||||
| @ -186,13 +135,15 @@ namespace osmium { | |||||||
|                 OPLOutputBlock(OPLOutputBlock&&) = default; |                 OPLOutputBlock(OPLOutputBlock&&) = default; | ||||||
|                 OPLOutputBlock& operator=(OPLOutputBlock&&) = default; |                 OPLOutputBlock& operator=(OPLOutputBlock&&) = default; | ||||||
| 
 | 
 | ||||||
|                 ~OPLOutputBlock() = default; |                 ~OPLOutputBlock() noexcept = default; | ||||||
| 
 | 
 | ||||||
|                 std::string operator()() { |                 std::string operator()() { | ||||||
|                     osmium::apply(m_input_buffer->cbegin(), m_input_buffer->cend(), *this); |                     osmium::apply(m_input_buffer->cbegin(), m_input_buffer->cend(), *this); | ||||||
| 
 | 
 | ||||||
|                     std::string out; |                     std::string out; | ||||||
|                     std::swap(out, *m_out); |                     using std::swap; | ||||||
|  |                     swap(out, *m_out); | ||||||
|  | 
 | ||||||
|                     return out; |                     return out; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
| @ -244,7 +195,7 @@ namespace osmium { | |||||||
|                     *m_out += changeset.created_at().to_iso(); |                     *m_out += changeset.created_at().to_iso(); | ||||||
|                     *m_out += " e"; |                     *m_out += " e"; | ||||||
|                     *m_out += changeset.closed_at().to_iso(); |                     *m_out += changeset.closed_at().to_iso(); | ||||||
|                     output_formatted(" i%d u", changeset.uid()); |                     output_formatted(" d%d i%d u", changeset.num_comments(), changeset.uid()); | ||||||
|                     append_encoded_string(changeset.user()); |                     append_encoded_string(changeset.user()); | ||||||
|                     write_location(changeset.bounds().bottom_left(), 'x', 'y'); |                     write_location(changeset.bounds().bottom_left(), 'x', 'y'); | ||||||
|                     write_location(changeset.bounds().top_right(), 'X', 'Y'); |                     write_location(changeset.bounds().top_right(), 'X', 'Y'); | ||||||
| @ -264,48 +215,42 @@ namespace osmium { | |||||||
|                     *m_out += '\n'; |                     *m_out += '\n'; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|             }; // OPLOutputBlock
 |             }; // class OPLOutputBlock
 | ||||||
| 
 | 
 | ||||||
|             class OPLOutputFormat : public osmium::io::detail::OutputFormat { |             class OPLOutputFormat : public osmium::io::detail::OutputFormat { | ||||||
| 
 | 
 | ||||||
|                 bool m_add_metadata; |                 opl_output_options m_options; | ||||||
| 
 | 
 | ||||||
|             public: |             public: | ||||||
| 
 | 
 | ||||||
|                 OPLOutputFormat(const osmium::io::File& file, data_queue_type& output_queue) : |                 OPLOutputFormat(const osmium::io::File& file, future_string_queue_type& output_queue) : | ||||||
|                     OutputFormat(file, output_queue), |                     OutputFormat(output_queue), | ||||||
|                     m_add_metadata(file.get("add_metadata") != "false") { |                     m_options() { | ||||||
|  |                     m_options.add_metadata = file.is_not_false("add_metadata"); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 OPLOutputFormat(const OPLOutputFormat&) = delete; |                 OPLOutputFormat(const OPLOutputFormat&) = delete; | ||||||
|                 OPLOutputFormat& operator=(const OPLOutputFormat&) = delete; |                 OPLOutputFormat& operator=(const OPLOutputFormat&) = delete; | ||||||
| 
 | 
 | ||||||
|                 void write_buffer(osmium::memory::Buffer&& buffer) override final { |                 ~OPLOutputFormat() noexcept final = default; | ||||||
|                     m_output_queue.push(osmium::thread::Pool::instance().submit(OPLOutputBlock{std::move(buffer), m_add_metadata})); |  | ||||||
|                 } |  | ||||||
| 
 | 
 | ||||||
|                 void close() override final { |                 void write_buffer(osmium::memory::Buffer&& buffer) final { | ||||||
|                     std::string out; |                     m_output_queue.push(osmium::thread::Pool::instance().submit(OPLOutputBlock{std::move(buffer), m_options})); | ||||||
|                     std::promise<std::string> promise; |  | ||||||
|                     m_output_queue.push(promise.get_future()); |  | ||||||
|                     promise.set_value(out); |  | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|             }; // class OPLOutputFormat
 |             }; // class OPLOutputFormat
 | ||||||
| 
 | 
 | ||||||
|             namespace { |             // we want the register_output_format() function to run, setting
 | ||||||
|  |             // the variable is only a side-effect, it will never be used
 | ||||||
|  |             const bool registered_opl_output = osmium::io::detail::OutputFormatFactory::instance().register_output_format(osmium::io::file_format::opl, | ||||||
|  |                 [](const osmium::io::File& file, future_string_queue_type& output_queue) { | ||||||
|  |                     return new osmium::io::detail::OPLOutputFormat(file, output_queue); | ||||||
|  |             }); | ||||||
| 
 | 
 | ||||||
| // we want the register_output_format() function to run, setting the variable
 |             // dummy function to silence the unused variable warning from above
 | ||||||
| // is only a side-effect, it will never be used
 |             inline bool get_registered_opl_output() noexcept { | ||||||
| #pragma GCC diagnostic push |                 return registered_opl_output; | ||||||
| #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 detail
 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -34,29 +34,48 @@ DEALINGS IN THE SOFTWARE. | |||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| #include <functional> | #include <functional> | ||||||
| #include <future> |  | ||||||
| #include <map> | #include <map> | ||||||
| #include <memory> | #include <memory> | ||||||
| #include <stdexcept> | #include <stdexcept> | ||||||
| #include <string> | #include <string> | ||||||
| #include <utility> | #include <utility> | ||||||
| 
 | 
 | ||||||
|  | #include <osmium/handler.hpp> | ||||||
|  | #include <osmium/io/detail/queue_util.hpp> | ||||||
|  | #include <osmium/io/detail/string_util.hpp> | ||||||
| #include <osmium/io/file.hpp> | #include <osmium/io/file.hpp> | ||||||
| #include <osmium/io/file_format.hpp> | #include <osmium/io/file_format.hpp> | ||||||
| #include <osmium/io/header.hpp> | #include <osmium/memory/buffer.hpp> | ||||||
| #include <osmium/thread/queue.hpp> |  | ||||||
| 
 | 
 | ||||||
| namespace osmium { | namespace osmium { | ||||||
| 
 | 
 | ||||||
|     namespace memory { |     namespace io { | ||||||
|         class Buffer; |         class Header; | ||||||
|     } |     } // namespace io
 | ||||||
| 
 | 
 | ||||||
|     namespace io { |     namespace io { | ||||||
| 
 | 
 | ||||||
|         namespace detail { |         namespace detail { | ||||||
| 
 | 
 | ||||||
|             typedef osmium::thread::Queue<std::future<std::string>> data_queue_type; |             class OutputBlock : public osmium::handler::Handler { | ||||||
|  | 
 | ||||||
|  |             protected: | ||||||
|  | 
 | ||||||
|  |                 std::shared_ptr<osmium::memory::Buffer> m_input_buffer; | ||||||
|  | 
 | ||||||
|  |                 std::shared_ptr<std::string> m_out; | ||||||
|  | 
 | ||||||
|  |                 explicit OutputBlock(osmium::memory::Buffer&& buffer) : | ||||||
|  |                     m_input_buffer(std::make_shared<osmium::memory::Buffer>(std::move(buffer))), | ||||||
|  |                     m_out(std::make_shared<std::string>()) { | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 template <typename... TArgs> | ||||||
|  |                 void output_formatted(const char* format, TArgs&&... args) { | ||||||
|  |                     append_printf_formatted_string(*m_out, format, std::forward<TArgs>(args)...); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |             }; // class OutputBlock;
 | ||||||
| 
 | 
 | ||||||
|             /**
 |             /**
 | ||||||
|              * Virtual base class for all classes writing OSM files in different |              * Virtual base class for all classes writing OSM files in different | ||||||
| @ -69,13 +88,19 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|             protected: |             protected: | ||||||
| 
 | 
 | ||||||
|                 osmium::io::File m_file; |                 future_string_queue_type& m_output_queue; | ||||||
|                 data_queue_type& m_output_queue; | 
 | ||||||
|  |                 /**
 | ||||||
|  |                  * Wrap the string into a future and add it to the output | ||||||
|  |                  * queue. | ||||||
|  |                  */ | ||||||
|  |                 void send_to_output_queue(std::string&& data) { | ||||||
|  |                     add_to_queue(m_output_queue, std::move(data)); | ||||||
|  |                 } | ||||||
| 
 | 
 | ||||||
|             public: |             public: | ||||||
| 
 | 
 | ||||||
|                 explicit OutputFormat(const osmium::io::File& file, data_queue_type& output_queue) : |                 explicit OutputFormat(future_string_queue_type& output_queue) : | ||||||
|                     m_file(file), |  | ||||||
|                     m_output_queue(output_queue) { |                     m_output_queue(output_queue) { | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
| @ -85,15 +110,15 @@ namespace osmium { | |||||||
|                 OutputFormat& operator=(const OutputFormat&) = delete; |                 OutputFormat& operator=(const OutputFormat&) = delete; | ||||||
|                 OutputFormat& operator=(OutputFormat&&) = delete; |                 OutputFormat& operator=(OutputFormat&&) = delete; | ||||||
| 
 | 
 | ||||||
|                 virtual ~OutputFormat() { |                 virtual ~OutputFormat() noexcept = default; | ||||||
|                 } |  | ||||||
| 
 | 
 | ||||||
|                 virtual void write_header(const osmium::io::Header&) { |                 virtual void write_header(const osmium::io::Header&) { | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 virtual void write_buffer(osmium::memory::Buffer&&) = 0; |                 virtual void write_buffer(osmium::memory::Buffer&&) = 0; | ||||||
| 
 | 
 | ||||||
|                 virtual void close() = 0; |                 virtual void write_end() { | ||||||
|  |                 } | ||||||
| 
 | 
 | ||||||
|             }; // class OutputFormat
 |             }; // class OutputFormat
 | ||||||
| 
 | 
 | ||||||
| @ -108,7 +133,7 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|             public: |             public: | ||||||
| 
 | 
 | ||||||
|                 typedef std::function<osmium::io::detail::OutputFormat*(const osmium::io::File&, data_queue_type&)> create_output_type; |                 typedef std::function<osmium::io::detail::OutputFormat*(const osmium::io::File&, future_string_queue_type&)> create_output_type; | ||||||
| 
 | 
 | ||||||
|             private: |             private: | ||||||
| 
 | 
 | ||||||
| @ -134,15 +159,18 @@ namespace osmium { | |||||||
|                     return true; |                     return true; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 std::unique_ptr<osmium::io::detail::OutputFormat> create_output(const osmium::io::File& file, data_queue_type& output_queue) { |                 std::unique_ptr<osmium::io::detail::OutputFormat> create_output(const osmium::io::File& file, future_string_queue_type& output_queue) { | ||||||
|                     file.check(); |  | ||||||
| 
 |  | ||||||
|                     auto it = m_callbacks.find(file.format()); |                     auto it = m_callbacks.find(file.format()); | ||||||
|                     if (it != m_callbacks.end()) { |                     if (it != m_callbacks.end()) { | ||||||
|                         return std::unique_ptr<osmium::io::detail::OutputFormat>((it->second)(file, output_queue)); |                         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."); |                     throw unsupported_file_format_error( | ||||||
|  |                                 std::string("Can not open file '") + | ||||||
|  |                                 file.filename() + | ||||||
|  |                                 "' with type '" + | ||||||
|  |                                 as_string(file.format()) + | ||||||
|  |                                 "'. No support for writing this format in this program."); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|             }; // class OutputFormatFactory
 |             }; // class OutputFormatFactory
 | ||||||
|  | |||||||
| @ -33,6 +33,7 @@ DEALINGS IN THE SOFTWARE. | |||||||
| 
 | 
 | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
|  | #include <cstdint> | ||||||
| #include <string> | #include <string> | ||||||
| 
 | 
 | ||||||
| // needed for htonl and ntohl
 | // needed for htonl and ntohl
 | ||||||
| @ -53,11 +54,11 @@ namespace osmium { | |||||||
|      */ |      */ | ||||||
|     struct pbf_error : public io_error { |     struct pbf_error : public io_error { | ||||||
| 
 | 
 | ||||||
|         pbf_error(const std::string& what) : |         explicit pbf_error(const std::string& what) : | ||||||
|             io_error(std::string("PBF error: ") + what) { |             io_error(std::string("PBF error: ") + what) { | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         pbf_error(const char* what) : |         explicit pbf_error(const char* what) : | ||||||
|             io_error(std::string("PBF error: ") + what) { |             io_error(std::string("PBF error: ") + what) { | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| @ -79,9 +80,9 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|             const int64_t resolution_convert = lonlat_resolution / osmium::Location::coordinate_precision; |             const int64_t resolution_convert = lonlat_resolution / osmium::Location::coordinate_precision; | ||||||
| 
 | 
 | ||||||
|         } |         } // namespace detail
 | ||||||
| 
 | 
 | ||||||
|     } |     } // namespace io
 | ||||||
| 
 | 
 | ||||||
| } // namespace osmium
 | } // namespace osmium
 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -37,8 +37,12 @@ DEALINGS IN THE SOFTWARE. | |||||||
| #include <cstdint> | #include <cstdint> | ||||||
| #include <cstring> | #include <cstring> | ||||||
| #include <algorithm> | #include <algorithm> | ||||||
| #include <iterator> |  | ||||||
| #include <limits> | #include <limits> | ||||||
|  | #include <memory> | ||||||
|  | #include <stdexcept> | ||||||
|  | #include <string> | ||||||
|  | #include <utility> | ||||||
|  | #include <vector> | ||||||
| 
 | 
 | ||||||
| #include <protozero/pbf_message.hpp> | #include <protozero/pbf_message.hpp> | ||||||
| 
 | 
 | ||||||
| @ -62,13 +66,14 @@ namespace osmium { | |||||||
|         namespace detail { |         namespace detail { | ||||||
| 
 | 
 | ||||||
|             using ptr_len_type = std::pair<const char*, size_t>; |             using ptr_len_type = std::pair<const char*, size_t>; | ||||||
|  |             using osm_string_len_type = std::pair<const char*, osmium::string_size_type>; | ||||||
| 
 | 
 | ||||||
|             class PBFPrimitiveBlockDecoder { |             class PBFPrimitiveBlockDecoder { | ||||||
| 
 | 
 | ||||||
|                 static constexpr size_t initial_buffer_size = 2 * 1024 * 1024; |                 static constexpr size_t initial_buffer_size = 2 * 1024 * 1024; | ||||||
| 
 | 
 | ||||||
|                 ptr_len_type m_data; |                 ptr_len_type m_data; | ||||||
|                 std::vector<ptr_len_type> m_stringtable; |                 std::vector<osm_string_len_type> m_stringtable; | ||||||
| 
 | 
 | ||||||
|                 int64_t m_lon_offset = 0; |                 int64_t m_lon_offset = 0; | ||||||
|                 int64_t m_lat_offset = 0; |                 int64_t m_lat_offset = 0; | ||||||
| @ -86,7 +91,11 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|                     protozero::pbf_message<OSMFormat::StringTable> pbf_string_table(data); |                     protozero::pbf_message<OSMFormat::StringTable> pbf_string_table(data); | ||||||
|                     while (pbf_string_table.next(OSMFormat::StringTable::repeated_bytes_s)) { |                     while (pbf_string_table.next(OSMFormat::StringTable::repeated_bytes_s)) { | ||||||
|                         m_stringtable.push_back(pbf_string_table.get_data()); |                         auto str_len = pbf_string_table.get_data(); | ||||||
|  |                         if (str_len.second > osmium::max_osm_string_length) { | ||||||
|  |                             throw osmium::pbf_error("overlong string in string table"); | ||||||
|  |                         } | ||||||
|  |                         m_stringtable.emplace_back(str_len.first, osmium::string_size_type(str_len.second)); | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
| @ -156,8 +165,8 @@ namespace osmium { | |||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 ptr_len_type decode_info(const ptr_len_type& data, osmium::OSMObject& object) { |                 osm_string_len_type decode_info(const ptr_len_type& data, osmium::OSMObject& object) { | ||||||
|                     ptr_len_type user = std::make_pair("", 0); |                     osm_string_len_type user = std::make_pair("", 0); | ||||||
| 
 | 
 | ||||||
|                     protozero::pbf_message<OSMFormat::Info> pbf_info(data); |                     protozero::pbf_message<OSMFormat::Info> pbf_info(data); | ||||||
|                     while (pbf_info.next()) { |                     while (pbf_info.next()) { | ||||||
| @ -220,7 +229,7 @@ namespace osmium { | |||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 int32_t convert_pbf_coordinate(int64_t c) const { |                 int32_t convert_pbf_coordinate(int64_t c) const { | ||||||
|                     return (c * m_granularity + m_lon_offset) / resolution_convert; |                     return int32_t((c * m_granularity + m_lon_offset) / resolution_convert); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void decode_node(const ptr_len_type& data) { |                 void decode_node(const ptr_len_type& data) { | ||||||
| @ -232,7 +241,7 @@ namespace osmium { | |||||||
|                     int64_t lon = std::numeric_limits<int64_t>::max(); |                     int64_t lon = std::numeric_limits<int64_t>::max(); | ||||||
|                     int64_t lat = std::numeric_limits<int64_t>::max(); |                     int64_t lat = std::numeric_limits<int64_t>::max(); | ||||||
| 
 | 
 | ||||||
|                     ptr_len_type user = { "", 0 }; |                     osm_string_len_type user = { "", 0 }; | ||||||
| 
 | 
 | ||||||
|                     protozero::pbf_message<OSMFormat::Node> pbf_node(data); |                     protozero::pbf_message<OSMFormat::Node> pbf_node(data); | ||||||
|                     while (pbf_node.next()) { |                     while (pbf_node.next()) { | ||||||
| @ -285,7 +294,7 @@ namespace osmium { | |||||||
|                     kv_type vals; |                     kv_type vals; | ||||||
|                     std::pair<protozero::pbf_reader::const_sint64_iterator, protozero::pbf_reader::const_sint64_iterator> refs; |                     std::pair<protozero::pbf_reader::const_sint64_iterator, protozero::pbf_reader::const_sint64_iterator> refs; | ||||||
| 
 | 
 | ||||||
|                     ptr_len_type user = { "", 0 }; |                     osm_string_len_type user = { "", 0 }; | ||||||
| 
 | 
 | ||||||
|                     protozero::pbf_message<OSMFormat::Way> pbf_way(data); |                     protozero::pbf_message<OSMFormat::Way> pbf_way(data); | ||||||
|                     while (pbf_way.next()) { |                     while (pbf_way.next()) { | ||||||
| @ -334,7 +343,7 @@ namespace osmium { | |||||||
|                     std::pair<protozero::pbf_reader::const_sint64_iterator, protozero::pbf_reader::const_sint64_iterator> refs; |                     std::pair<protozero::pbf_reader::const_sint64_iterator, protozero::pbf_reader::const_sint64_iterator> refs; | ||||||
|                     std::pair<protozero::pbf_reader::const_int32_iterator,  protozero::pbf_reader::const_int32_iterator> types; |                     std::pair<protozero::pbf_reader::const_int32_iterator,  protozero::pbf_reader::const_int32_iterator> types; | ||||||
| 
 | 
 | ||||||
|                     ptr_len_type user = { "", 0 }; |                     osm_string_len_type user = { "", 0 }; | ||||||
| 
 | 
 | ||||||
|                     protozero::pbf_message<OSMFormat::Relation> pbf_relation(data); |                     protozero::pbf_message<OSMFormat::Relation> pbf_relation(data); | ||||||
|                     while (pbf_relation.next()) { |                     while (pbf_relation.next()) { | ||||||
| @ -512,7 +521,7 @@ namespace osmium { | |||||||
|                                     // this is against the spec, must have same number of elements
 |                                     // this is against the spec, must have same number of elements
 | ||||||
|                                     throw osmium::pbf_error("PBF format error"); |                                     throw osmium::pbf_error("PBF format error"); | ||||||
|                                 } |                                 } | ||||||
|                                 visible = *visibles.first++; |                                 visible = (*visibles.first++) != 0; | ||||||
|                             } |                             } | ||||||
|                             node.set_visible(visible); |                             node.set_visible(visible); | ||||||
| 
 | 
 | ||||||
| @ -522,10 +531,14 @@ namespace osmium { | |||||||
|                             builder.add_user(""); |                             builder.add_user(""); | ||||||
|                         } |                         } | ||||||
| 
 | 
 | ||||||
|  |                         // even if the node isn't visible, there's still a record
 | ||||||
|  |                         // of its lat/lon in the dense arrays.
 | ||||||
|  |                         const auto lon = dense_longitude.update(*lons.first++); | ||||||
|  |                         const auto lat = dense_latitude.update(*lats.first++); | ||||||
|                         if (visible) { |                         if (visible) { | ||||||
|                             builder.object().set_location(osmium::Location( |                             builder.object().set_location(osmium::Location( | ||||||
|                                     convert_pbf_coordinate(dense_longitude.update(*lons.first++)), |                                     convert_pbf_coordinate(lon), | ||||||
|                                     convert_pbf_coordinate(dense_latitude.update(*lats.first++)) |                                     convert_pbf_coordinate(lat) | ||||||
|                             )); |                             )); | ||||||
|                         } |                         } | ||||||
| 
 | 
 | ||||||
| @ -552,7 +565,7 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|             public: |             public: | ||||||
| 
 | 
 | ||||||
|                 explicit PBFPrimitiveBlockDecoder(const ptr_len_type& data, osmium::osm_entity_bits::type read_types) : |                 PBFPrimitiveBlockDecoder(const ptr_len_type& data, osmium::osm_entity_bits::type read_types) : | ||||||
|                     m_data(data), |                     m_data(data), | ||||||
|                     m_read_types(read_types) { |                     m_read_types(read_types) { | ||||||
|                 } |                 } | ||||||
| @ -563,7 +576,7 @@ namespace osmium { | |||||||
|                 PBFPrimitiveBlockDecoder(PBFPrimitiveBlockDecoder&&) = delete; |                 PBFPrimitiveBlockDecoder(PBFPrimitiveBlockDecoder&&) = delete; | ||||||
|                 PBFPrimitiveBlockDecoder& operator=(PBFPrimitiveBlockDecoder&&) = delete; |                 PBFPrimitiveBlockDecoder& operator=(PBFPrimitiveBlockDecoder&&) = delete; | ||||||
| 
 | 
 | ||||||
|                 ~PBFPrimitiveBlockDecoder() = default; |                 ~PBFPrimitiveBlockDecoder() noexcept = default; | ||||||
| 
 | 
 | ||||||
|                 osmium::memory::Buffer operator()() { |                 osmium::memory::Buffer operator()() { | ||||||
|                     try { |                     try { | ||||||
| @ -579,8 +592,8 @@ namespace osmium { | |||||||
|             }; // class PBFPrimitiveBlockDecoder
 |             }; // class PBFPrimitiveBlockDecoder
 | ||||||
| 
 | 
 | ||||||
|             inline ptr_len_type decode_blob(const std::string& blob_data, std::string& output) { |             inline ptr_len_type decode_blob(const std::string& blob_data, std::string& output) { | ||||||
|                 int32_t raw_size; |                 int32_t raw_size = 0; | ||||||
|                 std::pair<const char*, protozero::pbf_length_type> zlib_data; |                 std::pair<const char*, protozero::pbf_length_type> zlib_data = {nullptr, 0}; | ||||||
| 
 | 
 | ||||||
|                 protozero::pbf_message<FileFormat::Blob> pbf_blob(blob_data); |                 protozero::pbf_message<FileFormat::Blob> pbf_blob(blob_data); | ||||||
|                 while (pbf_blob.next()) { |                 while (pbf_blob.next()) { | ||||||
| @ -609,7 +622,7 @@ namespace osmium { | |||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 if (zlib_data.second != 0) { |                 if (zlib_data.second != 0 && raw_size != 0) { | ||||||
|                     return osmium::io::detail::zlib_uncompress_string( |                     return osmium::io::detail::zlib_uncompress_string( | ||||||
|                         zlib_data.first, |                         zlib_data.first, | ||||||
|                         static_cast<unsigned long>(zlib_data.second), |                         static_cast<unsigned long>(zlib_data.second), | ||||||
| @ -694,7 +707,11 @@ namespace osmium { | |||||||
|                             header.set("generator", pbf_header_block.get_string()); |                             header.set("generator", pbf_header_block.get_string()); | ||||||
|                             break; |                             break; | ||||||
|                         case OSMFormat::HeaderBlock::optional_int64_osmosis_replication_timestamp: |                         case OSMFormat::HeaderBlock::optional_int64_osmosis_replication_timestamp: | ||||||
|                             header.set("osmosis_replication_timestamp", osmium::Timestamp(pbf_header_block.get_int64()).to_iso()); |                             { | ||||||
|  |                                 auto timestamp = osmium::Timestamp(pbf_header_block.get_int64()).to_iso(); | ||||||
|  |                                 header.set("osmosis_replication_timestamp", timestamp); | ||||||
|  |                                 header.set("timestamp", timestamp); | ||||||
|  |                             } | ||||||
|                             break; |                             break; | ||||||
|                         case OSMFormat::HeaderBlock::optional_int64_osmosis_replication_sequence_number: |                         case OSMFormat::HeaderBlock::optional_int64_osmosis_replication_sequence_number: | ||||||
|                             header.set("osmosis_replication_sequence_number", std::to_string(pbf_header_block.get_int64())); |                             header.set("osmosis_replication_sequence_number", std::to_string(pbf_header_block.get_int64())); | ||||||
| @ -741,7 +758,7 @@ namespace osmium { | |||||||
|                 PBFDataBlobDecoder(PBFDataBlobDecoder&&) = default; |                 PBFDataBlobDecoder(PBFDataBlobDecoder&&) = default; | ||||||
|                 PBFDataBlobDecoder& operator=(PBFDataBlobDecoder&&) = default; |                 PBFDataBlobDecoder& operator=(PBFDataBlobDecoder&&) = default; | ||||||
| 
 | 
 | ||||||
|                 ~PBFDataBlobDecoder() = default; |                 ~PBFDataBlobDecoder() noexcept = default; | ||||||
| 
 | 
 | ||||||
|                 osmium::memory::Buffer operator()() { |                 osmium::memory::Buffer operator()() { | ||||||
|                     std::string output; |                     std::string output; | ||||||
|  | |||||||
| @ -34,17 +34,12 @@ DEALINGS IN THE SOFTWARE. | |||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| #include <algorithm> | #include <algorithm> | ||||||
| #include <atomic> |  | ||||||
| #include <cassert> | #include <cassert> | ||||||
| #include <chrono> |  | ||||||
| #include <cstddef> | #include <cstddef> | ||||||
| #include <cstdint> | #include <cstdint> | ||||||
| #include <cstring> | #include <cstring> | ||||||
| #include <future> |  | ||||||
| #include <memory> | #include <memory> | ||||||
| #include <ratio> |  | ||||||
| #include <sstream> | #include <sstream> | ||||||
| #include <stdexcept> |  | ||||||
| #include <string> | #include <string> | ||||||
| #include <thread> | #include <thread> | ||||||
| #include <type_traits> | #include <type_traits> | ||||||
| @ -58,40 +53,22 @@ DEALINGS IN THE SOFTWARE. | |||||||
| #include <osmium/io/error.hpp> | #include <osmium/io/error.hpp> | ||||||
| #include <osmium/io/file.hpp> | #include <osmium/io/file.hpp> | ||||||
| #include <osmium/io/file_format.hpp> | #include <osmium/io/file_format.hpp> | ||||||
| #include <osmium/memory/buffer.hpp> |  | ||||||
| #include <osmium/osm.hpp> | #include <osmium/osm.hpp> | ||||||
| #include <osmium/osm/box.hpp> |  | ||||||
| #include <osmium/osm/entity_bits.hpp> | #include <osmium/osm/entity_bits.hpp> | ||||||
| #include <osmium/osm/location.hpp> |  | ||||||
| #include <osmium/osm/object.hpp> | #include <osmium/osm/object.hpp> | ||||||
| #include <osmium/osm/timestamp.hpp> | #include <osmium/osm/timestamp.hpp> | ||||||
| #include <osmium/thread/pool.hpp> | #include <osmium/thread/pool.hpp> | ||||||
| #include <osmium/thread/queue.hpp> |  | ||||||
| #include <osmium/thread/util.hpp> | #include <osmium/thread/util.hpp> | ||||||
| #include <osmium/util/cast.hpp> |  | ||||||
| #include <osmium/util/config.hpp> | #include <osmium/util/config.hpp> | ||||||
| 
 | 
 | ||||||
| namespace osmium { | namespace osmium { | ||||||
| 
 | 
 | ||||||
|     namespace io { |     namespace io { | ||||||
| 
 | 
 | ||||||
|         class File; |  | ||||||
| 
 |  | ||||||
|         namespace detail { |         namespace detail { | ||||||
| 
 | 
 | ||||||
|             /**
 |             class PBFParser : public Parser { | ||||||
|              * Class for parsing PBF files. |  | ||||||
|              */ |  | ||||||
|             class PBFInputFormat : public osmium::io::detail::InputFormat { |  | ||||||
| 
 | 
 | ||||||
|                 typedef osmium::thread::Queue<std::future<osmium::memory::Buffer>> queue_type; |  | ||||||
| 
 |  | ||||||
|                 bool m_use_thread_pool; |  | ||||||
|                 bool m_eof { false }; |  | ||||||
|                 queue_type m_queue; |  | ||||||
|                 std::atomic<bool> m_quit_input_thread; |  | ||||||
|                 std::thread m_reader; |  | ||||||
|                 osmium::thread::Queue<std::string>& m_input_queue; |  | ||||||
|                 std::string m_input_buffer; |                 std::string m_input_buffer; | ||||||
| 
 | 
 | ||||||
|                 /**
 |                 /**
 | ||||||
| @ -103,9 +80,8 @@ namespace osmium { | |||||||
|                  */ |                  */ | ||||||
|                 std::string read_from_input_queue(size_t size) { |                 std::string read_from_input_queue(size_t size) { | ||||||
|                     while (m_input_buffer.size() < size) { |                     while (m_input_buffer.size() < size) { | ||||||
|                         std::string new_data; |                         std::string new_data = get_input(); | ||||||
|                         m_input_queue.wait_and_pop(new_data); |                         if (input_done()) { | ||||||
|                         if (new_data.empty()) { |  | ||||||
|                             throw osmium::pbf_error("truncated data (EOF encountered)"); |                             throw osmium::pbf_error("truncated data (EOF encountered)"); | ||||||
|                         } |                         } | ||||||
|                         m_input_buffer += new_data; |                         m_input_buffer += new_data; | ||||||
| @ -113,7 +89,10 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|                     std::string output { m_input_buffer.substr(size) }; |                     std::string output { m_input_buffer.substr(size) }; | ||||||
|                     m_input_buffer.resize(size); |                     m_input_buffer.resize(size); | ||||||
|                     std::swap(output, m_input_buffer); | 
 | ||||||
|  |                     using std::swap; | ||||||
|  |                     swap(output, m_input_buffer); | ||||||
|  | 
 | ||||||
|                     return output; |                     return output; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
| @ -125,7 +104,7 @@ namespace osmium { | |||||||
|                     uint32_t size_in_network_byte_order; |                     uint32_t size_in_network_byte_order; | ||||||
| 
 | 
 | ||||||
|                     try { |                     try { | ||||||
|                         std::string input_data = read_from_input_queue(sizeof(size_in_network_byte_order)); |                         const 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()); |                         size_in_network_byte_order = *reinterpret_cast<const uint32_t*>(input_data.data()); | ||||||
|                     } catch (osmium::pbf_error&) { |                     } catch (osmium::pbf_error&) { | ||||||
|                         return 0; // EOF
 |                         return 0; // EOF
 | ||||||
| @ -174,125 +153,85 @@ namespace osmium { | |||||||
|                 size_t check_type_and_get_blob_size(const char* expected_type) { |                 size_t check_type_and_get_blob_size(const char* expected_type) { | ||||||
|                     assert(expected_type); |                     assert(expected_type); | ||||||
| 
 | 
 | ||||||
|                     auto size = read_blob_header_size_from_file(); |                     const auto size = read_blob_header_size_from_file(); | ||||||
|                     if (size == 0) { // EOF
 |                     if (size == 0) { // EOF
 | ||||||
|                         return 0; |                         return 0; | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                     std::string blob_header = read_from_input_queue(size); |                     const std::string blob_header = read_from_input_queue(size); | ||||||
| 
 | 
 | ||||||
|                     return decode_blob_header(protozero::pbf_message<FileFormat::BlobHeader>(blob_header), expected_type); |                     return decode_blob_header(protozero::pbf_message<FileFormat::BlobHeader>(blob_header), expected_type); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void parse_osm_data(osmium::osm_entity_bits::type read_types) { |                 std::string read_from_input_queue_with_check(size_t size) { | ||||||
|                     osmium::thread::set_thread_name("_osmium_pbf_in"); |                     if (size > max_uncompressed_blob_size) { | ||||||
| 
 |                         throw osmium::pbf_error(std::string("invalid blob size: " + | ||||||
|                     while (auto size = check_type_and_get_blob_size("OSMData")) { |                                                 std::to_string(size))); | ||||||
|                         std::string input_buffer = read_from_input_queue(size); |  | ||||||
|                         if (input_buffer.size() > max_uncompressed_blob_size) { |  | ||||||
|                             throw osmium::pbf_error(std::string("invalid blob size: " + std::to_string(input_buffer.size()))); |  | ||||||
|                         } |  | ||||||
| 
 |  | ||||||
|                         if (m_use_thread_pool) { |  | ||||||
|                             m_queue.push(osmium::thread::Pool::instance().submit(PBFDataBlobDecoder{ std::move(input_buffer), read_types })); |  | ||||||
|                         } else { |  | ||||||
|                             std::promise<osmium::memory::Buffer> promise; |  | ||||||
|                             m_queue.push(promise.get_future()); |  | ||||||
|                             PBFDataBlobDecoder data_blob_parser{ std::move(input_buffer), read_types }; |  | ||||||
|                             promise.set_value(data_blob_parser()); |  | ||||||
|                         } |  | ||||||
| 
 |  | ||||||
|                         if (m_quit_input_thread) { |  | ||||||
|                             return; |  | ||||||
|                         } |  | ||||||
|                     } |                     } | ||||||
| 
 |                     return read_from_input_queue(size); | ||||||
|                     // Send an empty buffer to signal the reader that we are
 |  | ||||||
|                     // done.
 |  | ||||||
|                     std::promise<osmium::memory::Buffer> promise; |  | ||||||
|                     m_queue.push(promise.get_future()); |  | ||||||
|                     promise.set_value(osmium::memory::Buffer{}); |  | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void signal_input_thread_to_quit() { |                 // Parse the header in the PBF OSMHeader blob.
 | ||||||
|                     m_quit_input_thread = true; |                 void parse_header_blob() { | ||||||
|  |                     osmium::io::Header header; | ||||||
|  |                     const auto size = check_type_and_get_blob_size("OSMHeader"); | ||||||
|  |                     header = decode_header(read_from_input_queue_with_check(size)); | ||||||
|  |                     set_header_value(header); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 void parse_data_blobs() { | ||||||
|  |                     while (const auto size = check_type_and_get_blob_size("OSMData")) { | ||||||
|  |                         std::string input_buffer = read_from_input_queue_with_check(size); | ||||||
|  | 
 | ||||||
|  |                         PBFDataBlobDecoder data_blob_parser{ std::move(input_buffer), read_types() }; | ||||||
|  | 
 | ||||||
|  |                         if (osmium::config::use_pool_threads_for_pbf_parsing()) { | ||||||
|  |                             send_to_output_queue(osmium::thread::Pool::instance().submit(std::move(data_blob_parser))); | ||||||
|  |                         } else { | ||||||
|  |                             send_to_output_queue(data_blob_parser()); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|             public: |             public: | ||||||
| 
 | 
 | ||||||
|                 /**
 |                 PBFParser(future_string_queue_type& input_queue, | ||||||
|                  * Instantiate PBF Parser |                           future_buffer_queue_type& output_queue, | ||||||
|                  * |                           std::promise<osmium::io::Header>& header_promise, | ||||||
|                  * @param file osmium::io::File instance describing file to be read from. |                           osmium::osm_entity_bits::type read_types) : | ||||||
|                  * @param read_which_entities Which types of OSM entities (nodes, ways, relations, changesets) should be parsed? |                     Parser(input_queue, output_queue, header_promise, read_types), | ||||||
|                  * @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), |  | ||||||
|                     m_use_thread_pool(osmium::config::use_pool_threads_for_pbf_parsing()), |  | ||||||
|                     m_queue(20, "pbf_parser_results"), // XXX
 |  | ||||||
|                     m_quit_input_thread(false), |  | ||||||
|                     m_input_queue(input_queue), |  | ||||||
|                     m_input_buffer() { |                     m_input_buffer() { | ||||||
|  |                 } | ||||||
| 
 | 
 | ||||||
|                     // handle OSMHeader
 |                 ~PBFParser() noexcept final = default; | ||||||
|                     const auto size = check_type_and_get_blob_size("OSMHeader"); |  | ||||||
|                     m_header = decode_header(read_from_input_queue(size)); |  | ||||||
| 
 | 
 | ||||||
|                     if (m_read_which_entities != osmium::osm_entity_bits::nothing) { |                 void run() final { | ||||||
|                         m_reader = std::thread(&PBFInputFormat::parse_osm_data, this, m_read_which_entities); |                     osmium::thread::set_thread_name("_osmium_pbf_in"); | ||||||
|  | 
 | ||||||
|  |                     parse_header_blob(); | ||||||
|  | 
 | ||||||
|  |                     if (read_types() != osmium::osm_entity_bits::nothing) { | ||||||
|  |                         parse_data_blobs(); | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 ~PBFInputFormat() { |             }; // class PBFParser
 | ||||||
|                     signal_input_thread_to_quit(); |  | ||||||
|                     if (m_reader.joinable()) { |  | ||||||
|                         m_reader.join(); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
| 
 | 
 | ||||||
|                 /**
 |             // we want the register_parser() function to run, setting
 | ||||||
|                  * Returns the next buffer with OSM data read from the PBF |             // the variable is only a side-effect, it will never be used
 | ||||||
|                  * file. Blocks if data is not available yet. |             const bool registered_pbf_parser = ParserFactory::instance().register_parser( | ||||||
|                  * Returns an empty buffer at end of input. |                 file_format::pbf, | ||||||
|                  */ |                 [](future_string_queue_type& input_queue, | ||||||
|                 osmium::memory::Buffer read() override { |                     future_buffer_queue_type& output_queue, | ||||||
|                     osmium::memory::Buffer buffer; |                     std::promise<osmium::io::Header>& header_promise, | ||||||
|                     if (m_eof) { |                     osmium::osm_entity_bits::type read_which_entities) { | ||||||
|                         return buffer; |                     return std::unique_ptr<Parser>(new PBFParser(input_queue, output_queue, header_promise, read_which_entities)); | ||||||
|                     } |             }); | ||||||
| 
 | 
 | ||||||
|                     std::future<osmium::memory::Buffer> buffer_future; |             // dummy function to silence the unused variable warning from above
 | ||||||
|                     m_queue.wait_and_pop(buffer_future); |             inline bool get_registered_pbf_parser() noexcept { | ||||||
| 
 |                 return registered_pbf_parser; | ||||||
|                     try { |             } | ||||||
|                         buffer = std::move(buffer_future.get()); |  | ||||||
|                         if (!buffer) { |  | ||||||
|                             m_eof = true; |  | ||||||
|                         } |  | ||||||
|                         return buffer; |  | ||||||
|                     } catch (...) { |  | ||||||
|                         m_eof = true; |  | ||||||
|                         signal_input_thread_to_quit(); |  | ||||||
|                         throw; |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
| 
 |  | ||||||
|             }; // class PBFInputFormat
 |  | ||||||
| 
 |  | ||||||
|             namespace { |  | ||||||
| 
 |  | ||||||
| // we want the register_input_format() function to run, setting the variable
 |  | ||||||
| // is only a side-effect, it will never be used
 |  | ||||||
| #pragma GCC diagnostic push |  | ||||||
| #pragma GCC diagnostic ignored "-Wunused-variable" |  | ||||||
|                 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); |  | ||||||
|                 }); |  | ||||||
| #pragma GCC diagnostic pop |  | ||||||
| 
 |  | ||||||
|             } // anonymous namespace
 |  | ||||||
| 
 | 
 | ||||||
|         } // namespace detail
 |         } // namespace detail
 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -34,19 +34,18 @@ DEALINGS IN THE SOFTWARE. | |||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| #include <algorithm> | #include <algorithm> | ||||||
| #include <chrono> | #include <cassert> | ||||||
| #include <cmath> | #include <cmath> | ||||||
| #include <cstdint> | #include <cstdint> | ||||||
| #include <cstdlib> | #include <cstdlib> | ||||||
| #include <future> |  | ||||||
| #include <iterator> | #include <iterator> | ||||||
| #include <memory> | #include <memory> | ||||||
| #include <ratio> |  | ||||||
| #include <string> | #include <string> | ||||||
| #include <thread> |  | ||||||
| #include <time.h> | #include <time.h> | ||||||
| #include <utility> | #include <utility> | ||||||
| 
 | 
 | ||||||
|  | // needed for older boost libraries
 | ||||||
|  | #define BOOST_RESULT_OF_USE_DECLTYPE | ||||||
| #include <boost/iterator/transform_iterator.hpp> | #include <boost/iterator/transform_iterator.hpp> | ||||||
| 
 | 
 | ||||||
| #include <protozero/pbf_builder.hpp> | #include <protozero/pbf_builder.hpp> | ||||||
| @ -71,6 +70,7 @@ DEALINGS IN THE SOFTWARE. | |||||||
| #include <osmium/osm/tag.hpp> | #include <osmium/osm/tag.hpp> | ||||||
| #include <osmium/osm/timestamp.hpp> | #include <osmium/osm/timestamp.hpp> | ||||||
| #include <osmium/osm/way.hpp> | #include <osmium/osm/way.hpp> | ||||||
|  | #include <osmium/thread/pool.hpp> | ||||||
| #include <osmium/util/cast.hpp> | #include <osmium/util/cast.hpp> | ||||||
| #include <osmium/util/delta.hpp> | #include <osmium/util/delta.hpp> | ||||||
| #include <osmium/visitor.hpp> | #include <osmium/visitor.hpp> | ||||||
| @ -81,6 +81,32 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|         namespace detail { |         namespace detail { | ||||||
| 
 | 
 | ||||||
|  |             struct pbf_output_options { | ||||||
|  | 
 | ||||||
|  |                 /// Should nodes be encoded in DenseNodes?
 | ||||||
|  |                 bool use_dense_nodes; | ||||||
|  | 
 | ||||||
|  |                 /**
 | ||||||
|  |                  * 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 use_compression; | ||||||
|  | 
 | ||||||
|  |                 /// Should metadata of objects be written?
 | ||||||
|  |                 bool add_metadata; | ||||||
|  | 
 | ||||||
|  |                 /// Add the "HistoricalInformation" header flag.
 | ||||||
|  |                 bool add_historical_information_flag; | ||||||
|  | 
 | ||||||
|  |                 /// Should the visible flag be added to all OSM objects?
 | ||||||
|  |                 bool add_visible_flag; | ||||||
|  | 
 | ||||||
|  |             }; | ||||||
|  | 
 | ||||||
|             /**
 |             /**
 | ||||||
|              * Maximum number of items in a primitive block. |              * Maximum number of items in a primitive block. | ||||||
|              * |              * | ||||||
| @ -104,43 +130,81 @@ namespace osmium { | |||||||
|                 return static_cast<int64_t>(std::round(lonlat * lonlat_resolution / location_granularity)); |                 return static_cast<int64_t>(std::round(lonlat * lonlat_resolution / location_granularity)); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             /**
 |             enum class pbf_blob_type { | ||||||
|              * Serialize a protobuf message into a Blob, optionally apply compression |                 header = 0, | ||||||
|              * and return it together with a BlobHeader ready to be written to a file. |                 data = 1 | ||||||
|              * |             }; | ||||||
|              * @param type Type-string used in the BlobHeader. |  | ||||||
|              * @param msg Protobuf-message. |  | ||||||
|              * @param use_compression Should the output be compressed using zlib? |  | ||||||
|              */ |  | ||||||
|             inline std::string serialize_blob(const std::string& type, const std::string& msg, bool use_compression) { |  | ||||||
|                 std::string blob_data; |  | ||||||
|                 protozero::pbf_builder<FileFormat::Blob> pbf_blob(blob_data); |  | ||||||
| 
 | 
 | ||||||
|                 if (use_compression) { |             class SerializeBlob { | ||||||
|                     pbf_blob.add_int32(FileFormat::Blob::optional_int32_raw_size, msg.size()); | 
 | ||||||
|                     pbf_blob.add_bytes(FileFormat::Blob::optional_bytes_zlib_data, osmium::io::detail::zlib_compress(msg)); |                 std::string m_msg; | ||||||
|                 } else { | 
 | ||||||
|                     pbf_blob.add_bytes(FileFormat::Blob::optional_bytes_raw, msg); |                 pbf_blob_type m_blob_type; | ||||||
|  | 
 | ||||||
|  |                 bool m_use_compression; | ||||||
|  | 
 | ||||||
|  |             public: | ||||||
|  | 
 | ||||||
|  |                 /**
 | ||||||
|  |                  * Initialize a blob serializer. | ||||||
|  |                  * | ||||||
|  |                  * @param msg Protobuf-message containing the blob data | ||||||
|  |                  * @param type Type of blob. | ||||||
|  |                  * @param use_compression Should the output be compressed using | ||||||
|  |                  *        zlib? | ||||||
|  |                  */ | ||||||
|  |                 SerializeBlob(std::string&& msg, pbf_blob_type type, bool use_compression) : | ||||||
|  |                     m_msg(std::move(msg)), | ||||||
|  |                     m_blob_type(type), | ||||||
|  |                     m_use_compression(use_compression) { | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 std::string blob_header_data; |                 /**
 | ||||||
|                 protozero::pbf_builder<FileFormat::BlobHeader> pbf_blob_header(blob_header_data); |                  * Serialize a protobuf message into a Blob, optionally apply | ||||||
|  |                  * compression and return it together with a BlobHeader ready | ||||||
|  |                  * to be written to a file. | ||||||
|  |                  */ | ||||||
|  |                 std::string operator()() { | ||||||
|  |                     assert(m_msg.size() <= max_uncompressed_blob_size); | ||||||
| 
 | 
 | ||||||
|                 pbf_blob_header.add_string(FileFormat::BlobHeader::required_string_type, type); |                     std::string blob_data; | ||||||
|                 pbf_blob_header.add_int32(FileFormat::BlobHeader::required_int32_datasize, blob_data.size()); |                     protozero::pbf_builder<FileFormat::Blob> pbf_blob(blob_data); | ||||||
| 
 | 
 | ||||||
|                 uint32_t sz = htonl(static_cast_with_assert<uint32_t>(blob_header_data.size())); |                     if (m_use_compression) { | ||||||
|  |                         pbf_blob.add_int32(FileFormat::Blob::optional_int32_raw_size, int32_t(m_msg.size())); | ||||||
|  |                         pbf_blob.add_bytes(FileFormat::Blob::optional_bytes_zlib_data, osmium::io::detail::zlib_compress(m_msg)); | ||||||
|  |                     } else { | ||||||
|  |                         pbf_blob.add_bytes(FileFormat::Blob::optional_bytes_raw, m_msg); | ||||||
|  |                     } | ||||||
| 
 | 
 | ||||||
|                 // write to output: the 4-byte BlobHeader-Size followed by the BlobHeader followed by the Blob
 |                     std::string blob_header_data; | ||||||
|                 std::string output; |                     protozero::pbf_builder<FileFormat::BlobHeader> pbf_blob_header(blob_header_data); | ||||||
|                 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; |                     pbf_blob_header.add_string(FileFormat::BlobHeader::required_string_type, m_blob_type == pbf_blob_type::data ? "OSMData" : "OSMHeader"); | ||||||
|             } |                     pbf_blob_header.add_int32(FileFormat::BlobHeader::required_int32_datasize, static_cast_with_assert<int32_t>(blob_data.size())); | ||||||
| 
 | 
 | ||||||
|  |                     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; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |             }; // class SerializeBlob
 | ||||||
|  | 
 | ||||||
|  |             /**
 | ||||||
|  |              * Contains the code to pack any number of nodes into a DenseNode | ||||||
|  |              * structure. | ||||||
|  |              * | ||||||
|  |              * Because this needs to allocate a lot of memory on the heap, | ||||||
|  |              * only one object of this class will be created and then re-used | ||||||
|  |              * after calling clear() on it. | ||||||
|  |              */ | ||||||
|             class DenseNodes { |             class DenseNodes { | ||||||
| 
 | 
 | ||||||
|                 StringTable& m_stringtable; |                 StringTable& m_stringtable; | ||||||
| @ -158,27 +222,26 @@ namespace osmium { | |||||||
|                 std::vector<int64_t> m_lons; |                 std::vector<int64_t> m_lons; | ||||||
|                 std::vector<int32_t> m_tags; |                 std::vector<int32_t> m_tags; | ||||||
| 
 | 
 | ||||||
|                 osmium::util::DeltaEncode<int64_t> m_delta_id; |                 osmium::util::DeltaEncode<object_id_type, int64_t> m_delta_id; | ||||||
| 
 | 
 | ||||||
|                 osmium::util::DeltaEncode<int64_t> m_delta_timestamp; |                 osmium::util::DeltaEncode<uint32_t, int64_t> m_delta_timestamp; | ||||||
|                 osmium::util::DeltaEncode<int64_t> m_delta_changeset; |                 osmium::util::DeltaEncode<changeset_id_type, int64_t> m_delta_changeset; | ||||||
|                 osmium::util::DeltaEncode<int32_t> m_delta_uid; |                 osmium::util::DeltaEncode<user_id_type, int32_t> m_delta_uid; | ||||||
|                 osmium::util::DeltaEncode<int32_t> m_delta_user_sid; |                 osmium::util::DeltaEncode<uint32_t, int32_t> m_delta_user_sid; | ||||||
| 
 | 
 | ||||||
|                 osmium::util::DeltaEncode<int64_t> m_delta_lat; |                 osmium::util::DeltaEncode<int64_t, int64_t> m_delta_lat; | ||||||
|                 osmium::util::DeltaEncode<int64_t> m_delta_lon; |                 osmium::util::DeltaEncode<int64_t, int64_t> m_delta_lon; | ||||||
| 
 | 
 | ||||||
|                 bool m_add_metadata; |                 const pbf_output_options& m_options; | ||||||
|                 bool m_add_visible; |  | ||||||
| 
 | 
 | ||||||
|             public: |             public: | ||||||
| 
 | 
 | ||||||
|                 DenseNodes(StringTable& stringtable, bool add_metadata, bool add_visible) : |                 DenseNodes(StringTable& stringtable, const pbf_output_options& options) : | ||||||
|                     m_stringtable(stringtable), |                     m_stringtable(stringtable), | ||||||
|                     m_add_metadata(add_metadata), |                     m_options(options) { | ||||||
|                     m_add_visible(add_visible) { |  | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|  |                 /// Clear object for re-use. Keep the allocated memory.
 | ||||||
|                 void clear() { |                 void clear() { | ||||||
|                     m_ids.clear(); |                     m_ids.clear(); | ||||||
| 
 | 
 | ||||||
| @ -211,13 +274,13 @@ namespace osmium { | |||||||
|                 void add_node(const osmium::Node& node) { |                 void add_node(const osmium::Node& node) { | ||||||
|                     m_ids.push_back(m_delta_id.update(node.id())); |                     m_ids.push_back(m_delta_id.update(node.id())); | ||||||
| 
 | 
 | ||||||
|                     if (m_add_metadata) { |                     if (m_options.add_metadata) { | ||||||
|                         m_versions.push_back(node.version()); |                         m_versions.push_back(static_cast_with_assert<int32_t>(node.version())); | ||||||
|                         m_timestamps.push_back(m_delta_timestamp.update(node.timestamp())); |                         m_timestamps.push_back(m_delta_timestamp.update(uint32_t(node.timestamp()))); | ||||||
|                         m_changesets.push_back(m_delta_changeset.update(node.changeset())); |                         m_changesets.push_back(m_delta_changeset.update(node.changeset())); | ||||||
|                         m_uids.push_back(m_delta_uid.update(node.uid())); |                         m_uids.push_back(m_delta_uid.update(node.uid())); | ||||||
|                         m_user_sids.push_back(m_delta_user_sid.update(m_stringtable.add(node.user()))); |                         m_user_sids.push_back(m_delta_user_sid.update(m_stringtable.add(node.user()))); | ||||||
|                         if (m_add_visible) { |                         if (m_options.add_visible_flag) { | ||||||
|                             m_visibles.push_back(node.visible()); |                             m_visibles.push_back(node.visible()); | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
| @ -226,8 +289,8 @@ namespace osmium { | |||||||
|                     m_lons.push_back(m_delta_lon.update(lonlat2int(node.location().lon_without_check()))); |                     m_lons.push_back(m_delta_lon.update(lonlat2int(node.location().lon_without_check()))); | ||||||
| 
 | 
 | ||||||
|                     for (const auto& tag : node.tags()) { |                     for (const auto& tag : node.tags()) { | ||||||
|                         m_tags.push_back(m_stringtable.add(tag.key())); |                         m_tags.push_back(static_cast_with_assert<int32_t>(m_stringtable.add(tag.key()))); | ||||||
|                         m_tags.push_back(m_stringtable.add(tag.value())); |                         m_tags.push_back(static_cast_with_assert<int32_t>(m_stringtable.add(tag.value()))); | ||||||
|                     } |                     } | ||||||
|                     m_tags.push_back(0); |                     m_tags.push_back(0); | ||||||
|                 } |                 } | ||||||
| @ -238,7 +301,7 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|                     pbf_dense_nodes.add_packed_sint64(OSMFormat::DenseNodes::packed_sint64_id, m_ids.cbegin(), m_ids.cend()); |                     pbf_dense_nodes.add_packed_sint64(OSMFormat::DenseNodes::packed_sint64_id, m_ids.cbegin(), m_ids.cend()); | ||||||
| 
 | 
 | ||||||
|                     if (m_add_metadata) { |                     if (m_options.add_metadata) { | ||||||
|                         protozero::pbf_builder<OSMFormat::DenseInfo> pbf_dense_info(pbf_dense_nodes, OSMFormat::DenseNodes::optional_DenseInfo_denseinfo); |                         protozero::pbf_builder<OSMFormat::DenseInfo> pbf_dense_info(pbf_dense_nodes, OSMFormat::DenseNodes::optional_DenseInfo_denseinfo); | ||||||
|                         pbf_dense_info.add_packed_int32(OSMFormat::DenseInfo::packed_int32_version, m_versions.cbegin(), m_versions.cend()); |                         pbf_dense_info.add_packed_int32(OSMFormat::DenseInfo::packed_int32_version, m_versions.cbegin(), m_versions.cend()); | ||||||
|                         pbf_dense_info.add_packed_sint64(OSMFormat::DenseInfo::packed_sint64_timestamp, m_timestamps.cbegin(), m_timestamps.cend()); |                         pbf_dense_info.add_packed_sint64(OSMFormat::DenseInfo::packed_sint64_timestamp, m_timestamps.cbegin(), m_timestamps.cend()); | ||||||
| @ -246,7 +309,7 @@ namespace osmium { | |||||||
|                         pbf_dense_info.add_packed_sint32(OSMFormat::DenseInfo::packed_sint32_uid, m_uids.cbegin(), m_uids.cend()); |                         pbf_dense_info.add_packed_sint32(OSMFormat::DenseInfo::packed_sint32_uid, m_uids.cbegin(), m_uids.cend()); | ||||||
|                         pbf_dense_info.add_packed_sint32(OSMFormat::DenseInfo::packed_sint32_user_sid, m_user_sids.cbegin(), m_user_sids.cend()); |                         pbf_dense_info.add_packed_sint32(OSMFormat::DenseInfo::packed_sint32_user_sid, m_user_sids.cbegin(), m_user_sids.cend()); | ||||||
| 
 | 
 | ||||||
|                         if (m_add_visible) { |                         if (m_options.add_visible_flag) { | ||||||
|                             pbf_dense_info.add_packed_bool(OSMFormat::DenseInfo::packed_bool_visible, m_visibles.cbegin(), m_visibles.cend()); |                             pbf_dense_info.add_packed_bool(OSMFormat::DenseInfo::packed_bool_visible, m_visibles.cbegin(), m_visibles.cend()); | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
| @ -272,11 +335,11 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|             public: |             public: | ||||||
| 
 | 
 | ||||||
|                 PrimitiveBlock(bool add_metadata, bool add_visible) : |                 explicit PrimitiveBlock(const pbf_output_options& options) : | ||||||
|                     m_pbf_primitive_group_data(), |                     m_pbf_primitive_group_data(), | ||||||
|                     m_pbf_primitive_group(m_pbf_primitive_group_data), |                     m_pbf_primitive_group(m_pbf_primitive_group_data), | ||||||
|                     m_stringtable(), |                     m_stringtable(), | ||||||
|                     m_dense_nodes(m_stringtable, add_metadata, add_visible), |                     m_dense_nodes(m_stringtable, options), | ||||||
|                     m_type(OSMFormat::PrimitiveGroup::unknown), |                     m_type(OSMFormat::PrimitiveGroup::unknown), | ||||||
|                     m_count(0) { |                     m_count(0) { | ||||||
|                 } |                 } | ||||||
| @ -312,7 +375,7 @@ namespace osmium { | |||||||
|                     ++m_count; |                     ++m_count; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 size_t add_string(const char* s) { |                 uint32_t store_in_stringtable(const char* s) { | ||||||
|                     return m_stringtable.add(s); |                     return m_stringtable.add(s); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
| @ -350,24 +413,7 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|             class PBFOutputFormat : public osmium::io::detail::OutputFormat, public osmium::handler::Handler { |             class PBFOutputFormat : public osmium::io::detail::OutputFormat, public osmium::handler::Handler { | ||||||
| 
 | 
 | ||||||
|                 /// Should nodes be encoded in DenseNodes?
 |                 pbf_output_options m_options; | ||||||
|                 bool m_use_dense_nodes; |  | ||||||
| 
 |  | ||||||
|                 /**
 |  | ||||||
|                  * 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; |  | ||||||
| 
 |  | ||||||
|                 /// Should metadata of objects be written?
 |  | ||||||
|                 bool m_add_metadata; |  | ||||||
| 
 |  | ||||||
|                 /// Should the visible flag be added to objects?
 |  | ||||||
|                 bool m_add_visible; |  | ||||||
| 
 | 
 | ||||||
|                 PrimitiveBlock m_primitive_block; |                 PrimitiveBlock m_primitive_block; | ||||||
| 
 | 
 | ||||||
| @ -386,20 +432,22 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|                     primitive_block.add_message(OSMFormat::PrimitiveBlock::repeated_PrimitiveGroup_primitivegroup, m_primitive_block.group_data()); |                     primitive_block.add_message(OSMFormat::PrimitiveBlock::repeated_PrimitiveGroup_primitivegroup, m_primitive_block.group_data()); | ||||||
| 
 | 
 | ||||||
|                     std::promise<std::string> promise; |                     m_output_queue.push(osmium::thread::Pool::instance().submit( | ||||||
|                     m_output_queue.push(promise.get_future()); |                         SerializeBlob{std::move(primitive_block_data), | ||||||
|                     promise.set_value(serialize_blob("OSMData", primitive_block_data, m_use_compression)); |                                       pbf_blob_type::data, | ||||||
|  |                                       m_options.use_compression} | ||||||
|  |                     )); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 template <typename T> |                 template <typename T> | ||||||
|                 void add_meta(const osmium::OSMObject& object, T& pbf_object) { |                 void add_meta(const osmium::OSMObject& object, T& pbf_object) { | ||||||
|                     const osmium::TagList& tags = object.tags(); |                     const osmium::TagList& tags = object.tags(); | ||||||
| 
 | 
 | ||||||
|                     auto map_tag_key = [this](const osmium::Tag& tag) -> size_t { |                     auto map_tag_key = [this](const osmium::Tag& tag) -> uint32_t { | ||||||
|                         return m_primitive_block.add_string(tag.key()); |                         return m_primitive_block.store_in_stringtable(tag.key()); | ||||||
|                     }; |                     }; | ||||||
|                     auto map_tag_value = [this](const osmium::Tag& tag) -> size_t { |                     auto map_tag_value = [this](const osmium::Tag& tag) -> uint32_t { | ||||||
|                         return m_primitive_block.add_string(tag.value()); |                         return m_primitive_block.store_in_stringtable(tag.value()); | ||||||
|                     }; |                     }; | ||||||
| 
 | 
 | ||||||
|                     pbf_object.add_packed_uint32(T::enum_type::packed_uint32_keys, |                     pbf_object.add_packed_uint32(T::enum_type::packed_uint32_keys, | ||||||
| @ -410,39 +458,46 @@ namespace osmium { | |||||||
|                         boost::make_transform_iterator(tags.begin(), map_tag_value), |                         boost::make_transform_iterator(tags.begin(), map_tag_value), | ||||||
|                         boost::make_transform_iterator(tags.end(), map_tag_value)); |                         boost::make_transform_iterator(tags.end(), map_tag_value)); | ||||||
| 
 | 
 | ||||||
|                     if (m_add_metadata) { |                     if (m_options.add_metadata) { | ||||||
|                         protozero::pbf_builder<OSMFormat::Info> pbf_info(pbf_object, T::enum_type::optional_Info_info); |                         protozero::pbf_builder<OSMFormat::Info> pbf_info(pbf_object, T::enum_type::optional_Info_info); | ||||||
| 
 | 
 | ||||||
|                         pbf_info.add_int32(OSMFormat::Info::optional_int32_version, object.version()); |                         pbf_info.add_int32(OSMFormat::Info::optional_int32_version, static_cast_with_assert<int32_t>(object.version())); | ||||||
|                         pbf_info.add_int64(OSMFormat::Info::optional_int64_timestamp, object.timestamp()); |                         pbf_info.add_int64(OSMFormat::Info::optional_int64_timestamp, uint32_t(object.timestamp())); | ||||||
|                         pbf_info.add_int64(OSMFormat::Info::optional_int64_changeset, object.changeset()); |                         pbf_info.add_int64(OSMFormat::Info::optional_int64_changeset, object.changeset()); | ||||||
|                         pbf_info.add_int32(OSMFormat::Info::optional_int32_uid, object.uid()); |                         pbf_info.add_int32(OSMFormat::Info::optional_int32_uid, static_cast_with_assert<int32_t>(object.uid())); | ||||||
|                         pbf_info.add_uint32(OSMFormat::Info::optional_uint32_user_sid, m_primitive_block.add_string(object.user())); |                         pbf_info.add_uint32(OSMFormat::Info::optional_uint32_user_sid, m_primitive_block.store_in_stringtable(object.user())); | ||||||
|                         if (m_add_visible) { |                         if (m_options.add_visible_flag) { | ||||||
|                             pbf_info.add_bool(OSMFormat::Info::optional_bool_visible, object.visible()); |                             pbf_info.add_bool(OSMFormat::Info::optional_bool_visible, object.visible()); | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 PBFOutputFormat(const PBFOutputFormat&) = delete; |                 void switch_primitive_block_type(OSMFormat::PrimitiveGroup type) { | ||||||
|                 PBFOutputFormat& operator=(const PBFOutputFormat&) = delete; |                     if (!m_primitive_block.can_add(type)) { | ||||||
|  |                         store_primitive_block(); | ||||||
|  |                         m_primitive_block.reset(type); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
| 
 | 
 | ||||||
|             public: |             public: | ||||||
| 
 | 
 | ||||||
|                 explicit PBFOutputFormat(const osmium::io::File& file, data_queue_type& output_queue) : |                 PBFOutputFormat(const osmium::io::File& file, future_string_queue_type& output_queue) : | ||||||
|                     OutputFormat(file, output_queue), |                     OutputFormat(output_queue), | ||||||
|                     m_use_dense_nodes(file.get("pbf_dense_nodes") != "false"), |                     m_options(), | ||||||
|                     m_use_compression(file.get("pbf_compression") != "none" && file.get("pbf_compression") != "false"), |                     m_primitive_block(m_options) { | ||||||
|                     m_add_metadata(file.get("pbf_add_metadata") != "false" && file.get("add_metadata") != "false"), |                     m_options.use_dense_nodes = file.is_not_false("pbf_dense_nodes"); | ||||||
|                     m_add_visible(file.has_multiple_object_versions()), |                     m_options.use_compression = file.get("pbf_compression") != "none" && file.is_not_false("pbf_compression"); | ||||||
|                     m_primitive_block(m_add_metadata, m_add_visible) { |                     m_options.add_metadata = file.is_not_false("pbf_add_metadata") && file.is_not_false("add_metadata"); | ||||||
|  |                     m_options.add_historical_information_flag = file.has_multiple_object_versions(); | ||||||
|  |                     m_options.add_visible_flag = file.has_multiple_object_versions(); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void write_buffer(osmium::memory::Buffer&& buffer) override final { |                 PBFOutputFormat(const PBFOutputFormat&) = delete; | ||||||
|                     osmium::apply(buffer.cbegin(), buffer.cend(), *this); |                 PBFOutputFormat& operator=(const PBFOutputFormat&) = delete; | ||||||
|                 } |  | ||||||
| 
 | 
 | ||||||
|                 void write_header(const osmium::io::Header& header) override final { |                 ~PBFOutputFormat() noexcept final = default; | ||||||
|  | 
 | ||||||
|  |                 void write_header(const osmium::io::Header& header) final { | ||||||
|                     std::string data; |                     std::string data; | ||||||
|                     protozero::pbf_builder<OSMFormat::HeaderBlock> pbf_header_block(data); |                     protozero::pbf_builder<OSMFormat::HeaderBlock> pbf_header_block(data); | ||||||
| 
 | 
 | ||||||
| @ -450,19 +505,19 @@ namespace osmium { | |||||||
|                         protozero::pbf_builder<OSMFormat::HeaderBBox> pbf_header_bbox(pbf_header_block, OSMFormat::HeaderBlock::optional_HeaderBBox_bbox); |                         protozero::pbf_builder<OSMFormat::HeaderBBox> pbf_header_bbox(pbf_header_block, OSMFormat::HeaderBlock::optional_HeaderBBox_bbox); | ||||||
| 
 | 
 | ||||||
|                         osmium::Box box = header.joined_boxes(); |                         osmium::Box box = header.joined_boxes(); | ||||||
|                         pbf_header_bbox.add_sint64(OSMFormat::HeaderBBox::required_sint64_left,   box.bottom_left().lon() * lonlat_resolution); |                         pbf_header_bbox.add_sint64(OSMFormat::HeaderBBox::required_sint64_left,   int64_t(box.bottom_left().lon() * lonlat_resolution)); | ||||||
|                         pbf_header_bbox.add_sint64(OSMFormat::HeaderBBox::required_sint64_right,  box.top_right().lon()   * lonlat_resolution); |                         pbf_header_bbox.add_sint64(OSMFormat::HeaderBBox::required_sint64_right,  int64_t(box.top_right().lon()   * lonlat_resolution)); | ||||||
|                         pbf_header_bbox.add_sint64(OSMFormat::HeaderBBox::required_sint64_top,    box.top_right().lat()   * lonlat_resolution); |                         pbf_header_bbox.add_sint64(OSMFormat::HeaderBBox::required_sint64_top,    int64_t(box.top_right().lat()   * lonlat_resolution)); | ||||||
|                         pbf_header_bbox.add_sint64(OSMFormat::HeaderBBox::required_sint64_bottom, box.bottom_left().lat() * lonlat_resolution); |                         pbf_header_bbox.add_sint64(OSMFormat::HeaderBBox::required_sint64_bottom, int64_t(box.bottom_left().lat() * lonlat_resolution)); | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                     pbf_header_block.add_string(OSMFormat::HeaderBlock::repeated_string_required_features, "OsmSchema-V0.6"); |                     pbf_header_block.add_string(OSMFormat::HeaderBlock::repeated_string_required_features, "OsmSchema-V0.6"); | ||||||
| 
 | 
 | ||||||
|                     if (m_use_dense_nodes) { |                     if (m_options.use_dense_nodes) { | ||||||
|                         pbf_header_block.add_string(OSMFormat::HeaderBlock::repeated_string_required_features, "DenseNodes"); |                         pbf_header_block.add_string(OSMFormat::HeaderBlock::repeated_string_required_features, "DenseNodes"); | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                     if (m_file.has_multiple_object_versions()) { |                     if (m_options.add_historical_information_flag) { | ||||||
|                         pbf_header_block.add_string(OSMFormat::HeaderBlock::repeated_string_required_features, "HistoricalInformation"); |                         pbf_header_block.add_string(OSMFormat::HeaderBlock::repeated_string_required_features, "HistoricalInformation"); | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
| @ -471,7 +526,7 @@ namespace osmium { | |||||||
|                     std::string osmosis_replication_timestamp = header.get("osmosis_replication_timestamp"); |                     std::string osmosis_replication_timestamp = header.get("osmosis_replication_timestamp"); | ||||||
|                     if (!osmosis_replication_timestamp.empty()) { |                     if (!osmosis_replication_timestamp.empty()) { | ||||||
|                         osmium::Timestamp ts(osmosis_replication_timestamp.c_str()); |                         osmium::Timestamp ts(osmosis_replication_timestamp.c_str()); | ||||||
|                         pbf_header_block.add_int64(OSMFormat::HeaderBlock::optional_int64_osmosis_replication_timestamp, ts); |                         pbf_header_block.add_int64(OSMFormat::HeaderBlock::optional_int64_osmosis_replication_timestamp, uint32_t(ts)); | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                     std::string osmosis_replication_sequence_number = header.get("osmosis_replication_sequence_number"); |                     std::string osmosis_replication_sequence_number = header.get("osmosis_replication_sequence_number"); | ||||||
| @ -484,20 +539,23 @@ namespace osmium { | |||||||
|                         pbf_header_block.add_string(OSMFormat::HeaderBlock::optional_string_osmosis_replication_base_url, osmosis_replication_base_url); |                         pbf_header_block.add_string(OSMFormat::HeaderBlock::optional_string_osmosis_replication_base_url, osmosis_replication_base_url); | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                     std::promise<std::string> promise; |                     m_output_queue.push(osmium::thread::Pool::instance().submit( | ||||||
|                     m_output_queue.push(promise.get_future()); |                         SerializeBlob{std::move(data), | ||||||
|                     promise.set_value(serialize_blob("OSMHeader", data, m_use_compression)); |                                       pbf_blob_type::header, | ||||||
|  |                                       m_options.use_compression} | ||||||
|  |                         )); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void switch_primitive_block_type(OSMFormat::PrimitiveGroup type) { |                 void write_buffer(osmium::memory::Buffer&& buffer) final { | ||||||
|                     if (!m_primitive_block.can_add(type)) { |                     osmium::apply(buffer.cbegin(), buffer.cend(), *this); | ||||||
|                         store_primitive_block(); |                 } | ||||||
|                         m_primitive_block.reset(type); | 
 | ||||||
|                     } |                 void write_end() final { | ||||||
|  |                     store_primitive_block(); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void node(const osmium::Node& node) { |                 void node(const osmium::Node& node) { | ||||||
|                     if (m_use_dense_nodes) { |                     if (m_options.use_dense_nodes) { | ||||||
|                         switch_primitive_block_type(OSMFormat::PrimitiveGroup::optional_DenseNodes_dense); |                         switch_primitive_block_type(OSMFormat::PrimitiveGroup::optional_DenseNodes_dense); | ||||||
|                         m_primitive_block.add_dense_node(node); |                         m_primitive_block.add_dense_node(node); | ||||||
|                         return; |                         return; | ||||||
| @ -538,8 +596,8 @@ namespace osmium { | |||||||
|                     pbf_relation.add_int64(OSMFormat::Relation::required_int64_id, relation.id()); |                     pbf_relation.add_int64(OSMFormat::Relation::required_int64_id, relation.id()); | ||||||
|                     add_meta(relation, pbf_relation); |                     add_meta(relation, pbf_relation); | ||||||
| 
 | 
 | ||||||
|                     auto map_member_role = [this](const osmium::RelationMember& member) -> size_t { |                     auto map_member_role = [this](const osmium::RelationMember& member) -> uint32_t { | ||||||
|                         return m_primitive_block.add_string(member.role()); |                         return m_primitive_block.store_in_stringtable(member.role()); | ||||||
|                     }; |                     }; | ||||||
|                     pbf_relation.add_packed_int32(OSMFormat::Relation::packed_int32_roles_sid, |                     pbf_relation.add_packed_int32(OSMFormat::Relation::packed_int32_roles_sid, | ||||||
|                         boost::make_transform_iterator(relation.members().begin(), map_member_role), |                         boost::make_transform_iterator(relation.members().begin(), map_member_role), | ||||||
| @ -554,41 +612,27 @@ namespace osmium { | |||||||
|                     it_type last { members.cend(), members.cend(), map_member_ref }; |                     it_type last { members.cend(), members.cend(), map_member_ref }; | ||||||
|                     pbf_relation.add_packed_sint64(OSMFormat::Relation::packed_sint64_memids, first, last); |                     pbf_relation.add_packed_sint64(OSMFormat::Relation::packed_sint64_memids, first, last); | ||||||
| 
 | 
 | ||||||
|                     static auto map_member_type = [](const osmium::RelationMember& member) noexcept -> int { |                     static auto map_member_type = [](const osmium::RelationMember& member) noexcept -> int32_t { | ||||||
|                         return osmium::item_type_to_nwr_index(member.type()); |                         return int32_t(osmium::item_type_to_nwr_index(member.type())); | ||||||
|                     }; |                     }; | ||||||
|                     pbf_relation.add_packed_int32(OSMFormat::Relation::packed_MemberType_types, |                     pbf_relation.add_packed_int32(OSMFormat::Relation::packed_MemberType_types, | ||||||
|                         boost::make_transform_iterator(relation.members().begin(), map_member_type), |                         boost::make_transform_iterator(relation.members().begin(), map_member_type), | ||||||
|                         boost::make_transform_iterator(relation.members().end(), map_member_type)); |                         boost::make_transform_iterator(relation.members().end(), map_member_type)); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 /**
 |  | ||||||
|                  * Finalize the writing process, flush any open primitive |  | ||||||
|                  * blocks to the file and close the file. |  | ||||||
|                  */ |  | ||||||
|                 void close() override final { |  | ||||||
|                     store_primitive_block(); |  | ||||||
| 
 |  | ||||||
|                     std::promise<std::string> promise; |  | ||||||
|                     m_output_queue.push(promise.get_future()); |  | ||||||
|                     promise.set_value(std::string()); |  | ||||||
|                 } |  | ||||||
| 
 |  | ||||||
|             }; // class PBFOutputFormat
 |             }; // class PBFOutputFormat
 | ||||||
| 
 | 
 | ||||||
|             namespace { |             // we want the register_output_format() function to run, setting
 | ||||||
|  |             // the variable is only a side-effect, it will never be used
 | ||||||
|  |             const bool registered_pbf_output = osmium::io::detail::OutputFormatFactory::instance().register_output_format(osmium::io::file_format::pbf, | ||||||
|  |                 [](const osmium::io::File& file, future_string_queue_type& output_queue) { | ||||||
|  |                     return new osmium::io::detail::PBFOutputFormat(file, output_queue); | ||||||
|  |             }); | ||||||
| 
 | 
 | ||||||
| // we want the register_output_format() function to run, setting the variable
 |             // dummy function to silence the unused variable warning from above
 | ||||||
| // is only a side-effect, it will never be used
 |             inline bool get_registered_pbf_output() noexcept { | ||||||
| #pragma GCC diagnostic push |                 return registered_pbf_output; | ||||||
| #pragma GCC diagnostic ignored "-Wunused-variable" |             } | ||||||
|                 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); |  | ||||||
|                 }); |  | ||||||
| #pragma GCC diagnostic pop |  | ||||||
| 
 |  | ||||||
|             } // anonymous namespace
 |  | ||||||
| 
 | 
 | ||||||
|         } // namespace detail
 |         } // namespace detail
 | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										157
									
								
								third_party/libosmium/include/osmium/io/detail/queue_util.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										157
									
								
								third_party/libosmium/include/osmium/io/detail/queue_util.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,157 @@ | |||||||
|  | #ifndef OSMIUM_IO_DETAIL_QUEUE_UTIL_HPP | ||||||
|  | #define OSMIUM_IO_DETAIL_QUEUE_UTIL_HPP | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  | 
 | ||||||
|  | This file is part of Osmium (http://osmcode.org/libosmium).
 | ||||||
|  | 
 | ||||||
|  | Copyright 2013-2015 Jochen Topf <jochen@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 <exception> | ||||||
|  | #include <future> | ||||||
|  | #include <string> | ||||||
|  | 
 | ||||||
|  | #include <osmium/memory/buffer.hpp> | ||||||
|  | #include <osmium/thread/queue.hpp> | ||||||
|  | 
 | ||||||
|  | namespace osmium { | ||||||
|  | 
 | ||||||
|  |     namespace io { | ||||||
|  | 
 | ||||||
|  |         namespace detail { | ||||||
|  | 
 | ||||||
|  |             /**
 | ||||||
|  |              * This type of queue contains buffers with OSM data in them. | ||||||
|  |              * The "end of file" is marked by an invalid Buffer. | ||||||
|  |              * The buffers are wrapped in a std::future so that they can also | ||||||
|  |              * transport exceptions. The future also helps with keeping the | ||||||
|  |              * data in order. | ||||||
|  |              */ | ||||||
|  |             using future_buffer_queue_type = osmium::thread::Queue<std::future<osmium::memory::Buffer>>; | ||||||
|  | 
 | ||||||
|  |             /**
 | ||||||
|  |              * This type of queue contains OSM file data in the form it is | ||||||
|  |              * stored on disk, ie encoded as XML, PBF, etc. | ||||||
|  |              * The "end of file" is marked by an empty string. | ||||||
|  |              */ | ||||||
|  |             using string_queue_type = osmium::thread::Queue<std::string>; | ||||||
|  | 
 | ||||||
|  |             /**
 | ||||||
|  |              * This type of queue contains OSM file data in the form it is | ||||||
|  |              * stored on disk, ie encoded as XML, PBF, etc. | ||||||
|  |              * The "end of file" is marked by an empty string. | ||||||
|  |              * The strings are wrapped in a std::future so that they can also | ||||||
|  |              * transport exceptions. The future also helps with keeping the | ||||||
|  |              * data in order. | ||||||
|  |              */ | ||||||
|  |             using future_string_queue_type = osmium::thread::Queue<std::future<std::string>>; | ||||||
|  | 
 | ||||||
|  |             template <typename T> | ||||||
|  |             inline void add_to_queue(osmium::thread::Queue<std::future<T>>& queue, T&& data) { | ||||||
|  |                 std::promise<T> promise; | ||||||
|  |                 queue.push(promise.get_future()); | ||||||
|  |                 promise.set_value(std::forward<T>(data)); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             template <typename T> | ||||||
|  |             inline void add_to_queue(osmium::thread::Queue<std::future<T>>& queue, std::exception_ptr&& exception) { | ||||||
|  |                 std::promise<T> promise; | ||||||
|  |                 queue.push(promise.get_future()); | ||||||
|  |                 promise.set_exception(std::move(exception)); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             template <typename T> | ||||||
|  |             inline void add_end_of_data_to_queue(osmium::thread::Queue<std::future<T>>& queue) { | ||||||
|  |                 add_to_queue<T>(queue, T{}); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             inline bool at_end_of_data(const std::string& data) { | ||||||
|  |                 return data.empty(); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             inline bool at_end_of_data(osmium::memory::Buffer& buffer) { | ||||||
|  |                 return !buffer; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             template <typename T> | ||||||
|  |             class queue_wrapper { | ||||||
|  | 
 | ||||||
|  |                 using queue_type = osmium::thread::Queue<std::future<T>>; | ||||||
|  | 
 | ||||||
|  |                 queue_type& m_queue; | ||||||
|  |                 bool m_has_reached_end_of_data; | ||||||
|  | 
 | ||||||
|  |             public: | ||||||
|  | 
 | ||||||
|  |                 explicit queue_wrapper(queue_type& queue) : | ||||||
|  |                     m_queue(queue), | ||||||
|  |                     m_has_reached_end_of_data(false) { | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 ~queue_wrapper() noexcept { | ||||||
|  |                     drain(); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 void drain() { | ||||||
|  |                     while (!m_has_reached_end_of_data) { | ||||||
|  |                         try { | ||||||
|  |                             pop(); | ||||||
|  |                         } catch (...) { | ||||||
|  |                             // Ignore any exceptions.
 | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 bool has_reached_end_of_data() const noexcept { | ||||||
|  |                     return m_has_reached_end_of_data; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 T pop() { | ||||||
|  |                     T data; | ||||||
|  |                     if (!m_has_reached_end_of_data) { | ||||||
|  |                         std::future<T> data_future; | ||||||
|  |                         m_queue.wait_and_pop(data_future); | ||||||
|  |                         data = std::move(data_future.get()); | ||||||
|  |                         if (at_end_of_data(data)) { | ||||||
|  |                             m_has_reached_end_of_data = true; | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                     return data; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |             }; // class queue_wrapper
 | ||||||
|  | 
 | ||||||
|  |         } // namespace detail
 | ||||||
|  | 
 | ||||||
|  |     } // namespace io
 | ||||||
|  | 
 | ||||||
|  | } // namespace osmium
 | ||||||
|  | 
 | ||||||
|  | #endif // OSMIUM_IO_DETAIL_QUEUE_UTIL_HPP
 | ||||||
| @ -34,14 +34,13 @@ DEALINGS IN THE SOFTWARE. | |||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| #include <atomic> | #include <atomic> | ||||||
| #include <chrono> | #include <exception> | ||||||
| #include <ratio> |  | ||||||
| #include <string> | #include <string> | ||||||
| #include <thread> | #include <thread> | ||||||
| #include <utility> | #include <utility> | ||||||
| 
 | 
 | ||||||
| #include <osmium/io/compression.hpp> | #include <osmium/io/compression.hpp> | ||||||
| #include <osmium/thread/queue.hpp> | #include <osmium/io/detail/queue_util.hpp> | ||||||
| #include <osmium/thread/util.hpp> | #include <osmium/thread/util.hpp> | ||||||
| 
 | 
 | ||||||
| namespace osmium { | namespace osmium { | ||||||
| @ -50,52 +49,80 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|         namespace detail { |         namespace detail { | ||||||
| 
 | 
 | ||||||
|             class ReadThread { |             /**
 | ||||||
|  |              * This code uses an internally managed thread to read data from | ||||||
|  |              * the input file and (optionally) decompress it. The result is | ||||||
|  |              * sent to the given queue. Any exceptions will also be send to | ||||||
|  |              * the queue. | ||||||
|  |              */ | ||||||
|  |             class ReadThreadManager { | ||||||
| 
 | 
 | ||||||
|                 osmium::thread::Queue<std::string>& m_queue; |                 // only used in the sub-thread
 | ||||||
|                 osmium::io::Decompressor* m_decompressor; |                 osmium::io::Decompressor& m_decompressor; | ||||||
|  |                 future_string_queue_type& m_queue; | ||||||
| 
 | 
 | ||||||
|                 // If this is set in the main thread, we have to wrap up at the
 |                 // used in both threads
 | ||||||
|                 // next possible moment.
 |                 std::atomic<bool> m_done; | ||||||
|                 std::atomic<bool>& m_done; |  | ||||||
| 
 | 
 | ||||||
|             public: |                 // only used in the main thread
 | ||||||
|  |                 std::thread m_thread; | ||||||
| 
 | 
 | ||||||
|                 explicit ReadThread(osmium::thread::Queue<std::string>& queue, osmium::io::Decompressor* decompressor, std::atomic<bool>& done) : |                 void run_in_thread() { | ||||||
|                     m_queue(queue), |                     osmium::thread::set_thread_name("_osmium_read"); | ||||||
|                     m_decompressor(decompressor), |  | ||||||
|                     m_done(done) { |  | ||||||
|                 } |  | ||||||
| 
 |  | ||||||
|                 bool operator()() { |  | ||||||
|                     osmium::thread::set_thread_name("_osmium_input"); |  | ||||||
| 
 | 
 | ||||||
|                     try { |                     try { | ||||||
|                         while (!m_done) { |                         while (!m_done) { | ||||||
|                             std::string data {m_decompressor->read()}; |                             std::string data {m_decompressor.read()}; | ||||||
|                             if (data.empty()) { |                             if (at_end_of_data(data)) { | ||||||
|                                 m_queue.push(std::move(data)); |  | ||||||
|                                 break; |                                 break; | ||||||
|                             } |                             } | ||||||
|                             m_queue.push(std::move(data)); |                             add_to_queue(m_queue, std::move(data)); | ||||||
|                             while (m_queue.size() > 10 && !m_done) { |  | ||||||
|                                 std::this_thread::sleep_for(std::chrono::milliseconds(10)); |  | ||||||
|                             } |  | ||||||
|                         } |                         } | ||||||
| 
 | 
 | ||||||
|                         m_decompressor->close(); |                         m_decompressor.close(); | ||||||
|                     } catch (...) { |                     } catch (...) { | ||||||
|                         // If there is an exception in this thread, we make sure
 |                         add_to_queue(m_queue, std::current_exception()); | ||||||
|                         // 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; | 
 | ||||||
|  |                     add_end_of_data_to_queue(m_queue); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|             }; // class ReadThread
 |             public: | ||||||
|  | 
 | ||||||
|  |                 ReadThreadManager(osmium::io::Decompressor& decompressor, | ||||||
|  |                                   future_string_queue_type& queue) : | ||||||
|  |                     m_decompressor(decompressor), | ||||||
|  |                     m_queue(queue), | ||||||
|  |                     m_done(false), | ||||||
|  |                     m_thread(std::thread(&ReadThreadManager::run_in_thread, this)) { | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 ReadThreadManager(const ReadThreadManager&) = delete; | ||||||
|  |                 ReadThreadManager& operator=(const ReadThreadManager&) = delete; | ||||||
|  | 
 | ||||||
|  |                 ReadThreadManager(ReadThreadManager&&) = delete; | ||||||
|  |                 ReadThreadManager& operator=(ReadThreadManager&&) = delete; | ||||||
|  | 
 | ||||||
|  |                 ~ReadThreadManager() noexcept { | ||||||
|  |                     try { | ||||||
|  |                         close(); | ||||||
|  |                     } catch (...) { | ||||||
|  |                         // Ignore any exceptions because destructor must not throw.
 | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 void stop() noexcept { | ||||||
|  |                     m_done = true; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 void close() { | ||||||
|  |                     stop(); | ||||||
|  |                     if (m_thread.joinable()) { | ||||||
|  |                         m_thread.join(); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |             }; // class ReadThreadManager
 | ||||||
| 
 | 
 | ||||||
|         } // namespace detail
 |         } // namespace detail
 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -35,6 +35,7 @@ DEALINGS IN THE SOFTWARE. | |||||||
| 
 | 
 | ||||||
| #include <cerrno> | #include <cerrno> | ||||||
| #include <cstddef> | #include <cstddef> | ||||||
|  | #include <errno.h> | ||||||
| #include <fcntl.h> | #include <fcntl.h> | ||||||
| #include <string> | #include <string> | ||||||
| #include <system_error> | #include <system_error> | ||||||
| @ -45,7 +46,7 @@ DEALINGS IN THE SOFTWARE. | |||||||
| # include <io.h> | # include <io.h> | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #include <osmium/io/overwrite.hpp> | #include <osmium/io/writer_options.hpp> | ||||||
| 
 | 
 | ||||||
| namespace osmium { | namespace osmium { | ||||||
| 
 | 
 | ||||||
| @ -68,23 +69,26 @@ namespace osmium { | |||||||
|              */ |              */ | ||||||
|             inline int open_for_writing(const std::string& filename, osmium::io::overwrite allow_overwrite = osmium::io::overwrite::no) { |             inline int open_for_writing(const std::string& filename, osmium::io::overwrite allow_overwrite = osmium::io::overwrite::no) { | ||||||
|                 if (filename == "" || filename == "-") { |                 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 | #ifdef _WIN32 | ||||||
|                     flags |= O_BINARY; |                     _setmode(1, _O_BINARY); | ||||||
| #endif | #endif | ||||||
|                     int fd = ::open(filename.c_str(), flags, 0666); |                     return 1; // stdout
 | ||||||
|                     if (fd < 0) { |  | ||||||
|                         throw std::system_error(errno, std::system_category(), std::string("Open failed for '") + filename + "'"); |  | ||||||
|                     } |  | ||||||
|                     return fd; |  | ||||||
|                 } |                 } | ||||||
|  | 
 | ||||||
|  |                 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; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             /**
 |             /**
 | ||||||
| @ -98,17 +102,17 @@ namespace osmium { | |||||||
|             inline int open_for_reading(const std::string& filename) { |             inline int open_for_reading(const std::string& filename) { | ||||||
|                 if (filename == "" || filename == "-") { |                 if (filename == "" || filename == "-") { | ||||||
|                     return 0; // stdin
 |                     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; |  | ||||||
|                 } |                 } | ||||||
|  | 
 | ||||||
|  |                 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; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             /**
 |             /**
 | ||||||
| @ -151,6 +155,22 @@ namespace osmium { | |||||||
|                 reliable_write(fd, reinterpret_cast<const unsigned char*>(output_buffer), size); |                 reliable_write(fd, reinterpret_cast<const unsigned char*>(output_buffer), size); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  |             inline void reliable_fsync(const int fd) { | ||||||
|  | #ifdef _WIN32 | ||||||
|  |                 if (_commit(fd) != 0) { | ||||||
|  | #else | ||||||
|  |                 if (::fsync(fd) != 0) { | ||||||
|  | #endif | ||||||
|  |                     throw std::system_error(errno, std::system_category(), "Fsync failed"); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             inline void reliable_close(const int fd) { | ||||||
|  |                 if (::close(fd) != 0) { | ||||||
|  |                     throw std::system_error(errno, std::system_category(), "Close failed"); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|         } // namespace detail
 |         } // namespace detail
 | ||||||
| 
 | 
 | ||||||
|     } // namespace io
 |     } // namespace io
 | ||||||
|  | |||||||
| @ -34,6 +34,7 @@ DEALINGS IN THE SOFTWARE. | |||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| #include <cassert> | #include <cassert> | ||||||
|  | #include <cstdint> | ||||||
| #include <cstdlib> | #include <cstdlib> | ||||||
| #include <cstring> | #include <cstring> | ||||||
| #include <iterator> | #include <iterator> | ||||||
| @ -41,6 +42,8 @@ DEALINGS IN THE SOFTWARE. | |||||||
| #include <map> | #include <map> | ||||||
| #include <string> | #include <string> | ||||||
| 
 | 
 | ||||||
|  | #include <osmium/io/detail/pbf.hpp> | ||||||
|  | 
 | ||||||
| namespace osmium { | namespace osmium { | ||||||
| 
 | 
 | ||||||
|     namespace io { |     namespace io { | ||||||
| @ -72,7 +75,7 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|             public: |             public: | ||||||
| 
 | 
 | ||||||
|                 StringStore(size_t chunk_size) : |                 explicit StringStore(size_t chunk_size) : | ||||||
|                     m_chunk_size(chunk_size), |                     m_chunk_size(chunk_size), | ||||||
|                     m_chunks() { |                     m_chunks() { | ||||||
|                     add_chunk(); |                     add_chunk(); | ||||||
| @ -172,15 +175,15 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|                 // These functions get you some idea how much memory was
 |                 // These functions get you some idea how much memory was
 | ||||||
|                 // used.
 |                 // used.
 | ||||||
|                 int get_chunk_size() const noexcept { |                 size_t get_chunk_size() const noexcept { | ||||||
|                     return m_chunk_size; |                     return m_chunk_size; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 int get_chunk_count() const noexcept { |                 size_t get_chunk_count() const noexcept { | ||||||
|                     return m_chunks.size(); |                     return m_chunks.size(); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 int get_used_bytes_in_last_chunk() const noexcept { |                 size_t get_used_bytes_in_last_chunk() const noexcept { | ||||||
|                     return m_chunks.front().size(); |                     return m_chunks.front().size(); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
| @ -196,9 +199,16 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|             class StringTable { |             class StringTable { | ||||||
| 
 | 
 | ||||||
|  |                 // This is the maximum number of entries in a string table.
 | ||||||
|  |                 // This should never be reached in practice but we better
 | ||||||
|  |                 // make sure it doesn't. If we had max_uncompressed_blob_size
 | ||||||
|  |                 // many entries, we are sure they would never fit into a PBF
 | ||||||
|  |                 // Blob.
 | ||||||
|  |                 static constexpr const uint32_t max_entries = max_uncompressed_blob_size; | ||||||
|  | 
 | ||||||
|                 StringStore m_strings; |                 StringStore m_strings; | ||||||
|                 std::map<const char*, size_t, StrComp> m_index; |                 std::map<const char*, size_t, StrComp> m_index; | ||||||
|                 size_t m_size; |                 uint32_t m_size; | ||||||
| 
 | 
 | ||||||
|             public: |             public: | ||||||
| 
 | 
 | ||||||
| @ -216,18 +226,23 @@ namespace osmium { | |||||||
|                     m_strings.add(""); |                     m_strings.add(""); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 size_t size() const noexcept { |                 uint32_t size() const noexcept { | ||||||
|                     return m_size + 1; |                     return m_size + 1; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 size_t add(const char* s) { |                 uint32_t add(const char* s) { | ||||||
|                     auto f = m_index.find(s); |                     auto f = m_index.find(s); | ||||||
|                     if (f != m_index.end()) { |                     if (f != m_index.end()) { | ||||||
|                         return f->second; |                         return uint32_t(f->second); | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                     const char* cs = m_strings.add(s); |                     const char* cs = m_strings.add(s); | ||||||
|                     m_index[cs] = ++m_size; |                     m_index[cs] = ++m_size; | ||||||
|  | 
 | ||||||
|  |                     if (m_size > max_entries) { | ||||||
|  |                         throw osmium::pbf_error("string table has too many entries"); | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|                     return m_size; |                     return m_size; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										206
									
								
								third_party/libosmium/include/osmium/io/detail/string_util.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										206
									
								
								third_party/libosmium/include/osmium/io/detail/string_util.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,206 @@ | |||||||
|  | #ifndef OSMIUM_IO_DETAIL_STRING_UTIL_HPP | ||||||
|  | #define OSMIUM_IO_DETAIL_STRING_UTIL_HPP | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  | 
 | ||||||
|  | This file is part of Osmium (http://osmcode.org/libosmium).
 | ||||||
|  | 
 | ||||||
|  | Copyright 2013-2015 Jochen Topf <jochen@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 <cstdint> | ||||||
|  | #include <cstring> | ||||||
|  | #include <string> | ||||||
|  | #include <utility> | ||||||
|  | 
 | ||||||
|  | #include <utf8.h> | ||||||
|  | 
 | ||||||
|  | namespace osmium { | ||||||
|  | 
 | ||||||
|  |     namespace io { | ||||||
|  | 
 | ||||||
|  |         namespace detail { | ||||||
|  | 
 | ||||||
|  | #ifndef _MSC_VER | ||||||
|  | # define SNPRINTF std::snprintf | ||||||
|  | #else | ||||||
|  | # define SNPRINTF _snprintf | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  |             template <typename... TArgs> | ||||||
|  |             inline int string_snprintf(std::string& out, | ||||||
|  |                                        size_t old_size, | ||||||
|  |                                        size_t max_size, | ||||||
|  |                                        const char* format, | ||||||
|  |                                        TArgs&&... args) { | ||||||
|  |                 out.resize(old_size + max_size); | ||||||
|  | 
 | ||||||
|  |                 return SNPRINTF(max_size ? const_cast<char*>(out.c_str()) + old_size : nullptr, | ||||||
|  |                                 max_size, | ||||||
|  |                                 format, | ||||||
|  |                                 std::forward<TArgs>(args)...); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  | #undef SNPRINTF | ||||||
|  | 
 | ||||||
|  |             /**
 | ||||||
|  |              * This is a helper function for writing printf-like formatted | ||||||
|  |              * data into a std::string. | ||||||
|  |              * | ||||||
|  |              * @param out The data will be appended to this string. | ||||||
|  |              * @param format A string with formatting instructions a la printf. | ||||||
|  |              * @param args Any further arguments like in printf. | ||||||
|  |              * @throws std::bad_alloc If the string needed to grow and there | ||||||
|  |              *         wasn't enough memory. | ||||||
|  |              */ | ||||||
|  |             template <typename... TArgs> | ||||||
|  |             inline void append_printf_formatted_string(std::string& out, | ||||||
|  |                                                    const char* format, | ||||||
|  |                                                    TArgs&&... args) { | ||||||
|  | 
 | ||||||
|  |                 // First try to write string with the max_size, if that doesn't
 | ||||||
|  |                 // work snprintf will tell us how much space it needs. We
 | ||||||
|  |                 // reserve that much space and try again. So this will always
 | ||||||
|  |                 // work, even if the output is larger than the given max_size.
 | ||||||
|  |                 //
 | ||||||
|  |                 // Unfortunately this trick doesn't work on Windows, because
 | ||||||
|  |                 // the _snprintf() function there only returns the length it
 | ||||||
|  |                 // needs if max_size==0 and the buffer pointer is the null
 | ||||||
|  |                 // pointer. So we have to take this into account.
 | ||||||
|  | 
 | ||||||
|  | #ifndef _MSC_VER | ||||||
|  |                 static const size_t max_size = 100; | ||||||
|  | #else | ||||||
|  |                 static const size_t max_size = 0; | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  |                 size_t old_size = out.size(); | ||||||
|  | 
 | ||||||
|  |                 int len = string_snprintf(out, | ||||||
|  |                                           old_size, | ||||||
|  |                                           max_size, | ||||||
|  |                                           format, | ||||||
|  |                                           std::forward<TArgs>(args)...); | ||||||
|  |                 assert(len > 0); | ||||||
|  | 
 | ||||||
|  |                 if (size_t(len) >= max_size) { | ||||||
|  |                     int len2 = string_snprintf(out, | ||||||
|  |                                                old_size, | ||||||
|  |                                                size_t(len) + 1, | ||||||
|  |                                                format, | ||||||
|  |                                                std::forward<TArgs>(args)...); | ||||||
|  |                     assert(len2 == len); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 out.resize(old_size + size_t(len)); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             inline void append_utf8_encoded_string(std::string& out, const char* data) { | ||||||
|  |                 const char* end = data + std::strlen(data); | ||||||
|  | 
 | ||||||
|  |                 while (data != end) { | ||||||
|  |                     const char* last = data; | ||||||
|  |                     uint32_t c = utf8::next(data, end); | ||||||
|  | 
 | ||||||
|  |                     // 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)) { | ||||||
|  |                         out.append(last, data); | ||||||
|  |                     } else { | ||||||
|  |                         out += '%'; | ||||||
|  |                         if (c <= 0xff) { | ||||||
|  |                             append_printf_formatted_string(out, "%02x", c); | ||||||
|  |                         } else { | ||||||
|  |                             append_printf_formatted_string(out, "%04x", c); | ||||||
|  |                         } | ||||||
|  |                         out += '%'; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             inline void append_xml_encoded_string(std::string& out, const char* data) { | ||||||
|  |                 for (; *data != '\0'; ++data) { | ||||||
|  |                     switch(*data) { | ||||||
|  |                         case '&':  out += "&";  break; | ||||||
|  |                         case '\"': out += """; break; | ||||||
|  |                         case '\'': out += "'"; break; | ||||||
|  |                         case '<':  out += "<";   break; | ||||||
|  |                         case '>':  out += ">";   break; | ||||||
|  |                         case '\n': out += "
";  break; | ||||||
|  |                         case '\r': out += "
";  break; | ||||||
|  |                         case '\t': out += "	";  break; | ||||||
|  |                         default:   out += *data;    break; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             inline void append_debug_encoded_string(std::string& out, const char* data, const char* prefix, const char* suffix) { | ||||||
|  |                 const char* end = data + std::strlen(data); | ||||||
|  | 
 | ||||||
|  |                 while (data != end) { | ||||||
|  |                     const char* last = data; | ||||||
|  |                     uint32_t c = utf8::next(data, end); | ||||||
|  | 
 | ||||||
|  |                     // 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
 | ||||||
|  |                     // non-printing characters.
 | ||||||
|  |                     if ((0x0020 <= c && c <= 0x0021) || | ||||||
|  |                         (0x0023 <= c && c <= 0x003b) || | ||||||
|  |                         (0x003d == c) || | ||||||
|  |                         (0x003f <= c && c <= 0x007e) || | ||||||
|  |                         (0x00a1 <= c && c <= 0x00ac) || | ||||||
|  |                         (0x00ae <= c && c <= 0x05ff)) { | ||||||
|  |                         out.append(last, data); | ||||||
|  |                     } else { | ||||||
|  |                         out.append(prefix); | ||||||
|  |                         append_printf_formatted_string(out, "<U+%04X>", c); | ||||||
|  |                         out.append(suffix); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |         } // namespace detail
 | ||||||
|  | 
 | ||||||
|  |     } // namespace io
 | ||||||
|  | 
 | ||||||
|  | } // namespace osmium
 | ||||||
|  | 
 | ||||||
|  | #endif // OSMIUM_IO_DETAIL_STRING_UTIL_HPP
 | ||||||
| @ -33,11 +33,13 @@ DEALINGS IN THE SOFTWARE. | |||||||
| 
 | 
 | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
|  | #include <algorithm> | ||||||
|  | #include <exception> | ||||||
| #include <future> | #include <future> | ||||||
| #include <string> | #include <string> | ||||||
| 
 | 
 | ||||||
| #include <osmium/io/compression.hpp> | #include <osmium/io/compression.hpp> | ||||||
| #include <osmium/io/detail/output_format.hpp> | #include <osmium/io/detail/queue_util.hpp> | ||||||
| #include <osmium/thread/util.hpp> | #include <osmium/thread/util.hpp> | ||||||
| 
 | 
 | ||||||
| namespace osmium { | namespace osmium { | ||||||
| @ -46,33 +48,52 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|         namespace detail { |         namespace detail { | ||||||
| 
 | 
 | ||||||
|  |             /**
 | ||||||
|  |              * This codes runs in its own thread, getting data from the given | ||||||
|  |              * queue, (optionally) compressing it, and writing it to the output | ||||||
|  |              * file. | ||||||
|  |              */ | ||||||
|             class WriteThread { |             class WriteThread { | ||||||
| 
 | 
 | ||||||
|                 typedef osmium::io::detail::data_queue_type data_queue_type; |                 queue_wrapper<std::string> m_queue; | ||||||
| 
 |                 std::unique_ptr<osmium::io::Compressor> m_compressor; | ||||||
|                 data_queue_type& m_input_queue; |                 std::promise<bool> m_promise; | ||||||
|                 osmium::io::Compressor* m_compressor; |  | ||||||
| 
 | 
 | ||||||
|             public: |             public: | ||||||
| 
 | 
 | ||||||
|                 explicit WriteThread(data_queue_type& input_queue, osmium::io::Compressor* compressor) : |                 WriteThread(future_string_queue_type& input_queue, | ||||||
|                     m_input_queue(input_queue), |                             std::unique_ptr<osmium::io::Compressor>&& compressor, | ||||||
|                     m_compressor(compressor) { |                             std::promise<bool>&& promise) : | ||||||
|  |                     m_queue(input_queue), | ||||||
|  |                     m_compressor(std::move(compressor)), | ||||||
|  |                     m_promise(std::move(promise)) { | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 bool operator()() { |                 WriteThread(const WriteThread&) = delete; | ||||||
|                     osmium::thread::set_thread_name("_osmium_output"); |                 WriteThread& operator=(const WriteThread&) = delete; | ||||||
| 
 | 
 | ||||||
|                     std::future<std::string> data_future; |                 WriteThread(WriteThread&&) = delete; | ||||||
|                     std::string data; |                 WriteThread& operator=(WriteThread&&) = delete; | ||||||
|                     do { |  | ||||||
|                         m_input_queue.wait_and_pop(data_future); |  | ||||||
|                         data = data_future.get(); |  | ||||||
|                         m_compressor->write(data); |  | ||||||
|                     } while (!data.empty()); |  | ||||||
| 
 | 
 | ||||||
|                     m_compressor->close(); |                 ~WriteThread() noexcept = default; | ||||||
|                     return true; | 
 | ||||||
|  |                 void operator()() { | ||||||
|  |                     osmium::thread::set_thread_name("_osmium_write"); | ||||||
|  | 
 | ||||||
|  |                     try { | ||||||
|  |                         while (true) { | ||||||
|  |                             std::string data = m_queue.pop(); | ||||||
|  |                             if (at_end_of_data(data)) { | ||||||
|  |                                 break; | ||||||
|  |                             } | ||||||
|  |                             m_compressor->write(data); | ||||||
|  |                         } | ||||||
|  |                         m_compressor->close(); | ||||||
|  |                         m_promise.set_value(true); | ||||||
|  |                     } catch (...) { | ||||||
|  |                         m_promise.set_exception(std::current_exception()); | ||||||
|  |                         m_queue.drain(); | ||||||
|  |                     } | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|             }; // class WriteThread
 |             }; // class WriteThread
 | ||||||
|  | |||||||
| @ -33,21 +33,14 @@ DEALINGS IN THE SOFTWARE. | |||||||
| 
 | 
 | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| #include <atomic> |  | ||||||
| #include <cassert> | #include <cassert> | ||||||
| #include <chrono> |  | ||||||
| #include <cstddef> | #include <cstddef> | ||||||
| #include <cstdlib> | #include <cstdlib> | ||||||
| #include <cstring> | #include <cstring> | ||||||
| #include <exception> | #include <exception> | ||||||
| #include <future> | #include <future> | ||||||
| #include <iostream> |  | ||||||
| #include <memory> | #include <memory> | ||||||
| #include <ratio> |  | ||||||
| #include <sstream> |  | ||||||
| #include <stdexcept> |  | ||||||
| #include <string> | #include <string> | ||||||
| #include <thread> |  | ||||||
| #include <utility> | #include <utility> | ||||||
| 
 | 
 | ||||||
| #include <expat.h> | #include <expat.h> | ||||||
| @ -55,6 +48,7 @@ DEALINGS IN THE SOFTWARE. | |||||||
| #include <osmium/builder/builder.hpp> | #include <osmium/builder/builder.hpp> | ||||||
| #include <osmium/builder/osm_object_builder.hpp> | #include <osmium/builder/osm_object_builder.hpp> | ||||||
| #include <osmium/io/detail/input_format.hpp> | #include <osmium/io/detail/input_format.hpp> | ||||||
|  | #include <osmium/io/detail/queue_util.hpp> | ||||||
| #include <osmium/io/error.hpp> | #include <osmium/io/error.hpp> | ||||||
| #include <osmium/io/file_format.hpp> | #include <osmium/io/file_format.hpp> | ||||||
| #include <osmium/io/header.hpp> | #include <osmium/io/header.hpp> | ||||||
| @ -130,23 +124,11 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|     namespace io { |     namespace io { | ||||||
| 
 | 
 | ||||||
|         class File; |  | ||||||
| 
 |  | ||||||
|         namespace detail { |         namespace detail { | ||||||
| 
 | 
 | ||||||
|             /**
 |             class XMLParser : public Parser { | ||||||
|              * 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 = 2 * 1000 * 1000; | ||||||
| 
 |  | ||||||
|                 static constexpr int buffer_size = 10 * 1000 * 1000; |  | ||||||
| 
 | 
 | ||||||
|                 enum class context { |                 enum class context { | ||||||
|                     root, |                     root, | ||||||
| @ -155,6 +137,9 @@ namespace osmium { | |||||||
|                     way, |                     way, | ||||||
|                     relation, |                     relation, | ||||||
|                     changeset, |                     changeset, | ||||||
|  |                     discussion, | ||||||
|  |                     comment, | ||||||
|  |                     comment_text, | ||||||
|                     ignored_node, |                     ignored_node, | ||||||
|                     ignored_way, |                     ignored_way, | ||||||
|                     ignored_relation, |                     ignored_relation, | ||||||
| @ -175,29 +160,22 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|                 osmium::memory::Buffer m_buffer; |                 osmium::memory::Buffer m_buffer; | ||||||
| 
 | 
 | ||||||
|                 std::unique_ptr<osmium::builder::NodeBuilder>               m_node_builder; |                 std::unique_ptr<osmium::builder::NodeBuilder>                m_node_builder; | ||||||
|                 std::unique_ptr<osmium::builder::WayBuilder>                m_way_builder; |                 std::unique_ptr<osmium::builder::WayBuilder>                 m_way_builder; | ||||||
|                 std::unique_ptr<osmium::builder::RelationBuilder>           m_relation_builder; |                 std::unique_ptr<osmium::builder::RelationBuilder>            m_relation_builder; | ||||||
|                 std::unique_ptr<osmium::builder::ChangesetBuilder>          m_changeset_builder; |                 std::unique_ptr<osmium::builder::ChangesetBuilder>           m_changeset_builder; | ||||||
|  |                 std::unique_ptr<osmium::builder::ChangesetDiscussionBuilder> m_changeset_discussion_builder; | ||||||
| 
 | 
 | ||||||
|                 std::unique_ptr<osmium::builder::TagListBuilder>            m_tl_builder; |                 std::unique_ptr<osmium::builder::TagListBuilder>             m_tl_builder; | ||||||
|                 std::unique_ptr<osmium::builder::WayNodeListBuilder>        m_wnl_builder; |                 std::unique_ptr<osmium::builder::WayNodeListBuilder>         m_wnl_builder; | ||||||
|                 std::unique_ptr<osmium::builder::RelationMemberListBuilder> m_rml_builder; |                 std::unique_ptr<osmium::builder::RelationMemberListBuilder>  m_rml_builder; | ||||||
| 
 | 
 | ||||||
|                 osmium::thread::Queue<std::string>& m_input_queue; |                 std::string m_comment_text; | ||||||
|                 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; |  | ||||||
| 
 |  | ||||||
|                 bool m_header_is_done; |  | ||||||
| 
 | 
 | ||||||
|                 /**
 |                 /**
 | ||||||
|                  * A C++ wrapper for the Expat parser that makes sure no memory is leaked. |                  * A C++ wrapper for the Expat parser that makes sure no memory is leaked. | ||||||
|                  */ |                  */ | ||||||
|                 template <class T> |                 template <typename T> | ||||||
|                 class ExpatXMLParser { |                 class ExpatXMLParser { | ||||||
| 
 | 
 | ||||||
|                     XML_Parser m_parser; |                     XML_Parser m_parser; | ||||||
| @ -210,15 +188,20 @@ namespace osmium { | |||||||
|                         static_cast<XMLParser*>(data)->end_element(element); |                         static_cast<XMLParser*>(data)->end_element(element); | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|  |                     static void XMLCALL character_data_wrapper(void* data, const XML_Char* text, int len) { | ||||||
|  |                         static_cast<XMLParser*>(data)->characters(text, len); | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|                 public: |                 public: | ||||||
| 
 | 
 | ||||||
|                     ExpatXMLParser(T* callback_object) : |                     explicit ExpatXMLParser(T* callback_object) : | ||||||
|                         m_parser(XML_ParserCreate(nullptr)) { |                         m_parser(XML_ParserCreate(nullptr)) { | ||||||
|                         if (!m_parser) { |                         if (!m_parser) { | ||||||
|                             throw osmium::io_error("Internal error: Can not create parser"); |                             throw osmium::io_error("Internal error: Can not create parser"); | ||||||
|                         } |                         } | ||||||
|                         XML_SetUserData(m_parser, callback_object); |                         XML_SetUserData(m_parser, callback_object); | ||||||
|                         XML_SetElementHandler(m_parser, start_element_wrapper, end_element_wrapper); |                         XML_SetElementHandler(m_parser, start_element_wrapper, end_element_wrapper); | ||||||
|  |                         XML_SetCharacterDataHandler(m_parser, character_data_wrapper); | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                     ExpatXMLParser(const ExpatXMLParser&) = delete; |                     ExpatXMLParser(const ExpatXMLParser&) = delete; | ||||||
| @ -227,7 +210,7 @@ namespace osmium { | |||||||
|                     ExpatXMLParser& operator=(const ExpatXMLParser&) = delete; |                     ExpatXMLParser& operator=(const ExpatXMLParser&) = delete; | ||||||
|                     ExpatXMLParser& operator=(ExpatXMLParser&&) = delete; |                     ExpatXMLParser& operator=(ExpatXMLParser&&) = delete; | ||||||
| 
 | 
 | ||||||
|                     ~ExpatXMLParser() { |                     ~ExpatXMLParser() noexcept { | ||||||
|                         XML_ParserFree(m_parser); |                         XML_ParserFree(m_parser); | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
| @ -239,126 +222,14 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|                 }; // class ExpatXMLParser
 |                 }; // class ExpatXMLParser
 | ||||||
| 
 | 
 | ||||||
|                 /**
 |                 template <typename T> | ||||||
|                  * A helper class that makes sure a promise is kept. It stores |                 static void check_attributes(const XML_Char** attrs, T check) { | ||||||
|                  * a reference to some piece of data and to a promise and, on |                     while (*attrs) { | ||||||
|                  * destruction, sets the value of the promise from the data. |                         check(attrs[0], attrs[1]); | ||||||
|                  */ |                         attrs += 2; | ||||||
|                 template <class T> |  | ||||||
|                 class PromiseKeeper { |  | ||||||
| 
 |  | ||||||
|                     T& m_data; |  | ||||||
|                     std::promise<T>& m_promise; |  | ||||||
|                     bool m_done; |  | ||||||
| 
 |  | ||||||
|                 public: |  | ||||||
| 
 |  | ||||||
|                     PromiseKeeper(T& data, std::promise<T>& promise) : |  | ||||||
|                         m_data(data), |  | ||||||
|                         m_promise(promise), |  | ||||||
|                         m_done(false) { |  | ||||||
|                     } |                     } | ||||||
| 
 |  | ||||||
|                     void fullfill_promise() { |  | ||||||
|                         if (!m_done) { |  | ||||||
|                             m_promise.set_value(m_data); |  | ||||||
|                             m_done = true; |  | ||||||
|                         } |  | ||||||
|                     } |  | ||||||
| 
 |  | ||||||
|                     ~PromiseKeeper() { |  | ||||||
|                         fullfill_promise(); |  | ||||||
|                     } |  | ||||||
| 
 |  | ||||||
|                 }; // 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), |  | ||||||
|                     m_header_is_done(false) { |  | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 /**
 |  | ||||||
|                  * 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), |  | ||||||
|                     m_header_is_done(other.m_header_is_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); |  | ||||||
|                             if (m_header_is_done) { |  | ||||||
|                                 promise_keeper.fullfill_promise(); |  | ||||||
|                             } |  | ||||||
|                         } 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) { |                 const char* init_object(osmium::OSMObject& object, const XML_Char** attrs) { | ||||||
|                     const char* user = ""; |                     const char* user = ""; | ||||||
| 
 | 
 | ||||||
| @ -367,17 +238,18 @@ namespace osmium { | |||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                     osmium::Location location; |                     osmium::Location location; | ||||||
|                     for (int count = 0; attrs[count]; count += 2) { | 
 | ||||||
|                         if (!strcmp(attrs[count], "lon")) { |                     check_attributes(attrs, [&location, &user, &object](const XML_Char* name, const XML_Char* value) { | ||||||
|                             location.set_lon(std::atof(attrs[count+1])); // XXX doesn't detect garbage after the number
 |                         if (!strcmp(name, "lon")) { | ||||||
|                         } else if (!strcmp(attrs[count], "lat")) { |                             location.set_lon(std::atof(value)); // XXX doesn't detect garbage after the number
 | ||||||
|                             location.set_lat(std::atof(attrs[count+1])); // XXX doesn't detect garbage after the number
 |                         } else if (!strcmp(name, "lat")) { | ||||||
|                         } else if (!strcmp(attrs[count], "user")) { |                             location.set_lat(std::atof(value)); // XXX doesn't detect garbage after the number
 | ||||||
|                             user = attrs[count+1]; |                         } else if (!strcmp(name, "user")) { | ||||||
|  |                             user = value; | ||||||
|                         } else { |                         } else { | ||||||
|                             object.set_attribute(attrs[count], attrs[count+1]); |                             object.set_attribute(name, value); | ||||||
|                         } |                         } | ||||||
|                     } |                     }); | ||||||
| 
 | 
 | ||||||
|                     if (location && object.type() == osmium::item_type::node) { |                     if (location && object.type() == osmium::item_type::node) { | ||||||
|                         static_cast<osmium::Node&>(object).set_location(location); |                         static_cast<osmium::Node&>(object).set_location(location); | ||||||
| @ -392,21 +264,21 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|                     osmium::Location min; |                     osmium::Location min; | ||||||
|                     osmium::Location max; |                     osmium::Location max; | ||||||
|                     for (int count = 0; attrs[count]; count += 2) { |                     check_attributes(attrs, [&min, &max, &user, &new_changeset](const XML_Char* name, const XML_Char* value) { | ||||||
|                         if (!strcmp(attrs[count], "min_lon")) { |                         if (!strcmp(name, "min_lon")) { | ||||||
|                             min.set_lon(atof(attrs[count+1])); |                             min.set_lon(atof(value)); | ||||||
|                         } else if (!strcmp(attrs[count], "min_lat")) { |                         } else if (!strcmp(name, "min_lat")) { | ||||||
|                             min.set_lat(atof(attrs[count+1])); |                             min.set_lat(atof(value)); | ||||||
|                         } else if (!strcmp(attrs[count], "max_lon")) { |                         } else if (!strcmp(name, "max_lon")) { | ||||||
|                             max.set_lon(atof(attrs[count+1])); |                             max.set_lon(atof(value)); | ||||||
|                         } else if (!strcmp(attrs[count], "max_lat")) { |                         } else if (!strcmp(name, "max_lat")) { | ||||||
|                             max.set_lat(atof(attrs[count+1])); |                             max.set_lat(atof(value)); | ||||||
|                         } else if (!strcmp(attrs[count], "user")) { |                         } else if (!strcmp(name, "user")) { | ||||||
|                             user = attrs[count+1]; |                             user = value; | ||||||
|                         } else { |                         } else { | ||||||
|                             new_changeset.set_attribute(attrs[count], attrs[count+1]); |                             new_changeset.set_attribute(name, value); | ||||||
|                         } |                         } | ||||||
|                     } |                     }); | ||||||
| 
 | 
 | ||||||
|                     new_changeset.bounds().extend(min); |                     new_changeset.bounds().extend(min); | ||||||
|                     new_changeset.bounds().extend(max); |                     new_changeset.bounds().extend(max); | ||||||
| @ -414,32 +286,24 @@ namespace osmium { | |||||||
|                     builder->add_user(user); |                     builder->add_user(user); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void check_tag(osmium::builder::Builder* builder, const XML_Char* element, const XML_Char** attrs) { |                 void get_tag(osmium::builder::Builder* builder, const XML_Char** attrs) { | ||||||
|                     if (!strcmp(element, "tag")) { |                     const char* k = ""; | ||||||
|                         m_wnl_builder.reset(); |                     const char* v = ""; | ||||||
|                         m_rml_builder.reset(); |                     check_attributes(attrs, [&k, &v](const XML_Char* name, const XML_Char* value) { | ||||||
| 
 |                         if (name[0] == 'k' && name[1] == 0) { | ||||||
|                         const char* key = ""; |                             k = value; | ||||||
|                         const char* value = ""; |                         } else if (name[0] == 'v' && name[1] == 0) { | ||||||
|                         for (int count = 0; attrs[count]; count += 2) { |                             v = value; | ||||||
|                             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)); |                     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); |  | ||||||
|                     } |                     } | ||||||
|  |                     m_tl_builder->add_tag(k, v); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void header_is_done() { |                 void mark_header_as_done() { | ||||||
|                     m_header_is_done = true; |                     set_header_value(m_header); | ||||||
|                     if (m_read_types == osmium::osm_entity_bits::nothing) { |  | ||||||
|                         throw ParserIsDone(); |  | ||||||
|                     } |  | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void start_element(const XML_Char* element, const XML_Char** attrs) { |                 void start_element(const XML_Char* element, const XML_Char** attrs) { | ||||||
| @ -449,16 +313,16 @@ namespace osmium { | |||||||
|                                 if (!strcmp(element, "osmChange")) { |                                 if (!strcmp(element, "osmChange")) { | ||||||
|                                     m_header.set_has_multiple_object_versions(true); |                                     m_header.set_has_multiple_object_versions(true); | ||||||
|                                 } |                                 } | ||||||
|                                 for (int count = 0; attrs[count]; count += 2) { |                                 check_attributes(attrs, [this](const XML_Char* name, const XML_Char* value) { | ||||||
|                                     if (!strcmp(attrs[count], "version")) { |                                     if (!strcmp(name, "version")) { | ||||||
|                                         m_header.set("version", attrs[count+1]); |                                         m_header.set("version", value); | ||||||
|                                         if (strcmp(attrs[count+1], "0.6")) { |                                         if (strcmp(value, "0.6")) { | ||||||
|                                             throw osmium::format_version_error(attrs[count+1]); |                                             throw osmium::format_version_error(value); | ||||||
|                                         } |                                         } | ||||||
|                                     } else if (!strcmp(attrs[count], "generator")) { |                                     } else if (!strcmp(name, "generator")) { | ||||||
|                                         m_header.set("generator", attrs[count+1]); |                                         m_header.set("generator", value); | ||||||
|                                     } |                                     } | ||||||
|                                 } |                                 }); | ||||||
|                                 if (m_header.get("version") == "") { |                                 if (m_header.get("version") == "") { | ||||||
|                                     throw osmium::format_version_error(); |                                     throw osmium::format_version_error(); | ||||||
|                                 } |                                 } | ||||||
| @ -470,8 +334,8 @@ namespace osmium { | |||||||
|                         case context::top: |                         case context::top: | ||||||
|                             assert(!m_tl_builder); |                             assert(!m_tl_builder); | ||||||
|                             if (!strcmp(element, "node")) { |                             if (!strcmp(element, "node")) { | ||||||
|                                 header_is_done(); |                                 mark_header_as_done(); | ||||||
|                                 if (m_read_types & osmium::osm_entity_bits::node) { |                                 if (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 = 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_node_builder->add_user(init_object(m_node_builder->object(), attrs)); | ||||||
|                                     m_context = context::node; |                                     m_context = context::node; | ||||||
| @ -479,8 +343,8 @@ namespace osmium { | |||||||
|                                     m_context = context::ignored_node; |                                     m_context = context::ignored_node; | ||||||
|                                 } |                                 } | ||||||
|                             } else if (!strcmp(element, "way")) { |                             } else if (!strcmp(element, "way")) { | ||||||
|                                 header_is_done(); |                                 mark_header_as_done(); | ||||||
|                                 if (m_read_types & osmium::osm_entity_bits::way) { |                                 if (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 = 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_way_builder->add_user(init_object(m_way_builder->object(), attrs)); | ||||||
|                                     m_context = context::way; |                                     m_context = context::way; | ||||||
| @ -488,8 +352,8 @@ namespace osmium { | |||||||
|                                     m_context = context::ignored_way; |                                     m_context = context::ignored_way; | ||||||
|                                 } |                                 } | ||||||
|                             } else if (!strcmp(element, "relation")) { |                             } else if (!strcmp(element, "relation")) { | ||||||
|                                 header_is_done(); |                                 mark_header_as_done(); | ||||||
|                                 if (m_read_types & osmium::osm_entity_bits::relation) { |                                 if (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 = 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_relation_builder->add_user(init_object(m_relation_builder->object(), attrs)); | ||||||
|                                     m_context = context::relation; |                                     m_context = context::relation; | ||||||
| @ -497,8 +361,8 @@ namespace osmium { | |||||||
|                                     m_context = context::ignored_relation; |                                     m_context = context::ignored_relation; | ||||||
|                                 } |                                 } | ||||||
|                             } else if (!strcmp(element, "changeset")) { |                             } else if (!strcmp(element, "changeset")) { | ||||||
|                                 header_is_done(); |                                 mark_header_as_done(); | ||||||
|                                 if (m_read_types & osmium::osm_entity_bits::changeset) { |                                 if (read_types() & osmium::osm_entity_bits::changeset) { | ||||||
|                                     m_changeset_builder = std::unique_ptr<osmium::builder::ChangesetBuilder>(new osmium::builder::ChangesetBuilder(m_buffer)); |                                     m_changeset_builder = std::unique_ptr<osmium::builder::ChangesetBuilder>(new osmium::builder::ChangesetBuilder(m_buffer)); | ||||||
|                                     init_changeset(m_changeset_builder.get(), attrs); |                                     init_changeset(m_changeset_builder.get(), attrs); | ||||||
|                                     m_context = context::changeset; |                                     m_context = context::changeset; | ||||||
| @ -508,17 +372,17 @@ namespace osmium { | |||||||
|                             } else if (!strcmp(element, "bounds")) { |                             } else if (!strcmp(element, "bounds")) { | ||||||
|                                 osmium::Location min; |                                 osmium::Location min; | ||||||
|                                 osmium::Location max; |                                 osmium::Location max; | ||||||
|                                 for (int count = 0; attrs[count]; count += 2) { |                                 check_attributes(attrs, [&min, &max](const XML_Char* name, const XML_Char* value) { | ||||||
|                                     if (!strcmp(attrs[count], "minlon")) { |                                     if (!strcmp(name, "minlon")) { | ||||||
|                                         min.set_lon(atof(attrs[count+1])); |                                         min.set_lon(atof(value)); | ||||||
|                                     } else if (!strcmp(attrs[count], "minlat")) { |                                     } else if (!strcmp(name, "minlat")) { | ||||||
|                                         min.set_lat(atof(attrs[count+1])); |                                         min.set_lat(atof(value)); | ||||||
|                                     } else if (!strcmp(attrs[count], "maxlon")) { |                                     } else if (!strcmp(name, "maxlon")) { | ||||||
|                                         max.set_lon(atof(attrs[count+1])); |                                         max.set_lon(atof(value)); | ||||||
|                                     } else if (!strcmp(attrs[count], "maxlat")) { |                                     } else if (!strcmp(name, "maxlat")) { | ||||||
|                                         max.set_lat(atof(attrs[count+1])); |                                         max.set_lat(atof(value)); | ||||||
|                                     } |                                     } | ||||||
|                                 } |                                 }); | ||||||
|                                 osmium::Box box; |                                 osmium::Box box; | ||||||
|                                 box.extend(min).extend(max); |                                 box.extend(min).extend(max); | ||||||
|                                 m_header.add_box(box); |                                 m_header.add_box(box); | ||||||
| @ -529,7 +393,9 @@ namespace osmium { | |||||||
|                         case context::node: |                         case context::node: | ||||||
|                             m_last_context = context::node; |                             m_last_context = context::node; | ||||||
|                             m_context = context::in_object; |                             m_context = context::in_object; | ||||||
|                             check_tag(m_node_builder.get(), element, attrs); |                             if (!strcmp(element, "tag")) { | ||||||
|  |                                 get_tag(m_node_builder.get(), attrs); | ||||||
|  |                             } | ||||||
|                             break; |                             break; | ||||||
|                         case context::way: |                         case context::way: | ||||||
|                             m_last_context = context::way; |                             m_last_context = context::way; | ||||||
| @ -541,13 +407,14 @@ namespace osmium { | |||||||
|                                     m_wnl_builder = std::unique_ptr<osmium::builder::WayNodeListBuilder>(new osmium::builder::WayNodeListBuilder(m_buffer, m_way_builder.get())); |                                     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) { |                                 check_attributes(attrs, [this](const XML_Char* name, const XML_Char* value) { | ||||||
|                                     if (!strcmp(attrs[count], "ref")) { |                                     if (!strcmp(name, "ref")) { | ||||||
|                                         m_wnl_builder->add_node_ref(osmium::string_to_object_id(attrs[count+1])); |                                         m_wnl_builder->add_node_ref(osmium::string_to_object_id(value)); | ||||||
|                                     } |                                     } | ||||||
|                                 } |                                 }); | ||||||
|                             } else { |                             } else if (!strcmp(element, "tag")) { | ||||||
|                                 check_tag(m_way_builder.get(), element, attrs); |                                 m_wnl_builder.reset(); | ||||||
|  |                                 get_tag(m_way_builder.get(), attrs); | ||||||
|                             } |                             } | ||||||
|                             break; |                             break; | ||||||
|                         case context::relation: |                         case context::relation: | ||||||
| @ -560,28 +427,68 @@ namespace osmium { | |||||||
|                                     m_rml_builder = std::unique_ptr<osmium::builder::RelationMemberListBuilder>(new osmium::builder::RelationMemberListBuilder(m_buffer, m_relation_builder.get())); |                                     m_rml_builder = std::unique_ptr<osmium::builder::RelationMemberListBuilder>(new osmium::builder::RelationMemberListBuilder(m_buffer, m_relation_builder.get())); | ||||||
|                                 } |                                 } | ||||||
| 
 | 
 | ||||||
|                                 char type = 'x'; |                                 item_type type = item_type::undefined; | ||||||
|                                 object_id_type ref  = 0; |                                 object_id_type ref = 0; | ||||||
|                                 const char* role = ""; |                                 const char* role = ""; | ||||||
|                                 for (int count = 0; attrs[count]; count += 2) { |                                 check_attributes(attrs, [&type, &ref, &role](const XML_Char* name, const XML_Char* value) { | ||||||
|                                     if (!strcmp(attrs[count], "type")) { |                                     if (!strcmp(name, "type")) { | ||||||
|                                         type = static_cast<char>(attrs[count+1][0]); |                                         type = char_to_item_type(value[0]); | ||||||
|                                     } else if (!strcmp(attrs[count], "ref")) { |                                     } else if (!strcmp(name, "ref")) { | ||||||
|                                         ref = osmium::string_to_object_id(attrs[count+1]); |                                         ref = osmium::string_to_object_id(value); | ||||||
|                                     } else if (!strcmp(attrs[count], "role")) { |                                     } else if (!strcmp(name, "role")) { | ||||||
|                                         role = static_cast<const char*>(attrs[count+1]); |                                         role = static_cast<const char*>(value); | ||||||
|                                     } |                                     } | ||||||
|  |                                 }); | ||||||
|  |                                 if (type != item_type::node && type != item_type::way && type != item_type::relation) { | ||||||
|  |                                     throw osmium::xml_error("Unknown type on relation member"); | ||||||
|                                 } |                                 } | ||||||
|                                 // XXX assert type, ref, role are set
 |                                 if (ref == 0) { | ||||||
|                                 m_rml_builder->add_member(char_to_item_type(type), ref, role); |                                     throw osmium::xml_error("Missing ref on relation member"); | ||||||
|                             } else { |                                 } | ||||||
|                                 check_tag(m_relation_builder.get(), element, attrs); |                                 m_rml_builder->add_member(type, ref, role); | ||||||
|  |                             } else if (!strcmp(element, "tag")) { | ||||||
|  |                                 m_rml_builder.reset(); | ||||||
|  |                                 get_tag(m_relation_builder.get(), attrs); | ||||||
|                             } |                             } | ||||||
|                             break; |                             break; | ||||||
|                         case context::changeset: |                         case context::changeset: | ||||||
|                             m_last_context = context::changeset; |                             m_last_context = context::changeset; | ||||||
|                             m_context = context::in_object; |                             if (!strcmp(element, "discussion")) { | ||||||
|                             check_tag(m_changeset_builder.get(), element, attrs); |                                 m_context = context::discussion; | ||||||
|  |                                 m_tl_builder.reset(); | ||||||
|  |                                 if (!m_changeset_discussion_builder) { | ||||||
|  |                                     m_changeset_discussion_builder = std::unique_ptr<osmium::builder::ChangesetDiscussionBuilder>(new osmium::builder::ChangesetDiscussionBuilder(m_buffer, m_changeset_builder.get())); | ||||||
|  |                                 } | ||||||
|  |                             } else if (!strcmp(element, "tag")) { | ||||||
|  |                                 m_context = context::in_object; | ||||||
|  |                                 m_changeset_discussion_builder.reset(); | ||||||
|  |                                 get_tag(m_changeset_builder.get(), attrs); | ||||||
|  |                             } | ||||||
|  |                             break; | ||||||
|  |                         case context::discussion: | ||||||
|  |                             if (!strcmp(element, "comment")) { | ||||||
|  |                                 m_context = context::comment; | ||||||
|  |                                 osmium::Timestamp date; | ||||||
|  |                                 osmium::user_id_type uid = 0; | ||||||
|  |                                 const char* user = ""; | ||||||
|  |                                 check_attributes(attrs, [&date, &uid, &user](const XML_Char* name, const XML_Char* value) { | ||||||
|  |                                     if (!strcmp(name, "date")) { | ||||||
|  |                                         date = osmium::Timestamp(value); | ||||||
|  |                                     } else if (!strcmp(name, "uid")) { | ||||||
|  |                                         uid = osmium::string_to_user_id(value); | ||||||
|  |                                     } else if (!strcmp(name, "user")) { | ||||||
|  |                                         user = static_cast<const char*>(value); | ||||||
|  |                                     } | ||||||
|  |                                 }); | ||||||
|  |                                 m_changeset_discussion_builder->add_comment(date, uid, user); | ||||||
|  |                             } | ||||||
|  |                             break; | ||||||
|  |                         case context::comment: | ||||||
|  |                             if (!strcmp(element, "text")) { | ||||||
|  |                                 m_context = context::comment_text; | ||||||
|  |                             } | ||||||
|  |                             break; | ||||||
|  |                         case context::comment_text: | ||||||
|                             break; |                             break; | ||||||
|                         case context::ignored_node: |                         case context::ignored_node: | ||||||
|                             break; |                             break; | ||||||
| @ -604,7 +511,7 @@ namespace osmium { | |||||||
|                             break; |                             break; | ||||||
|                         case context::top: |                         case context::top: | ||||||
|                             if (!strcmp(element, "osm") || !strcmp(element, "osmChange")) { |                             if (!strcmp(element, "osm") || !strcmp(element, "osmChange")) { | ||||||
|                                 header_is_done(); |                                 mark_header_as_done(); | ||||||
|                                 m_context = context::root; |                                 m_context = context::root; | ||||||
|                             } else if (!strcmp(element, "delete")) { |                             } else if (!strcmp(element, "delete")) { | ||||||
|                                 m_in_delete_section = false; |                                 m_in_delete_section = false; | ||||||
| @ -639,11 +546,25 @@ namespace osmium { | |||||||
|                         case context::changeset: |                         case context::changeset: | ||||||
|                             assert(!strcmp(element, "changeset")); |                             assert(!strcmp(element, "changeset")); | ||||||
|                             m_tl_builder.reset(); |                             m_tl_builder.reset(); | ||||||
|  |                             m_changeset_discussion_builder.reset(); | ||||||
|                             m_changeset_builder.reset(); |                             m_changeset_builder.reset(); | ||||||
|                             m_buffer.commit(); |                             m_buffer.commit(); | ||||||
|                             m_context = context::top; |                             m_context = context::top; | ||||||
|                             flush_buffer(); |                             flush_buffer(); | ||||||
|                             break; |                             break; | ||||||
|  |                         case context::discussion: | ||||||
|  |                             assert(!strcmp(element, "discussion")); | ||||||
|  |                             m_context = context::changeset; | ||||||
|  |                             break; | ||||||
|  |                         case context::comment: | ||||||
|  |                             assert(!strcmp(element, "comment")); | ||||||
|  |                             m_context = context::discussion; | ||||||
|  |                             break; | ||||||
|  |                         case context::comment_text: | ||||||
|  |                             assert(!strcmp(element, "text")); | ||||||
|  |                             m_context = context::comment; | ||||||
|  |                             m_changeset_discussion_builder->add_comment_text(m_comment_text); | ||||||
|  |                             break; | ||||||
|                         case context::in_object: |                         case context::in_object: | ||||||
|                             m_context = m_last_context; |                             m_context = m_last_context; | ||||||
|                             break; |                             break; | ||||||
| @ -670,85 +591,84 @@ namespace osmium { | |||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|  |                 void characters(const XML_Char* text, int len) { | ||||||
|  |                     if (m_context == context::comment_text) { | ||||||
|  |                         m_comment_text.append(text, len); | ||||||
|  |                     } else { | ||||||
|  |                         m_comment_text.resize(0); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|                 void flush_buffer() { |                 void flush_buffer() { | ||||||
|                     if (m_buffer.capacity() - m_buffer.committed() < 1000 * 1000) { |                     if (m_buffer.committed() > buffer_size / 10 * 9) { | ||||||
|                         m_queue.push(std::move(m_buffer)); |                         send_to_output_queue(std::move(m_buffer)); | ||||||
|                         osmium::memory::Buffer buffer(buffer_size); |                         osmium::memory::Buffer buffer(buffer_size); | ||||||
|                         std::swap(m_buffer, buffer); |                         using std::swap; | ||||||
|  |                         swap(m_buffer, buffer); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |             public: | ||||||
|  | 
 | ||||||
|  |                 XMLParser(future_string_queue_type& input_queue, | ||||||
|  |                           future_buffer_queue_type& output_queue, | ||||||
|  |                           std::promise<osmium::io::Header>& header_promise, | ||||||
|  |                           osmium::osm_entity_bits::type read_types) : | ||||||
|  |                     Parser(input_queue, output_queue, header_promise, read_types), | ||||||
|  |                     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_changeset_discussion_builder(), | ||||||
|  |                     m_tl_builder(), | ||||||
|  |                     m_wnl_builder(), | ||||||
|  |                     m_rml_builder() { | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 ~XMLParser() noexcept final = default; | ||||||
|  | 
 | ||||||
|  |                 void run() final { | ||||||
|  |                     osmium::thread::set_thread_name("_osmium_xml_in"); | ||||||
|  | 
 | ||||||
|  |                     ExpatXMLParser<XMLParser> parser(this); | ||||||
|  | 
 | ||||||
|  |                     while (!input_done()) { | ||||||
|  |                         std::string data = get_input(); | ||||||
|  |                         parser(data, input_done()); | ||||||
|  |                         if (read_types() == osmium::osm_entity_bits::nothing && header_is_done()) { | ||||||
|  |                             break; | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     mark_header_as_done(); | ||||||
|  | 
 | ||||||
|  |                     if (m_buffer.committed() > 0) { | ||||||
|  |                         send_to_output_queue(std::move(m_buffer)); | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|             }; // class XMLParser
 |             }; // class XMLParser
 | ||||||
| 
 | 
 | ||||||
|             class XMLInputFormat : public osmium::io::detail::InputFormat { |             // we want the register_parser() function to run, setting
 | ||||||
|  |             // the variable is only a side-effect, it will never be used
 | ||||||
|  |             const bool registered_xml_parser = ParserFactory::instance().register_parser( | ||||||
|  |                 file_format::xml, | ||||||
|  |                 [](future_string_queue_type& input_queue, | ||||||
|  |                     future_buffer_queue_type& output_queue, | ||||||
|  |                     std::promise<osmium::io::Header>& header_promise, | ||||||
|  |                     osmium::osm_entity_bits::type read_which_entities) { | ||||||
|  |                     return std::unique_ptr<Parser>(new XMLParser(input_queue, output_queue, header_promise, read_which_entities)); | ||||||
|  |             }); | ||||||
| 
 | 
 | ||||||
|                 static constexpr size_t max_queue_size = 100; |             // dummy function to silence the unused variable warning from above
 | ||||||
| 
 |             inline bool get_registered_xml_parser() noexcept { | ||||||
|                 osmium::thread::Queue<osmium::memory::Buffer> m_queue; |                 return registered_xml_parser; | ||||||
|                 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), |  | ||||||
|                     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() override { |  | ||||||
|                     m_done = true; |  | ||||||
|                     osmium::thread::wait_until_done(m_parser_future); |  | ||||||
|                 } |  | ||||||
| 
 |  | ||||||
|             }; // class XMLInputFormat
 |  | ||||||
| 
 |  | ||||||
|             namespace { |  | ||||||
| 
 |  | ||||||
| // we want the register_input_format() function to run, setting the variable
 |  | ||||||
| // is only a side-effect, it will never be used
 |  | ||||||
| #pragma GCC diagnostic push |  | ||||||
| #pragma GCC diagnostic ignored "-Wunused-variable" |  | ||||||
|                 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); |  | ||||||
|                 }); |  | ||||||
| #pragma GCC diagnostic pop |  | ||||||
| 
 |  | ||||||
|             } // anonymous namespace
 |  | ||||||
| 
 | 
 | ||||||
|         } // namespace detail
 |         } // namespace detail
 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -33,20 +33,17 @@ DEALINGS IN THE SOFTWARE. | |||||||
| 
 | 
 | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| #include <cassert> | #include <algorithm> | ||||||
| #include <chrono> |  | ||||||
| #include <cinttypes> | #include <cinttypes> | ||||||
| #include <cstddef> | #include <cstddef> | ||||||
| #include <cstdio> | #include <cstdio> | ||||||
| #include <future> | #include <future> | ||||||
| #include <iterator> | #include <iterator> | ||||||
| #include <memory> | #include <memory> | ||||||
| #include <ratio> |  | ||||||
| #include <string> | #include <string> | ||||||
| #include <thread> | #include <thread> | ||||||
| #include <utility> | #include <utility> | ||||||
| 
 | 
 | ||||||
| #include <osmium/handler.hpp> |  | ||||||
| #include <osmium/io/detail/output_format.hpp> | #include <osmium/io/detail/output_format.hpp> | ||||||
| #include <osmium/io/file.hpp> | #include <osmium/io/file.hpp> | ||||||
| #include <osmium/io/file_format.hpp> | #include <osmium/io/file_format.hpp> | ||||||
| @ -75,45 +72,23 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|             struct XMLWriteError {}; |             struct XMLWriteError {}; | ||||||
| 
 | 
 | ||||||
|             namespace { |             struct xml_output_options { | ||||||
| 
 | 
 | ||||||
|                 void xml_string(std::string& out, const char* in) { |                 /// Should metadata of objects be added?
 | ||||||
|                     for (; *in != '\0'; ++in) { |                 bool add_metadata; | ||||||
|                         switch(*in) { |  | ||||||
|                             case '&':  out += "&";  break; |  | ||||||
|                             case '\"': out += """; break; |  | ||||||
|                             case '\'': out += "'"; break; |  | ||||||
|                             case '<':  out += "<";   break; |  | ||||||
|                             case '>':  out += ">";   break; |  | ||||||
|                             case '\n': out += "
";  break; |  | ||||||
|                             case '\r': out += "
";  break; |  | ||||||
|                             case '\t': out += "	";  break; |  | ||||||
|                             default:   out += *in;      break; |  | ||||||
|                         } |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
| 
 | 
 | ||||||
|                 const size_t tmp_buffer_size = 100; |                 /// Should the visible flag be added to all OSM objects?
 | ||||||
|  |                 bool add_visible_flag; | ||||||
| 
 | 
 | ||||||
|                 template <typename T> |                 /**
 | ||||||
|                 void oprintf(std::string& out, const char* format, T value) { |                  * Should <create>, <modify>, <delete> "operations" be added? | ||||||
|                     char buffer[tmp_buffer_size+1]; |                  * (This is used for .osc files.) | ||||||
|                     size_t max_size = sizeof(buffer)/sizeof(char); |                  */ | ||||||
| #ifndef NDEBUG |                 bool use_change_ops; | ||||||
|                     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 { |             class XMLOutputBlock : public OutputBlock { | ||||||
| 
 | 
 | ||||||
|                 // operation (create, modify, delete) for osc files
 |                 // operation (create, modify, delete) for osc files
 | ||||||
|                 enum class operation { |                 enum class operation { | ||||||
| @ -123,15 +98,9 @@ namespace osmium { | |||||||
|                     op_delete = 3 |                     op_delete = 3 | ||||||
|                 }; // enum class operation
 |                 }; // enum class operation
 | ||||||
| 
 | 
 | ||||||
|                 std::shared_ptr<osmium::memory::Buffer> m_input_buffer; |  | ||||||
| 
 |  | ||||||
|                 std::shared_ptr<std::string> m_out; |  | ||||||
| 
 |  | ||||||
|                 operation m_last_op {operation::op_none}; |                 operation m_last_op {operation::op_none}; | ||||||
| 
 | 
 | ||||||
|                 const bool m_add_metadata; |                 xml_output_options m_options; | ||||||
|                 const bool m_write_visible_flag; |  | ||||||
|                 const bool m_write_change_ops; |  | ||||||
| 
 | 
 | ||||||
|                 void write_spaces(int num) { |                 void write_spaces(int num) { | ||||||
|                     for (; num != 0; --num) { |                     for (; num != 0; --num) { | ||||||
| @ -139,20 +108,20 @@ namespace osmium { | |||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|  |                 int prefix_spaces() { | ||||||
|  |                     return m_options.use_change_ops ? 4 : 2; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|                 void write_prefix() { |                 void write_prefix() { | ||||||
|                     if (m_write_change_ops) { |                     write_spaces(prefix_spaces()); | ||||||
|                         write_spaces(4); |  | ||||||
|                     } else { |  | ||||||
|                         write_spaces(2); |  | ||||||
|                     } |  | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void write_meta(const osmium::OSMObject& object) { |                 void write_meta(const osmium::OSMObject& object) { | ||||||
|                     oprintf(*m_out, " id=\"%" PRId64 "\"", object.id()); |                     output_formatted(" id=\"%" PRId64 "\"", object.id()); | ||||||
| 
 | 
 | ||||||
|                     if (m_add_metadata) { |                     if (m_options.add_metadata) { | ||||||
|                         if (object.version()) { |                         if (object.version()) { | ||||||
|                             oprintf(*m_out, " version=\"%d\"", object.version()); |                             output_formatted(" version=\"%d\"", object.version()); | ||||||
|                         } |                         } | ||||||
| 
 | 
 | ||||||
|                         if (object.timestamp()) { |                         if (object.timestamp()) { | ||||||
| @ -162,16 +131,16 @@ namespace osmium { | |||||||
|                         } |                         } | ||||||
| 
 | 
 | ||||||
|                         if (!object.user_is_anonymous()) { |                         if (!object.user_is_anonymous()) { | ||||||
|                             oprintf(*m_out, " uid=\"%d\" user=\"", object.uid()); |                             output_formatted(" uid=\"%d\" user=\"", object.uid()); | ||||||
|                             xml_string(*m_out, object.user()); |                             append_xml_encoded_string(*m_out, object.user()); | ||||||
|                             *m_out += "\""; |                             *m_out += "\""; | ||||||
|                         } |                         } | ||||||
| 
 | 
 | ||||||
|                         if (object.changeset()) { |                         if (object.changeset()) { | ||||||
|                             oprintf(*m_out, " changeset=\"%d\"", object.changeset()); |                             output_formatted(" changeset=\"%d\"", object.changeset()); | ||||||
|                         } |                         } | ||||||
| 
 | 
 | ||||||
|                         if (m_write_visible_flag) { |                         if (m_options.add_visible_flag) { | ||||||
|                             if (object.visible()) { |                             if (object.visible()) { | ||||||
|                                 *m_out += " visible=\"true\""; |                                 *m_out += " visible=\"true\""; | ||||||
|                             } else { |                             } else { | ||||||
| @ -181,17 +150,31 @@ namespace osmium { | |||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void write_tags(const osmium::TagList& tags) { |                 void write_tags(const osmium::TagList& tags, int spaces) { | ||||||
|                     for (const auto& tag : tags) { |                     for (const auto& tag : tags) { | ||||||
|                         write_prefix(); |                         write_spaces(spaces); | ||||||
|                         *m_out += "  <tag k=\""; |                         *m_out += "  <tag k=\""; | ||||||
|                         xml_string(*m_out, tag.key()); |                         append_xml_encoded_string(*m_out, tag.key()); | ||||||
|                         *m_out += "\" v=\""; |                         *m_out += "\" v=\""; | ||||||
|                         xml_string(*m_out, tag.value()); |                         append_xml_encoded_string(*m_out, tag.value()); | ||||||
|                         *m_out += "\"/>\n"; |                         *m_out += "\"/>\n"; | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|  |                 void write_discussion(const osmium::ChangesetDiscussion& comments) { | ||||||
|  |                     for (const auto& comment : comments) { | ||||||
|  |                         output_formatted("   <comment uid=\"%d\" user=\"", comment.uid()); | ||||||
|  |                         append_xml_encoded_string(*m_out, comment.user()); | ||||||
|  |                         *m_out += "\" date=\""; | ||||||
|  |                         *m_out += comment.date().to_iso(); | ||||||
|  |                         *m_out += "\">\n"; | ||||||
|  |                         *m_out += "    <text>"; | ||||||
|  |                         append_xml_encoded_string(*m_out, comment.text()); | ||||||
|  |                         *m_out += "</text>\n   </comment>\n"; | ||||||
|  |                     } | ||||||
|  |                     *m_out += "  </discussion>\n"; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|                 void open_close_op_tag(const operation op = operation::op_none) { |                 void open_close_op_tag(const operation op = operation::op_none) { | ||||||
|                     if (op == m_last_op) { |                     if (op == m_last_op) { | ||||||
|                         return; |                         return; | ||||||
| @ -230,12 +213,9 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|             public: |             public: | ||||||
| 
 | 
 | ||||||
|                 explicit XMLOutputBlock(osmium::memory::Buffer&& buffer, bool add_metadata, bool write_visible_flag, bool write_change_ops) : |                 XMLOutputBlock(osmium::memory::Buffer&& buffer, const xml_output_options& options) : | ||||||
|                     m_input_buffer(std::make_shared<osmium::memory::Buffer>(std::move(buffer))), |                     OutputBlock(std::move(buffer)), | ||||||
|                     m_out(std::make_shared<std::string>()), |                     m_options(options) { | ||||||
|                     m_add_metadata(add_metadata), |  | ||||||
|                     m_write_visible_flag(write_visible_flag && !write_change_ops), |  | ||||||
|                     m_write_change_ops(write_change_ops) { |  | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 XMLOutputBlock(const XMLOutputBlock&) = default; |                 XMLOutputBlock(const XMLOutputBlock&) = default; | ||||||
| @ -244,22 +224,24 @@ namespace osmium { | |||||||
|                 XMLOutputBlock(XMLOutputBlock&&) = default; |                 XMLOutputBlock(XMLOutputBlock&&) = default; | ||||||
|                 XMLOutputBlock& operator=(XMLOutputBlock&&) = default; |                 XMLOutputBlock& operator=(XMLOutputBlock&&) = default; | ||||||
| 
 | 
 | ||||||
|                 ~XMLOutputBlock() = default; |                 ~XMLOutputBlock() noexcept = default; | ||||||
| 
 | 
 | ||||||
|                 std::string operator()() { |                 std::string operator()() { | ||||||
|                     osmium::apply(m_input_buffer->cbegin(), m_input_buffer->cend(), *this); |                     osmium::apply(m_input_buffer->cbegin(), m_input_buffer->cend(), *this); | ||||||
| 
 | 
 | ||||||
|                     if (m_write_change_ops) { |                     if (m_options.use_change_ops) { | ||||||
|                         open_close_op_tag(); |                         open_close_op_tag(); | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                     std::string out; |                     std::string out; | ||||||
|                     std::swap(out, *m_out); |                     using std::swap; | ||||||
|  |                     swap(out, *m_out); | ||||||
|  | 
 | ||||||
|                     return out; |                     return out; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void node(const osmium::Node& node) { |                 void node(const osmium::Node& node) { | ||||||
|                     if (m_write_change_ops) { |                     if (m_options.use_change_ops) { | ||||||
|                         open_close_op_tag(node.visible() ? (node.version() == 1 ? operation::op_create : operation::op_modify) : operation::op_delete); |                         open_close_op_tag(node.visible() ? (node.version() == 1 ? operation::op_create : operation::op_modify) : operation::op_delete); | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
| @ -283,14 +265,14 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|                     *m_out += ">\n"; |                     *m_out += ">\n"; | ||||||
| 
 | 
 | ||||||
|                     write_tags(node.tags()); |                     write_tags(node.tags(), prefix_spaces()); | ||||||
| 
 | 
 | ||||||
|                     write_prefix(); |                     write_prefix(); | ||||||
|                     *m_out += "</node>\n"; |                     *m_out += "</node>\n"; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void way(const osmium::Way& way) { |                 void way(const osmium::Way& way) { | ||||||
|                     if (m_write_change_ops) { |                     if (m_options.use_change_ops) { | ||||||
|                         open_close_op_tag(way.visible() ? (way.version() == 1 ? operation::op_create : operation::op_modify) : operation::op_delete); |                         open_close_op_tag(way.visible() ? (way.version() == 1 ? operation::op_create : operation::op_modify) : operation::op_delete); | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
| @ -307,17 +289,17 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|                     for (const auto& node_ref : way.nodes()) { |                     for (const auto& node_ref : way.nodes()) { | ||||||
|                         write_prefix(); |                         write_prefix(); | ||||||
|                         oprintf(*m_out, "  <nd ref=\"%" PRId64 "\"/>\n", node_ref.ref()); |                         output_formatted("  <nd ref=\"%" PRId64 "\"/>\n", node_ref.ref()); | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                     write_tags(way.tags()); |                     write_tags(way.tags(), prefix_spaces()); | ||||||
| 
 | 
 | ||||||
|                     write_prefix(); |                     write_prefix(); | ||||||
|                     *m_out += "</way>\n"; |                     *m_out += "</way>\n"; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void relation(const osmium::Relation& relation) { |                 void relation(const osmium::Relation& relation) { | ||||||
|                     if (m_write_change_ops) { |                     if (m_options.use_change_ops) { | ||||||
|                         open_close_op_tag(relation.visible() ? (relation.version() == 1 ? operation::op_create : operation::op_modify) : operation::op_delete); |                         open_close_op_tag(relation.visible() ? (relation.version() == 1 ? operation::op_create : operation::op_modify) : operation::op_delete); | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
| @ -336,22 +318,21 @@ namespace osmium { | |||||||
|                         write_prefix(); |                         write_prefix(); | ||||||
|                         *m_out += "  <member type=\""; |                         *m_out += "  <member type=\""; | ||||||
|                         *m_out += item_type_to_name(member.type()); |                         *m_out += item_type_to_name(member.type()); | ||||||
|                         oprintf(*m_out, "\" ref=\"%" PRId64 "\" role=\"", member.ref()); |                         output_formatted("\" ref=\"%" PRId64 "\" role=\"", member.ref()); | ||||||
|                         xml_string(*m_out, member.role()); |                         append_xml_encoded_string(*m_out, member.role()); | ||||||
|                         *m_out += "\"/>\n"; |                         *m_out += "\"/>\n"; | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                     write_tags(relation.tags()); |                     write_tags(relation.tags(), prefix_spaces()); | ||||||
| 
 | 
 | ||||||
|                     write_prefix(); |                     write_prefix(); | ||||||
|                     *m_out += "</relation>\n"; |                     *m_out += "</relation>\n"; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void changeset(const osmium::Changeset& changeset) { |                 void changeset(const osmium::Changeset& changeset) { | ||||||
|                     write_prefix(); |                     *m_out += " <changeset"; | ||||||
|                     *m_out += "<changeset"; |  | ||||||
| 
 | 
 | ||||||
|                     oprintf(*m_out, " id=\"%" PRId32 "\"", changeset.id()); |                     output_formatted(" id=\"%" PRId32 "\"", changeset.id()); | ||||||
| 
 | 
 | ||||||
|                     if (changeset.created_at()) { |                     if (changeset.created_at()) { | ||||||
|                         *m_out += " created_at=\""; |                         *m_out += " created_at=\""; | ||||||
| @ -359,8 +340,6 @@ namespace osmium { | |||||||
|                         *m_out += "\""; |                         *m_out += "\""; | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                     oprintf(*m_out, " num_changes=\"%" PRId32 "\"", changeset.num_changes()); |  | ||||||
| 
 |  | ||||||
|                     if (changeset.closed_at()) { |                     if (changeset.closed_at()) { | ||||||
|                         *m_out += " closed_at=\""; |                         *m_out += " closed_at=\""; | ||||||
|                         *m_out += changeset.closed_at().to_iso(); |                         *m_out += changeset.closed_at().to_iso(); | ||||||
| @ -369,64 +348,67 @@ namespace osmium { | |||||||
|                         *m_out += " open=\"true\""; |                         *m_out += " open=\"true\""; | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                     if (changeset.bounds()) { |  | ||||||
|                         oprintf(*m_out, " min_lon=\"%.7f\"", changeset.bounds().bottom_left().lon_without_check()); |  | ||||||
|                         oprintf(*m_out, " min_lat=\"%.7f\"", changeset.bounds().bottom_left().lat_without_check()); |  | ||||||
|                         oprintf(*m_out, " max_lon=\"%.7f\"", changeset.bounds().top_right().lon_without_check()); |  | ||||||
|                         oprintf(*m_out, " max_lat=\"%.7f\"", changeset.bounds().top_right().lat_without_check()); |  | ||||||
|                     } |  | ||||||
| 
 |  | ||||||
|                     if (!changeset.user_is_anonymous()) { |                     if (!changeset.user_is_anonymous()) { | ||||||
|                         *m_out += " user=\""; |                         *m_out += " user=\""; | ||||||
|                         xml_string(*m_out, changeset.user()); |                         append_xml_encoded_string(*m_out, changeset.user()); | ||||||
|                         oprintf(*m_out, "\" uid=\"%d\"", changeset.uid()); |                         output_formatted("\" uid=\"%d\"", changeset.uid()); | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                     if (changeset.tags().empty()) { |                     if (changeset.bounds()) { | ||||||
|  |                         output_formatted(" min_lat=\"%.7f\"", changeset.bounds().bottom_left().lat_without_check()); | ||||||
|  |                         output_formatted(" min_lon=\"%.7f\"", changeset.bounds().bottom_left().lon_without_check()); | ||||||
|  |                         output_formatted(" max_lat=\"%.7f\"", changeset.bounds().top_right().lat_without_check()); | ||||||
|  |                         output_formatted(" max_lon=\"%.7f\"", changeset.bounds().top_right().lon_without_check()); | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     output_formatted(" num_changes=\"%" PRId32 "\"", changeset.num_changes()); | ||||||
|  |                     output_formatted(" comments_count=\"%" PRId32 "\"", changeset.num_comments()); | ||||||
|  | 
 | ||||||
|  |                     // If there are no tags and no comments, we can close the
 | ||||||
|  |                     // tag right here and are done.
 | ||||||
|  |                     if (changeset.tags().empty() && changeset.num_comments() == 0) { | ||||||
|                         *m_out += "/>\n"; |                         *m_out += "/>\n"; | ||||||
|                         return; |                         return; | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                     *m_out += ">\n"; |                     *m_out += ">\n"; | ||||||
| 
 | 
 | ||||||
|                     write_tags(changeset.tags()); |                     write_tags(changeset.tags(), 0); | ||||||
| 
 | 
 | ||||||
|                     write_prefix(); |                     if (changeset.num_comments() > 0) { | ||||||
|                     *m_out += "</changeset>\n"; |                         *m_out += "  <discussion>\n"; | ||||||
|  |                         write_discussion(changeset.discussion()); | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     *m_out += " </changeset>\n"; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|             }; // class XMLOutputBlock
 |             }; // class XMLOutputBlock
 | ||||||
| 
 | 
 | ||||||
|             class XMLOutputFormat : public osmium::io::detail::OutputFormat, public osmium::handler::Handler { |             class XMLOutputFormat : public osmium::io::detail::OutputFormat, public osmium::handler::Handler { | ||||||
| 
 | 
 | ||||||
|                 bool m_add_metadata; |                 xml_output_options m_options; | ||||||
|                 bool m_write_visible_flag; |  | ||||||
| 
 | 
 | ||||||
|             public: |             public: | ||||||
| 
 | 
 | ||||||
|                 XMLOutputFormat(const osmium::io::File& file, data_queue_type& output_queue) : |                 XMLOutputFormat(const osmium::io::File& file, future_string_queue_type& output_queue) : | ||||||
|                     OutputFormat(file, output_queue), |                     OutputFormat(output_queue), | ||||||
|                     m_add_metadata(file.get("add_metadata") != "false"), |                     m_options() { | ||||||
|                     m_write_visible_flag(file.has_multiple_object_versions() || m_file.is_true("force_visible_flag")) { |                     m_options.add_metadata     = file.is_not_false("add_metadata"); | ||||||
|  |                     m_options.use_change_ops   = file.is_true("xml_change_format"); | ||||||
|  |                     m_options.add_visible_flag = (file.has_multiple_object_versions() || file.is_true("force_visible_flag")) && !m_options.use_change_ops; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 XMLOutputFormat(const XMLOutputFormat&) = delete; |                 XMLOutputFormat(const XMLOutputFormat&) = delete; | ||||||
|                 XMLOutputFormat& operator=(const XMLOutputFormat&) = delete; |                 XMLOutputFormat& operator=(const XMLOutputFormat&) = delete; | ||||||
| 
 | 
 | ||||||
|                 ~XMLOutputFormat() override final { |                 ~XMLOutputFormat() noexcept final = default; | ||||||
|                 } |  | ||||||
| 
 | 
 | ||||||
|                 void write_buffer(osmium::memory::Buffer&& buffer) override final { |                 void write_header(const osmium::io::Header& header) final { | ||||||
|                     m_output_queue.push(osmium::thread::Pool::instance().submit(XMLOutputBlock{std::move(buffer), m_add_metadata, 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"; |                     std::string out = "<?xml version='1.0' encoding='UTF-8'?>\n"; | ||||||
| 
 | 
 | ||||||
|                     if (m_file.is_true("xml_change_format")) { |                     if (m_options.use_change_ops) { | ||||||
|                         out += "<osmChange version=\"0.6\" generator=\""; |                         out += "<osmChange version=\"0.6\" generator=\""; | ||||||
|                         xml_string(out, header.get("generator").c_str()); |  | ||||||
|                         out += "\">\n"; |  | ||||||
|                     } else { |                     } else { | ||||||
|                         out += "<osm version=\"0.6\""; |                         out += "<osm version=\"0.6\""; | ||||||
| 
 | 
 | ||||||
| @ -437,61 +419,54 @@ namespace osmium { | |||||||
|                             out += "\""; |                             out += "\""; | ||||||
|                         } |                         } | ||||||
|                         out += " generator=\""; |                         out += " generator=\""; | ||||||
|                         xml_string(out, header.get("generator").c_str()); |  | ||||||
|                         out += "\">\n"; |  | ||||||
|                     } |                     } | ||||||
|  |                     append_xml_encoded_string(out, header.get("generator").c_str()); | ||||||
|  |                     out += "\">\n"; | ||||||
| 
 | 
 | ||||||
|                     for (const auto& box : header.boxes()) { |                     for (const auto& box : header.boxes()) { | ||||||
|                         out += "  <bounds"; |                         out += "  <bounds"; | ||||||
|                         oprintf(out, " minlon=\"%.7f\"", box.bottom_left().lon()); |                         append_printf_formatted_string(out, " minlon=\"%.7f\"", box.bottom_left().lon()); | ||||||
|                         oprintf(out, " minlat=\"%.7f\"", box.bottom_left().lat()); |                         append_printf_formatted_string(out, " minlat=\"%.7f\"", box.bottom_left().lat()); | ||||||
|                         oprintf(out, " maxlon=\"%.7f\"", box.top_right().lon()); |                         append_printf_formatted_string(out, " maxlon=\"%.7f\"", box.top_right().lon()); | ||||||
|                         oprintf(out, " maxlat=\"%.7f\"/>\n", box.top_right().lat()); |                         append_printf_formatted_string(out, " maxlat=\"%.7f\"/>\n", box.top_right().lat()); | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                     std::promise<std::string> promise; |                     send_to_output_queue(std::move(out)); | ||||||
|                     m_output_queue.push(promise.get_future()); |  | ||||||
|                     promise.set_value(std::move(out)); |  | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 void close() override final { |                 void write_buffer(osmium::memory::Buffer&& buffer) final { | ||||||
|                     { |                     m_output_queue.push(osmium::thread::Pool::instance().submit(XMLOutputBlock{std::move(buffer), m_options})); | ||||||
|                         std::string out; |                 } | ||||||
|                         if (m_file.is_true("xml_change_format")) { |  | ||||||
|                             out += "</osmChange>\n"; |  | ||||||
|                         } else { |  | ||||||
|                             out += "</osm>\n"; |  | ||||||
|                         } |  | ||||||
| 
 | 
 | ||||||
|                         std::promise<std::string> promise; |                 void write_end() final { | ||||||
|                         m_output_queue.push(promise.get_future()); |                     std::string out; | ||||||
|                         promise.set_value(std::move(out)); | 
 | ||||||
|  |                     if (m_options.use_change_ops) { | ||||||
|  |                         out += "</osmChange>\n"; | ||||||
|  |                     } else { | ||||||
|  |                         out += "</osm>\n"; | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                     std::promise<std::string> promise; |                     send_to_output_queue(std::move(out)); | ||||||
|                     m_output_queue.push(promise.get_future()); |  | ||||||
|                     promise.set_value(std::string()); |  | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|             }; // class XMLOutputFormat
 |             }; // class XMLOutputFormat
 | ||||||
| 
 | 
 | ||||||
|             namespace { |             // we want the register_output_format() function to run, setting
 | ||||||
|  |             // the variable is only a side-effect, it will never be used
 | ||||||
|  |             const bool registered_xml_output = osmium::io::detail::OutputFormatFactory::instance().register_output_format(osmium::io::file_format::xml, | ||||||
|  |                 [](const osmium::io::File& file, future_string_queue_type& output_queue) { | ||||||
|  |                     return new osmium::io::detail::XMLOutputFormat(file, output_queue); | ||||||
|  |             }); | ||||||
| 
 | 
 | ||||||
| // we want the register_output_format() function to run, setting the variable
 |             // dummy function to silence the unused variable warning from above
 | ||||||
| // is only a side-effect, it will never be used
 |             inline bool get_registered_xml_output() noexcept { | ||||||
| #pragma GCC diagnostic push |                 return registered_xml_output; | ||||||
| #pragma GCC diagnostic ignored "-Wunused-variable" |             } | ||||||
|                 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); |  | ||||||
|                 }); |  | ||||||
| #pragma GCC diagnostic pop |  | ||||||
| 
 |  | ||||||
|             } // anonymous namespace
 |  | ||||||
| 
 | 
 | ||||||
|         } // namespace detail
 |         } // namespace detail
 | ||||||
| 
 | 
 | ||||||
|     } // namespace output
 |     } // namespace io
 | ||||||
| 
 | 
 | ||||||
| } // namespace osmium
 | } // namespace osmium
 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -39,6 +39,7 @@ DEALINGS IN THE SOFTWARE. | |||||||
| 
 | 
 | ||||||
| #include <zlib.h> | #include <zlib.h> | ||||||
| 
 | 
 | ||||||
|  | #include <osmium/io/error.hpp> | ||||||
| #include <osmium/util/cast.hpp> | #include <osmium/util/cast.hpp> | ||||||
| 
 | 
 | ||||||
| namespace osmium { | namespace osmium { | ||||||
| @ -69,7 +70,7 @@ namespace osmium { | |||||||
|                 ); |                 ); | ||||||
| 
 | 
 | ||||||
|                 if (result != Z_OK) { |                 if (result != Z_OK) { | ||||||
|                     throw std::runtime_error(std::string("failed to compress data: ") + zError(result)); |                     throw io_error(std::string("failed to compress data: ") + zError(result)); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 output.resize(output_size); |                 output.resize(output_size); | ||||||
| @ -99,7 +100,7 @@ namespace osmium { | |||||||
|                 ); |                 ); | ||||||
| 
 | 
 | ||||||
|                 if (result != Z_OK) { |                 if (result != Z_OK) { | ||||||
|                     throw std::runtime_error(std::string("failed to uncompress data: ") + zError(result)); |                     throw io_error(std::string("failed to uncompress data: ") + zError(result)); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 return std::make_pair(output.data(), output.size()); |                 return std::make_pair(output.data(), output.size()); | ||||||
|  | |||||||
| @ -43,16 +43,28 @@ namespace osmium { | |||||||
|      */ |      */ | ||||||
|     struct io_error : public std::runtime_error { |     struct io_error : public std::runtime_error { | ||||||
| 
 | 
 | ||||||
|         io_error(const std::string& what) : |         explicit io_error(const std::string& what) : | ||||||
|             std::runtime_error(what) { |             std::runtime_error(what) { | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         io_error(const char* what) : |         explicit io_error(const char* what) : | ||||||
|             std::runtime_error(what) { |             std::runtime_error(what) { | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|     }; // struct io_error
 |     }; // struct io_error
 | ||||||
| 
 | 
 | ||||||
|  |     struct unsupported_file_format_error : public io_error { | ||||||
|  | 
 | ||||||
|  |         explicit unsupported_file_format_error(const std::string& what) : | ||||||
|  |             io_error(what) { | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         explicit unsupported_file_format_error(const char* what) : | ||||||
|  |             io_error(what) { | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     }; // struct unsupported_file_format_error
 | ||||||
|  | 
 | ||||||
| } // namespace osmium
 | } // namespace osmium
 | ||||||
| 
 | 
 | ||||||
| #endif // OSMIUM_IO_ERROR_HPP
 | #endif // OSMIUM_IO_ERROR_HPP
 | ||||||
|  | |||||||
| @ -39,6 +39,7 @@ DEALINGS IN THE SOFTWARE. | |||||||
| #include <string> | #include <string> | ||||||
| #include <vector> | #include <vector> | ||||||
| 
 | 
 | ||||||
|  | #include <osmium/io/error.hpp> | ||||||
| #include <osmium/io/file_format.hpp> | #include <osmium/io/file_format.hpp> | ||||||
| #include <osmium/io/file_compression.hpp> | #include <osmium/io/file_compression.hpp> | ||||||
| #include <osmium/util/options.hpp> | #include <osmium/util/options.hpp> | ||||||
| @ -255,9 +256,9 @@ namespace osmium { | |||||||
|              * Check file format etc. for consistency and throw exception if |              * Check file format etc. for consistency and throw exception if | ||||||
|              * there is a problem. |              * there is a problem. | ||||||
|              * |              * | ||||||
|              * @throws std::runtime_error |              * @throws osmium::io_error | ||||||
|              */ |              */ | ||||||
|             void check() const { |             const File& check() const { | ||||||
|                 if (m_file_format == file_format::unknown) { |                 if (m_file_format == file_format::unknown) { | ||||||
|                     std::string msg = "Could not detect file format"; |                     std::string msg = "Could not detect file format"; | ||||||
|                     if (!m_format_string.empty())  { |                     if (!m_format_string.empty())  { | ||||||
| @ -273,8 +274,9 @@ namespace osmium { | |||||||
|                         msg += "'"; |                         msg += "'"; | ||||||
|                     } |                     } | ||||||
|                     msg += "."; |                     msg += "."; | ||||||
|                     throw std::runtime_error(msg); |                     throw io_error(msg); | ||||||
|                 } |                 } | ||||||
|  |                 return *this; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             file_format format() const noexcept { |             file_format format() const noexcept { | ||||||
|  | |||||||
| @ -49,7 +49,9 @@ DEALINGS IN THE SOFTWARE. | |||||||
| #include <zlib.h> | #include <zlib.h> | ||||||
| 
 | 
 | ||||||
| #include <osmium/io/compression.hpp> | #include <osmium/io/compression.hpp> | ||||||
|  | #include <osmium/io/error.hpp> | ||||||
| #include <osmium/io/file_compression.hpp> | #include <osmium/io/file_compression.hpp> | ||||||
|  | #include <osmium/io/writer_options.hpp> | ||||||
| #include <osmium/util/cast.hpp> | #include <osmium/util/cast.hpp> | ||||||
| #include <osmium/util/compatibility.hpp> | #include <osmium/util/compatibility.hpp> | ||||||
| 
 | 
 | ||||||
| @ -59,13 +61,13 @@ namespace osmium { | |||||||
|      * Exception thrown when there are problems compressing or |      * Exception thrown when there are problems compressing or | ||||||
|      * decompressing gzip files. |      * decompressing gzip files. | ||||||
|      */ |      */ | ||||||
|     struct gzip_error : public std::runtime_error { |     struct gzip_error : public io_error { | ||||||
| 
 | 
 | ||||||
|         int gzip_error_code; |         int gzip_error_code; | ||||||
|         int system_errno; |         int system_errno; | ||||||
| 
 | 
 | ||||||
|         gzip_error(const std::string& what, int error_code) : |         gzip_error(const std::string& what, int error_code) : | ||||||
|             std::runtime_error(what), |             io_error(what), | ||||||
|             gzip_error_code(error_code), |             gzip_error_code(error_code), | ||||||
|             system_errno(error_code == Z_ERRNO ? errno : 0) { |             system_errno(error_code == Z_ERRNO ? errno : 0) { | ||||||
|         } |         } | ||||||
| @ -93,23 +95,29 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|         class GzipCompressor : public Compressor { |         class GzipCompressor : public Compressor { | ||||||
| 
 | 
 | ||||||
|  |             int m_fd; | ||||||
|             gzFile m_gzfile; |             gzFile m_gzfile; | ||||||
| 
 | 
 | ||||||
|         public: |         public: | ||||||
| 
 | 
 | ||||||
|             explicit GzipCompressor(int fd) : |             explicit GzipCompressor(int fd, fsync sync) : | ||||||
|                 Compressor(), |                 Compressor(sync), | ||||||
|  |                 m_fd(dup(fd)), | ||||||
|                 m_gzfile(::gzdopen(fd, "w")) { |                 m_gzfile(::gzdopen(fd, "w")) { | ||||||
|                 if (!m_gzfile) { |                 if (!m_gzfile) { | ||||||
|                     detail::throw_gzip_error(m_gzfile, "write initialization failed"); |                     detail::throw_gzip_error(m_gzfile, "write initialization failed"); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             ~GzipCompressor() override final { |             ~GzipCompressor() noexcept final { | ||||||
|                 close(); |                 try { | ||||||
|  |                     close(); | ||||||
|  |                 } catch (...) { | ||||||
|  |                     // Ignore any exceptions because destructor must not throw.
 | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             void write(const std::string& data) override final { |             void write(const std::string& data) final { | ||||||
|                 if (!data.empty()) { |                 if (!data.empty()) { | ||||||
|                     int nwrite = ::gzwrite(m_gzfile, data.data(), static_cast_with_assert<unsigned int>(data.size())); |                     int nwrite = ::gzwrite(m_gzfile, data.data(), static_cast_with_assert<unsigned int>(data.size())); | ||||||
|                     if (nwrite == 0) { |                     if (nwrite == 0) { | ||||||
| @ -118,13 +126,17 @@ namespace osmium { | |||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             void close() override final { |             void close() final { | ||||||
|                 if (m_gzfile) { |                 if (m_gzfile) { | ||||||
|                     int result = ::gzclose(m_gzfile); |                     int result = ::gzclose(m_gzfile); | ||||||
|                     m_gzfile = nullptr; |                     m_gzfile = nullptr; | ||||||
|                     if (result != Z_OK) { |                     if (result != Z_OK) { | ||||||
|                         detail::throw_gzip_error(m_gzfile, "write close failed", result); |                         detail::throw_gzip_error(m_gzfile, "write close failed", result); | ||||||
|                     } |                     } | ||||||
|  |                     if (do_fsync()) { | ||||||
|  |                         osmium::io::detail::reliable_fsync(m_fd); | ||||||
|  |                     } | ||||||
|  |                     osmium::io::detail::reliable_close(m_fd); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
| @ -144,11 +156,15 @@ namespace osmium { | |||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             ~GzipDecompressor() override final { |             ~GzipDecompressor() noexcept final { | ||||||
|                 close(); |                 try { | ||||||
|  |                     close(); | ||||||
|  |                 } catch (...) { | ||||||
|  |                     // Ignore any exceptions because destructor must not throw.
 | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             std::string read() override final { |             std::string read() final { | ||||||
|                 std::string buffer(osmium::io::Decompressor::input_buffer_size, '\0'); |                 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())); |                 int nread = ::gzread(m_gzfile, const_cast<char*>(buffer.data()), static_cast_with_assert<unsigned int>(buffer.size())); | ||||||
|                 if (nread < 0) { |                 if (nread < 0) { | ||||||
| @ -158,7 +174,7 @@ namespace osmium { | |||||||
|                 return buffer; |                 return buffer; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             void close() override final { |             void close() final { | ||||||
|                 if (m_gzfile) { |                 if (m_gzfile) { | ||||||
|                     int result = ::gzclose(m_gzfile); |                     int result = ::gzclose(m_gzfile); | ||||||
|                     m_gzfile = nullptr; |                     m_gzfile = nullptr; | ||||||
| @ -194,11 +210,15 @@ namespace osmium { | |||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             ~GzipBufferDecompressor() override final { |             ~GzipBufferDecompressor() noexcept final { | ||||||
|                 inflateEnd(&m_zstream); |                 try { | ||||||
|  |                     close(); | ||||||
|  |                 } catch (...) { | ||||||
|  |                     // Ignore any exceptions because destructor must not throw.
 | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             std::string read() override final { |             std::string read() final { | ||||||
|                 std::string output; |                 std::string output; | ||||||
| 
 | 
 | ||||||
|                 if (m_buffer) { |                 if (m_buffer) { | ||||||
| @ -227,22 +247,28 @@ namespace osmium { | |||||||
|                 return output; |                 return output; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  |             void close() final { | ||||||
|  |                 inflateEnd(&m_zstream); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|         }; // class GzipBufferDecompressor
 |         }; // class GzipBufferDecompressor
 | ||||||
| 
 | 
 | ||||||
|         namespace { |         namespace detail { | ||||||
| 
 | 
 | ||||||
| // we want the register_compression() function to run, setting the variable
 |             // we want the register_compression() function to run, setting
 | ||||||
| // is only a side-effect, it will never be used
 |             // the variable is only a side-effect, it will never be used
 | ||||||
| #pragma GCC diagnostic push |  | ||||||
| #pragma GCC diagnostic ignored "-Wunused-variable" |  | ||||||
|             const bool registered_gzip_compression = osmium::io::CompressionFactory::instance().register_compression(osmium::io::file_compression::gzip, |             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, fsync sync) { return new osmium::io::GzipCompressor(fd, sync); }, | ||||||
|                 [](int fd) { return new osmium::io::GzipDecompressor(fd); }, |                 [](int fd) { return new osmium::io::GzipDecompressor(fd); }, | ||||||
|                 [](const char* buffer, size_t size) { return new osmium::io::GzipBufferDecompressor(buffer, size); } |                 [](const char* buffer, size_t size) { return new osmium::io::GzipBufferDecompressor(buffer, size); } | ||||||
|             ); |             ); | ||||||
| #pragma GCC diagnostic pop |  | ||||||
| 
 | 
 | ||||||
|         } // anonymous namespace
 |             // dummy function to silence the unused variable warning from above
 | ||||||
|  |             inline bool get_registered_gzip_compression() noexcept { | ||||||
|  |                 return registered_gzip_compression; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |         } // namespace detail
 | ||||||
| 
 | 
 | ||||||
|     } // namespace io
 |     } // namespace io
 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -52,7 +52,7 @@ namespace osmium { | |||||||
|          * source. It hides all the buffer handling and makes the contents of a |          * source. It hides all the buffer handling and makes the contents of a | ||||||
|          * source accessible as a normal STL input iterator. |          * source accessible as a normal STL input iterator. | ||||||
|          */ |          */ | ||||||
|         template <class TSource, class TItem = osmium::memory::Item> |         template <typename TSource, typename TItem = osmium::memory::Item> | ||||||
|         class InputIterator { |         class InputIterator { | ||||||
| 
 | 
 | ||||||
|             static_assert(std::is_base_of<osmium::memory::Item, TItem>::value, "TItem must derive from osmium::buffer::Item"); |             static_assert(std::is_base_of<osmium::memory::Item, TItem>::value, "TItem must derive from osmium::buffer::Item"); | ||||||
| @ -133,6 +133,44 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|         }; // class InputIterator
 |         }; // class InputIterator
 | ||||||
| 
 | 
 | ||||||
|  |         template <typename TSource, typename TItem = osmium::memory::Item> | ||||||
|  |         class InputIteratorRange { | ||||||
|  | 
 | ||||||
|  |             InputIterator<TSource, TItem> m_begin; | ||||||
|  |             InputIterator<TSource, TItem> m_end; | ||||||
|  | 
 | ||||||
|  |         public: | ||||||
|  | 
 | ||||||
|  |             InputIteratorRange(InputIterator<TSource, TItem>&& begin, | ||||||
|  |                                InputIterator<TSource, TItem>&& end) : | ||||||
|  |                 m_begin(std::move(begin)), | ||||||
|  |                 m_end(std::move(end)) { | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             InputIterator<TSource, TItem> begin() const noexcept { | ||||||
|  |                 return m_begin; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             InputIterator<TSource, TItem> end() const noexcept { | ||||||
|  |                 return m_end; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             const InputIterator<TSource, TItem> cbegin() const noexcept { | ||||||
|  |                 return m_begin; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             const InputIterator<TSource, TItem> cend() const noexcept { | ||||||
|  |                 return m_end; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |         }; // class InputIteratorRange
 | ||||||
|  | 
 | ||||||
|  |         template <typename TItem, typename TSource> | ||||||
|  |         InputIteratorRange<TSource, TItem> make_input_iterator_range(TSource& source) { | ||||||
|  |             using it_type = InputIterator<TSource, TItem>; | ||||||
|  |             return InputIteratorRange<TSource, TItem>(it_type{source}, it_type{}); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|     } // namespace io
 |     } // namespace io
 | ||||||
| 
 | 
 | ||||||
| } // namespace osmium
 | } // namespace osmium
 | ||||||
|  | |||||||
							
								
								
									
										45
									
								
								third_party/libosmium/include/osmium/io/o5m_input.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								third_party/libosmium/include/osmium/io/o5m_input.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,45 @@ | |||||||
|  | #ifndef OSMIUM_IO_O5M_INPUT_HPP | ||||||
|  | #define OSMIUM_IO_O5M_INPUT_HPP | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  | 
 | ||||||
|  | This file is part of Osmium (http://osmcode.org/libosmium).
 | ||||||
|  | 
 | ||||||
|  | Copyright 2013-2015 Jochen Topf <jochen@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. | ||||||
|  | 
 | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * @file | ||||||
|  |  * | ||||||
|  |  * Include this file if you want to read OSM o5m and o5c files. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #include <osmium/io/reader.hpp> // IWYU pragma: export
 | ||||||
|  | #include <osmium/io/detail/o5m_input_format.hpp> // IWYU pragma: export
 | ||||||
|  | 
 | ||||||
|  | #endif // OSMIUM_IO_O5M_INPUT_HPP
 | ||||||
| @ -40,6 +40,7 @@ DEALINGS IN THE SOFTWARE. | |||||||
| 
 | 
 | ||||||
| #include <osmium/memory/buffer.hpp> | #include <osmium/memory/buffer.hpp> | ||||||
| #include <osmium/osm/diff_object.hpp> | #include <osmium/osm/diff_object.hpp> | ||||||
|  | #include <osmium/util/compatibility.hpp> | ||||||
| 
 | 
 | ||||||
| namespace osmium { | namespace osmium { | ||||||
| 
 | 
 | ||||||
| @ -49,30 +50,26 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|     namespace io { |     namespace io { | ||||||
| 
 | 
 | ||||||
|         template <class TDest> |         template <typename TDest> | ||||||
|         class OutputIterator : public std::iterator<std::output_iterator_tag, osmium::memory::Item> { |         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; |             TDest* m_destination; | ||||||
| 
 | 
 | ||||||
|             std::shared_ptr<buffer_wrapper> m_buffer_wrapper; |  | ||||||
| 
 |  | ||||||
|         public: |         public: | ||||||
| 
 | 
 | ||||||
|             explicit OutputIterator(TDest& destination, const size_t buffer_size = default_buffer_size) : |             explicit OutputIterator(TDest& destination) : | ||||||
|                 m_destination(&destination), |                 m_destination(&destination) { | ||||||
|                 m_buffer_wrapper(std::make_shared<buffer_wrapper>(buffer_size)) { |             } | ||||||
|  | 
 | ||||||
|  |             /**
 | ||||||
|  |              * @deprecated | ||||||
|  |              * Use of buffer size argument on OutputIterator | ||||||
|  |              * constructor is deprecated. Call Writer::set_buffer_size() | ||||||
|  |              * instead if you want to change the default. | ||||||
|  |              */ | ||||||
|  |             OSMIUM_DEPRECATED OutputIterator(TDest& destination, const size_t buffer_size) : | ||||||
|  |                 m_destination(&destination) { | ||||||
|  |                 destination.set_buffer_size(buffer_size); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             OutputIterator(const OutputIterator&) = default; |             OutputIterator(const OutputIterator&) = default; | ||||||
| @ -83,19 +80,17 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|             ~OutputIterator() = default; |             ~OutputIterator() = default; | ||||||
| 
 | 
 | ||||||
|             void flush() { |             /**
 | ||||||
|                 osmium::memory::Buffer buffer(m_buffer_wrapper->buffer.capacity(), osmium::memory::Buffer::auto_grow::no); |              * @deprecated | ||||||
|                 std::swap(m_buffer_wrapper->buffer, buffer); |              * Calling OutputIterator<Writer>::flush() is usually not | ||||||
|                 (*m_destination)(std::move(buffer)); |              * needed any more. Call flush() on the Writer instead if needed. | ||||||
|  |              */ | ||||||
|  |             OSMIUM_DEPRECATED void flush() { | ||||||
|  |                 m_destination->flush(); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             OutputIterator& operator=(const osmium::memory::Item& item) { |             OutputIterator& operator=(const osmium::memory::Item& item) { | ||||||
|                 try { |                 (*m_destination)(item); | ||||||
|                     m_buffer_wrapper->buffer.push_back(item); |  | ||||||
|                 } catch (osmium::buffer_is_full&) { |  | ||||||
|                     flush(); |  | ||||||
|                     m_buffer_wrapper->buffer.push_back(item); |  | ||||||
|                 } |  | ||||||
|                 return *this; |                 return *this; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
| @ -117,6 +112,23 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|         }; // class OutputIterator
 |         }; // class OutputIterator
 | ||||||
| 
 | 
 | ||||||
|  |         template <typename TDest> | ||||||
|  |         OutputIterator<TDest> make_output_iterator(TDest& destination) { | ||||||
|  |             return OutputIterator<TDest>{destination}; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         /**
 | ||||||
|  |          * @deprecated | ||||||
|  |          * Use of buffer size argument on make_output_iterator is deprecated. | ||||||
|  |          * Call Writer::set_buffer_size() instead if you want to change the | ||||||
|  |          * default. | ||||||
|  |          */ | ||||||
|  |         template <typename TDest> | ||||||
|  |         OSMIUM_DEPRECATED OutputIterator<TDest> make_output_iterator(TDest& destination, const size_t buffer_size) { | ||||||
|  |             destination.set_buffer_size(buffer_size); | ||||||
|  |             return OutputIterator<TDest>{destination}; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|     } // namespace io
 |     } // namespace io
 | ||||||
| 
 | 
 | ||||||
| } // namespace osmium
 | } // namespace osmium
 | ||||||
|  | |||||||
| @ -33,20 +33,7 @@ DEALINGS IN THE SOFTWARE. | |||||||
| 
 | 
 | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| namespace osmium { | #pragma message("Including overwrite.hpp is deprecated, #include <osmium/io/writer_options.hpp> instead.") | ||||||
| 
 | #include <osmium/io/writer_options.hpp> | ||||||
|     namespace io { |  | ||||||
| 
 |  | ||||||
|         /**
 |  | ||||||
|          * Allow overwriting of existing file. |  | ||||||
|          */ |  | ||||||
|         enum class overwrite : bool { |  | ||||||
|             no    = false, |  | ||||||
|             allow = true |  | ||||||
|         }; |  | ||||||
| 
 |  | ||||||
|     } // namespace io
 |  | ||||||
| 
 |  | ||||||
| } // namespace osmium
 |  | ||||||
| 
 | 
 | ||||||
| #endif // OSMIUM_IO_OVERWRITE_HPP
 | #endif // OSMIUM_IO_OVERWRITE_HPP
 | ||||||
|  | |||||||
							
								
								
									
										162
									
								
								third_party/libosmium/include/osmium/io/reader.hpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										162
									
								
								third_party/libosmium/include/osmium/io/reader.hpp
									
									
									
									
										vendored
									
									
								
							| @ -33,10 +33,10 @@ DEALINGS IN THE SOFTWARE. | |||||||
| 
 | 
 | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| #include <atomic> |  | ||||||
| #include <cerrno> | #include <cerrno> | ||||||
| #include <cstdlib> | #include <cstdlib> | ||||||
| #include <fcntl.h> | #include <fcntl.h> | ||||||
|  | #include <future> | ||||||
| #include <memory> | #include <memory> | ||||||
| #include <string> | #include <string> | ||||||
| #include <system_error> | #include <system_error> | ||||||
| @ -55,12 +55,13 @@ DEALINGS IN THE SOFTWARE. | |||||||
| #include <osmium/io/detail/input_format.hpp> | #include <osmium/io/detail/input_format.hpp> | ||||||
| #include <osmium/io/detail/read_thread.hpp> | #include <osmium/io/detail/read_thread.hpp> | ||||||
| #include <osmium/io/detail/read_write.hpp> | #include <osmium/io/detail/read_write.hpp> | ||||||
|  | #include <osmium/io/detail/queue_util.hpp> | ||||||
|  | #include <osmium/io/error.hpp> | ||||||
| #include <osmium/io/file.hpp> | #include <osmium/io/file.hpp> | ||||||
| #include <osmium/io/header.hpp> | #include <osmium/io/header.hpp> | ||||||
| #include <osmium/memory/buffer.hpp> | #include <osmium/memory/buffer.hpp> | ||||||
| #include <osmium/osm/entity_bits.hpp> | #include <osmium/osm/entity_bits.hpp> | ||||||
| #include <osmium/thread/util.hpp> | #include <osmium/thread/util.hpp> | ||||||
| #include <osmium/thread/queue.hpp> |  | ||||||
| 
 | 
 | ||||||
| namespace osmium { | namespace osmium { | ||||||
| 
 | 
 | ||||||
| @ -74,17 +75,46 @@ namespace osmium { | |||||||
|          */ |          */ | ||||||
|         class Reader { |         class Reader { | ||||||
| 
 | 
 | ||||||
|  |             static constexpr size_t max_input_queue_size = 20; // XXX
 | ||||||
|  |             static constexpr size_t max_osmdata_queue_size = 20; // XXX
 | ||||||
|  | 
 | ||||||
|             osmium::io::File m_file; |             osmium::io::File m_file; | ||||||
|             osmium::osm_entity_bits::type m_read_which_entities; |             osmium::osm_entity_bits::type m_read_which_entities; | ||||||
|             std::atomic<bool> m_input_done; | 
 | ||||||
|  |             enum class status { | ||||||
|  |                 okay   = 0, // normal reading
 | ||||||
|  |                 error  = 1, // some error occurred while reading
 | ||||||
|  |                 closed = 2, // close() called successfully after eof
 | ||||||
|  |                 eof    = 3  // eof of file was reached without error
 | ||||||
|  |             } m_status; | ||||||
|  | 
 | ||||||
|             int m_childpid; |             int m_childpid; | ||||||
| 
 | 
 | ||||||
|             osmium::thread::Queue<std::string> m_input_queue; |             detail::future_string_queue_type m_input_queue; | ||||||
| 
 | 
 | ||||||
|             std::unique_ptr<osmium::io::Decompressor> m_decompressor; |             std::unique_ptr<osmium::io::Decompressor> m_decompressor; | ||||||
|             std::future<bool> m_read_future; |  | ||||||
| 
 | 
 | ||||||
|             std::unique_ptr<osmium::io::detail::InputFormat> m_input; |             osmium::io::detail::ReadThreadManager m_read_thread_manager; | ||||||
|  | 
 | ||||||
|  |             detail::future_buffer_queue_type m_osmdata_queue; | ||||||
|  |             detail::queue_wrapper<osmium::memory::Buffer> m_osmdata_queue_wrapper; | ||||||
|  | 
 | ||||||
|  |             std::future<osmium::io::Header> m_header_future; | ||||||
|  |             osmium::io::Header m_header; | ||||||
|  | 
 | ||||||
|  |             osmium::thread::thread_handler m_thread; | ||||||
|  | 
 | ||||||
|  |             // This function will run in a separate thread.
 | ||||||
|  |             static void parser_thread(const osmium::io::File& file, | ||||||
|  |                                       detail::future_string_queue_type& input_queue, | ||||||
|  |                                       detail::future_buffer_queue_type& osmdata_queue, | ||||||
|  |                                       std::promise<osmium::io::Header>&& header_promise, | ||||||
|  |                                       osmium::osm_entity_bits::type read_which_entities) { | ||||||
|  |                 std::promise<osmium::io::Header> promise = std::move(header_promise); | ||||||
|  |                 auto creator = detail::ParserFactory::instance().get_creator_function(file); | ||||||
|  |                 auto parser = creator(input_queue, osmdata_queue, promise, read_which_entities); | ||||||
|  |                 parser->parse(); | ||||||
|  |             } | ||||||
| 
 | 
 | ||||||
| #ifndef _WIN32 | #ifndef _WIN32 | ||||||
|             /**
 |             /**
 | ||||||
| @ -149,7 +179,7 @@ namespace osmium { | |||||||
| #ifndef _WIN32 | #ifndef _WIN32 | ||||||
|                     return execute("curl", filename, childpid); |                     return execute("curl", filename, childpid); | ||||||
| #else | #else | ||||||
|                     throw std::runtime_error("Reading OSM files from the network currently not supported on Windows."); |                     throw io_error("Reading OSM files from the network currently not supported on Windows."); | ||||||
| #endif | #endif | ||||||
|                 } else { |                 } else { | ||||||
|                     return osmium::io::detail::open_for_reading(filename); |                     return osmium::io::detail::open_for_reading(filename); | ||||||
| @ -168,16 +198,23 @@ namespace osmium { | |||||||
|              *                            parsed. |              *                            parsed. | ||||||
|              */ |              */ | ||||||
|             explicit Reader(const osmium::io::File& file, osmium::osm_entity_bits::type read_which_entities = osmium::osm_entity_bits::all) : |             explicit Reader(const osmium::io::File& file, osmium::osm_entity_bits::type read_which_entities = osmium::osm_entity_bits::all) : | ||||||
|                 m_file(file), |                 m_file(file.check()), | ||||||
|                 m_read_which_entities(read_which_entities), |                 m_read_which_entities(read_which_entities), | ||||||
|                 m_input_done(false), |                 m_status(status::okay), | ||||||
|                 m_childpid(0), |                 m_childpid(0), | ||||||
|                 m_input_queue(20, "raw_input"), // XXX
 |                 m_input_queue(max_input_queue_size, "raw_input"), | ||||||
|                 m_decompressor(m_file.buffer() ? |                 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(), 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))), |                     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_read_thread_manager(*m_decompressor, m_input_queue), | ||||||
|                 m_input(osmium::io::detail::InputFormatFactory::instance().create_input(m_file, m_read_which_entities, m_input_queue)) { |                 m_osmdata_queue(max_osmdata_queue_size, "parser_results"), | ||||||
|  |                 m_osmdata_queue_wrapper(m_osmdata_queue), | ||||||
|  |                 m_header_future(), | ||||||
|  |                 m_header(), | ||||||
|  |                 m_thread() { | ||||||
|  |                 std::promise<osmium::io::Header> header_promise; | ||||||
|  |                 m_header_future = header_promise.get_future(); | ||||||
|  |                 m_thread = osmium::thread::thread_handler{parser_thread, std::ref(m_file), std::ref(m_input_queue), std::ref(m_osmdata_queue), std::move(header_promise), read_which_entities}; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             explicit Reader(const std::string& filename, osmium::osm_entity_bits::type read_types = osmium::osm_entity_bits::all) : |             explicit Reader(const std::string& filename, osmium::osm_entity_bits::type read_types = osmium::osm_entity_bits::all) : | ||||||
| @ -191,27 +228,37 @@ namespace osmium { | |||||||
|             Reader(const Reader&) = delete; |             Reader(const Reader&) = delete; | ||||||
|             Reader& operator=(const Reader&) = delete; |             Reader& operator=(const Reader&) = delete; | ||||||
| 
 | 
 | ||||||
|             ~Reader() { |             Reader(Reader&&) = default; | ||||||
|  |             Reader& operator=(Reader&&) = default; | ||||||
|  | 
 | ||||||
|  |             ~Reader() noexcept { | ||||||
|                 try { |                 try { | ||||||
|                     close(); |                     close(); | ||||||
|                 } |                 } catch (...) { | ||||||
|                 catch (...) { |                     // Ignore any exceptions because destructor must not throw.
 | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             /**
 |             /**
 | ||||||
|              * Close down the Reader. A call to this is optional, because the |              * 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 |              * destructor of Reader will also call this. But if you don't call | ||||||
|              * this function first, the destructor might throw an exception |              * this function first, you might miss an exception, because the | ||||||
|              * which is not good. |              * destructor is not allowed to throw. | ||||||
|              * |              * | ||||||
|              * @throws Some form of std::runtime_error when there is a problem. |              * @throws Some form of osmium::io_error when there is a problem. | ||||||
|              */ |              */ | ||||||
|             void close() { |             void close() { | ||||||
|                 // Signal to input child process that it should wrap up.
 |                 m_status = status::closed; | ||||||
|                 m_input_done = true; |  | ||||||
| 
 | 
 | ||||||
|                 m_input->close(); |                 m_read_thread_manager.stop(); | ||||||
|  | 
 | ||||||
|  |                 m_osmdata_queue_wrapper.drain(); | ||||||
|  | 
 | ||||||
|  |                 try { | ||||||
|  |                     m_read_thread_manager.close(); | ||||||
|  |                 } catch (...) { | ||||||
|  |                     // Ignore any exceptions.
 | ||||||
|  |                 } | ||||||
| 
 | 
 | ||||||
| #ifndef _WIN32 | #ifndef _WIN32 | ||||||
|                 if (m_childpid) { |                 if (m_childpid) { | ||||||
| @ -226,15 +273,32 @@ namespace osmium { | |||||||
|                     m_childpid = 0; |                     m_childpid = 0; | ||||||
|                 } |                 } | ||||||
| #endif | #endif | ||||||
| 
 |  | ||||||
|                 osmium::thread::wait_until_done(m_read_future); |  | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             /**
 |             /**
 | ||||||
|              * Get the header data from the file. |              * Get the header data from the file. | ||||||
|  |              * | ||||||
|  |              * @returns Header. | ||||||
|  |              * @throws Some form of osmium::io_error if there is an error. | ||||||
|              */ |              */ | ||||||
|             osmium::io::Header header() const { |             osmium::io::Header header() { | ||||||
|                 return m_input->header(); |                 if (m_status == status::error) { | ||||||
|  |                     throw io_error("Can not get header from reader when in status 'error'"); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 try { | ||||||
|  |                     if (m_header_future.valid()) { | ||||||
|  |                         m_header = m_header_future.get(); | ||||||
|  |                         if (m_read_which_entities == osmium::osm_entity_bits::nothing) { | ||||||
|  |                             m_status = status::eof; | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } catch (...) { | ||||||
|  |                     close(); | ||||||
|  |                     m_status = status::error; | ||||||
|  |                     throw; | ||||||
|  |                 } | ||||||
|  |                 return m_header; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             /**
 |             /**
 | ||||||
| @ -245,32 +309,36 @@ namespace osmium { | |||||||
|              * constructed. |              * constructed. | ||||||
|              * |              * | ||||||
|              * @returns Buffer. |              * @returns Buffer. | ||||||
|              * @throws Some form of std::runtime_error if there is an error. |              * @throws Some form of osmium::io_error if there is an error. | ||||||
|              */ |              */ | ||||||
|             osmium::memory::Buffer read() { |             osmium::memory::Buffer read() { | ||||||
|                 // If an exception happened in the input thread, re-throw
 |                 osmium::memory::Buffer buffer; | ||||||
|                 // 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 (m_status != status::okay || | ||||||
|                     // If the caller didn't want anything but the header, it will
 |                     m_read_which_entities == osmium::osm_entity_bits::nothing) { | ||||||
|                     // always get an empty buffer here.
 |                     throw io_error("Can not read from reader when in status 'closed', 'eof', or 'error'"); | ||||||
|                     return osmium::memory::Buffer(); |  | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 // m_input->read() can return an invalid buffer to signal EOF,
 |                 try { | ||||||
|                 // or a valid buffer with or without data. A valid buffer
 |                     // m_input_format.read() can return an invalid buffer to signal EOF,
 | ||||||
|                 // without data is not an error, it just means we have to
 |                     // or a valid buffer with or without data. A valid buffer
 | ||||||
|                 // keep getting the next buffer until there is one with data.
 |                     // without data is not an error, it just means we have to
 | ||||||
|                 while (true) { |                     // keep getting the next buffer until there is one with data.
 | ||||||
|                     osmium::memory::Buffer buffer = m_input->read(); |                     while (true) { | ||||||
|                     if (!buffer) { |                         buffer = m_osmdata_queue_wrapper.pop(); | ||||||
|                         m_input_done = true; |                         if (detail::at_end_of_data(buffer)) { | ||||||
|                         return buffer; |                             m_status = status::eof; | ||||||
|                     } |                             m_read_thread_manager.close(); | ||||||
|                     if (buffer.committed() > 0) { |                             return buffer; | ||||||
|                         return buffer; |                         } | ||||||
|  |                         if (buffer.committed() > 0) { | ||||||
|  |                             return buffer; | ||||||
|  |                         } | ||||||
|                     } |                     } | ||||||
|  |                 } catch (...) { | ||||||
|  |                     close(); | ||||||
|  |                     m_status = status::error; | ||||||
|  |                     throw; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
| @ -279,7 +347,7 @@ namespace osmium { | |||||||
|              * data has been read. It is also set by calling close(). |              * data has been read. It is also set by calling close(). | ||||||
|              */ |              */ | ||||||
|             bool eof() const { |             bool eof() const { | ||||||
|                 return m_input_done; |                 return m_status == status::eof || m_status == status::closed; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|         }; // class Reader
 |         }; // class Reader
 | ||||||
| @ -292,7 +360,7 @@ namespace osmium { | |||||||
|          * unless you are working with small OSM files and/or have lots of |          * unless you are working with small OSM files and/or have lots of | ||||||
|          * RAM. |          * RAM. | ||||||
|          */ |          */ | ||||||
|         template <class... TArgs> |         template <typename... TArgs> | ||||||
|         osmium::memory::Buffer read_file(TArgs&&... args) { |         osmium::memory::Buffer read_file(TArgs&&... args) { | ||||||
|             osmium::memory::Buffer buffer(1024*1024, osmium::memory::Buffer::auto_grow::yes); |             osmium::memory::Buffer buffer(1024*1024, osmium::memory::Buffer::auto_grow::yes); | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										281
									
								
								third_party/libosmium/include/osmium/io/writer.hpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										281
									
								
								third_party/libosmium/include/osmium/io/writer.hpp
									
									
									
									
										vendored
									
									
								
							| @ -33,17 +33,23 @@ DEALINGS IN THE SOFTWARE. | |||||||
| 
 | 
 | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
|  | #include <cassert> | ||||||
|  | #include <future> | ||||||
| #include <memory> | #include <memory> | ||||||
|  | #include <stdexcept> | ||||||
| #include <string> | #include <string> | ||||||
|  | #include <thread> | ||||||
| #include <utility> | #include <utility> | ||||||
| 
 | 
 | ||||||
| #include <osmium/io/compression.hpp> | #include <osmium/io/compression.hpp> | ||||||
| #include <osmium/io/detail/output_format.hpp> | #include <osmium/io/detail/output_format.hpp> | ||||||
|  | #include <osmium/io/detail/queue_util.hpp> | ||||||
| #include <osmium/io/detail/read_write.hpp> | #include <osmium/io/detail/read_write.hpp> | ||||||
| #include <osmium/io/detail/write_thread.hpp> | #include <osmium/io/detail/write_thread.hpp> | ||||||
|  | #include <osmium/io/error.hpp> | ||||||
| #include <osmium/io/file.hpp> | #include <osmium/io/file.hpp> | ||||||
| #include <osmium/io/header.hpp> | #include <osmium/io/header.hpp> | ||||||
| #include <osmium/io/overwrite.hpp> | #include <osmium/io/writer_options.hpp> | ||||||
| #include <osmium/memory/buffer.hpp> | #include <osmium/memory/buffer.hpp> | ||||||
| #include <osmium/thread/util.hpp> | #include <osmium/thread/util.hpp> | ||||||
| 
 | 
 | ||||||
| @ -54,21 +60,112 @@ namespace osmium { | |||||||
|         /**
 |         /**
 | ||||||
|          * This is the user-facing interface for writing OSM files. Instantiate |          * 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 |          * 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 |          * and optionally the data for the header and then call operator() on | ||||||
|          * to write Buffers. Call close() to finish up. |          * it to write Buffers or Items. | ||||||
|  |          * | ||||||
|  |          * The writer uses multithreading internally to do the actual encoding | ||||||
|  |          * of the data into the intended format, possible compress the data and | ||||||
|  |          * then write it out. But this is intentionally hidden from the user | ||||||
|  |          * of this class who can use it without knowing those details. | ||||||
|  |          * | ||||||
|  |          * If you are done call the close() method to finish up. Only if you | ||||||
|  |          * don't get an exception from the close() method, you can be sure | ||||||
|  |          * the data is written correctly (modulo operating system buffering). | ||||||
|  |          * The destructor of this class will also do the right thing if you | ||||||
|  |          * forget to call close(), but because the destructor can't throw you | ||||||
|  |          * will not get informed about any problems. | ||||||
|  |          * | ||||||
|  |          * The writer is usually used to write complete blocks of data stored | ||||||
|  |          * in osmium::memory::Buffers. But you can also write single | ||||||
|  |          * osmium::memory::Items. In this case the Writer uses an internal | ||||||
|  |          * Buffer. | ||||||
|          */ |          */ | ||||||
|         class Writer { |         class Writer { | ||||||
| 
 | 
 | ||||||
|  |             static constexpr size_t default_buffer_size = 10 * 1024 * 1024; | ||||||
|  | 
 | ||||||
|             osmium::io::File m_file; |             osmium::io::File m_file; | ||||||
| 
 | 
 | ||||||
|             osmium::io::detail::data_queue_type m_output_queue; |             detail::future_string_queue_type m_output_queue; | ||||||
| 
 | 
 | ||||||
|             std::unique_ptr<osmium::io::detail::OutputFormat> m_output; |             std::unique_ptr<osmium::io::detail::OutputFormat> m_output; | ||||||
| 
 | 
 | ||||||
|             std::unique_ptr<osmium::io::Compressor> m_compressor; |             osmium::memory::Buffer m_buffer; | ||||||
|  | 
 | ||||||
|  |             size_t m_buffer_size; | ||||||
| 
 | 
 | ||||||
|             std::future<bool> m_write_future; |             std::future<bool> m_write_future; | ||||||
| 
 | 
 | ||||||
|  |             osmium::thread::thread_handler m_thread; | ||||||
|  | 
 | ||||||
|  |             enum class status { | ||||||
|  |                 okay   = 0, // normal writing
 | ||||||
|  |                 error  = 1, // some error occurred while writing
 | ||||||
|  |                 closed = 2  // close() called successfully
 | ||||||
|  |             } m_status; | ||||||
|  | 
 | ||||||
|  |             // This function will run in a separate thread.
 | ||||||
|  |             static void write_thread(detail::future_string_queue_type& output_queue, | ||||||
|  |                                      std::unique_ptr<osmium::io::Compressor>&& compressor, | ||||||
|  |                                      std::promise<bool>&& write_promise) { | ||||||
|  |                 detail::WriteThread write_thread{output_queue, | ||||||
|  |                                                  std::move(compressor), | ||||||
|  |                                                  std::move(write_promise)}; | ||||||
|  |                 write_thread(); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             void do_write(osmium::memory::Buffer&& buffer) { | ||||||
|  |                 if (buffer && buffer.committed() > 0) { | ||||||
|  |                     m_output->write_buffer(std::move(buffer)); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             void do_flush() { | ||||||
|  |                 osmium::thread::check_for_exception(m_write_future); | ||||||
|  |                 if (m_buffer && m_buffer.committed() > 0) { | ||||||
|  |                     osmium::memory::Buffer buffer{m_buffer_size, | ||||||
|  |                                                   osmium::memory::Buffer::auto_grow::no}; | ||||||
|  |                     using std::swap; | ||||||
|  |                     swap(m_buffer, buffer); | ||||||
|  | 
 | ||||||
|  |                     m_output->write_buffer(std::move(buffer)); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             template <typename TFunction, typename... TArgs> | ||||||
|  |             void ensure_cleanup(TFunction func, TArgs&&... args) { | ||||||
|  |                 if (m_status != status::okay) { | ||||||
|  |                     throw io_error("Can not write to writer when in status 'closed' or 'error'"); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 try { | ||||||
|  |                     func(std::forward<TArgs>(args)...); | ||||||
|  |                 } catch (...) { | ||||||
|  |                     m_status = status::error; | ||||||
|  |                     detail::add_to_queue(m_output_queue, std::current_exception()); | ||||||
|  |                     detail::add_end_of_data_to_queue(m_output_queue); | ||||||
|  |                     throw; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             struct options_type { | ||||||
|  |                 osmium::io::Header header; | ||||||
|  |                 overwrite allow_overwrite = overwrite::no; | ||||||
|  |                 fsync sync = fsync::no; | ||||||
|  |             }; | ||||||
|  | 
 | ||||||
|  |             static void set_option(options_type& options, const osmium::io::Header& header) { | ||||||
|  |                 options.header = header; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             static void set_option(options_type& options, overwrite value) { | ||||||
|  |                 options.allow_overwrite = value; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             static void set_option(options_type& options, fsync value) { | ||||||
|  |                 options.sync = value; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|         public: |         public: | ||||||
| 
 | 
 | ||||||
|             /**
 |             /**
 | ||||||
| @ -76,64 +173,166 @@ namespace osmium { | |||||||
|              * header to it. |              * header to it. | ||||||
|              * |              * | ||||||
|              * @param file File (contains name and format info) to open. |              * @param file File (contains name and format info) to open. | ||||||
|              * @param header Optional header data. If this is not given sensible |              * @param args All further arguments are optional and can appear | ||||||
|              *               defaults will be used. See the default constructor |              *             in any order: | ||||||
|              *               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. |              * * osmium::io::Header: Optional header data. If this is | ||||||
|  |              *       not given, a default constructed osmium::io::Header | ||||||
|  |              *       object will be used. | ||||||
|  |              * | ||||||
|  |              * * osmium::io::overwrite: Allow overwriting of existing file? | ||||||
|  |              *       Can be osmium::io::overwrite::allow or | ||||||
|  |              *       osmium::io::overwrite::no (default). | ||||||
|  |              * | ||||||
|  |              * * osmium::io::fsync: Should fsync be called on the file | ||||||
|  |              *       before closing it? Can be osmium::io::fsync::yes or | ||||||
|  |              *       osmium::io::fsync::no (default). | ||||||
|  |              * | ||||||
|  |              * @throws osmium::io_error If there was an error. | ||||||
|              * @throws std::system_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) : |             template <typename... TArgs> | ||||||
|                 m_file(file), |             explicit Writer(const osmium::io::File& file, TArgs&&... args) : | ||||||
|  |                 m_file(file.check()), | ||||||
|                 m_output_queue(20, "raw_output"), // XXX
 |                 m_output_queue(20, "raw_output"), // XXX
 | ||||||
|                 m_output(osmium::io::detail::OutputFormatFactory::instance().create_output(m_file, m_output_queue)), |                 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_buffer(), | ||||||
|                 m_write_future(std::async(std::launch::async, detail::WriteThread(m_output_queue, m_compressor.get()))) { |                 m_buffer_size(default_buffer_size), | ||||||
|                 assert(!m_file.buffer()); |                 m_write_future(), | ||||||
|                 m_output->write_header(header); |                 m_thread(), | ||||||
|  |                 m_status(status::okay) { | ||||||
|  |                 assert(!m_file.buffer()); // XXX can't handle pseudo-files
 | ||||||
|  | 
 | ||||||
|  |                 options_type options; | ||||||
|  |                 (void)std::initializer_list<int>{ | ||||||
|  |                     (set_option(options, args), 0)... | ||||||
|  |                 }; | ||||||
|  | 
 | ||||||
|  |                 std::unique_ptr<osmium::io::Compressor> compressor = | ||||||
|  |                     CompressionFactory::instance().create_compressor(file.compression(), | ||||||
|  |                                                                      osmium::io::detail::open_for_writing(m_file.filename(), options.allow_overwrite), | ||||||
|  |                                                                      options.sync); | ||||||
|  | 
 | ||||||
|  |                 std::promise<bool> write_promise; | ||||||
|  |                 m_write_future = write_promise.get_future(); | ||||||
|  |                 m_thread = osmium::thread::thread_handler{write_thread, std::ref(m_output_queue), std::move(compressor), std::move(write_promise)}; | ||||||
|  | 
 | ||||||
|  |                 ensure_cleanup([&](){ | ||||||
|  |                     m_output->write_header(options.header); | ||||||
|  |                 }); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             explicit Writer(const std::string& filename, const osmium::io::Header& header = osmium::io::Header(), overwrite allow_overwrite = overwrite::no) : |             template <typename... TArgs> | ||||||
|                 Writer(osmium::io::File(filename), header, allow_overwrite) { |             explicit Writer(const std::string& filename, TArgs&&... args) : | ||||||
|  |                 Writer(osmium::io::File(filename), std::forward<TArgs>(args)...) { | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             explicit Writer(const char* filename, const osmium::io::Header& header = osmium::io::Header(), overwrite allow_overwrite = overwrite::no) : |             template <typename... TArgs> | ||||||
|                 Writer(osmium::io::File(filename), header, allow_overwrite) { |             explicit Writer(const char* filename, TArgs&&... args) : | ||||||
|  |                 Writer(osmium::io::File(filename), std::forward<TArgs>(args)...) { | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             Writer(const Writer&) = delete; |             Writer(const Writer&) = delete; | ||||||
|             Writer& operator=(const Writer&) = delete; |             Writer& operator=(const Writer&) = delete; | ||||||
| 
 | 
 | ||||||
|             ~Writer() { |             Writer(Writer&&) = default; | ||||||
|                 close(); |             Writer& operator=(Writer&&) = default; | ||||||
|             } |  | ||||||
| 
 | 
 | ||||||
|             /**
 |             ~Writer() noexcept { | ||||||
|              * Write contents of a buffer to the output file. |                 try { | ||||||
|              * |                     close(); | ||||||
|              * @throws Some form of std::runtime_error when there is a problem. |                 } catch (...) { | ||||||
|              */ |                     // Ignore any exceptions because destructor must not throw.
 | ||||||
|             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 |              * Get the currently configured size of the internal buffer. | ||||||
|              * call this, the destructor of Writer will also do the same |              */ | ||||||
|              * thing. But because this call might thrown an exception, |             size_t buffer_size() const noexcept { | ||||||
|              * it is better to call close() explicitly. |                 return m_buffer_size; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             /**
 | ||||||
|  |              * Set the size of the internal buffer. This will only take effect | ||||||
|  |              * if you have not yet written anything or after the next flush(). | ||||||
|  |              */ | ||||||
|  |             void set_buffer_size(size_t size) noexcept { | ||||||
|  |                 m_buffer_size = size; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             /**
 | ||||||
|  |              * Flush the internal buffer if it contains any data. This is | ||||||
|  |              * usually not needed as the buffer gets flushed on close() | ||||||
|  |              * automatically. | ||||||
|              * |              * | ||||||
|              * @throws Some form of std::runtime_error when there is a problem. |              * @throws Some form of osmium::io_error when there is a problem. | ||||||
|  |              */ | ||||||
|  |             void flush() { | ||||||
|  |                 ensure_cleanup([&](){ | ||||||
|  |                     do_flush(); | ||||||
|  |                 }); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             /**
 | ||||||
|  |              * Write contents of a buffer to the output file. The buffer is | ||||||
|  |              * moved into this function and will be in an undefined moved-from | ||||||
|  |              * state afterwards. | ||||||
|  |              * | ||||||
|  |              * @param buffer Buffer that is being written out. | ||||||
|  |              * @throws Some form of osmium::io_error when there is a problem. | ||||||
|  |              */ | ||||||
|  |             void operator()(osmium::memory::Buffer&& buffer) { | ||||||
|  |                 ensure_cleanup([&](){ | ||||||
|  |                     do_flush(); | ||||||
|  |                     do_write(std::move(buffer)); | ||||||
|  |                 }); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             /**
 | ||||||
|  |              * Add item to the internal buffer for eventual writing to the | ||||||
|  |              * output file. | ||||||
|  |              * | ||||||
|  |              * @param item Item to write (usually an OSM object). | ||||||
|  |              * @throws Some form of osmium::io_error when there is a problem. | ||||||
|  |              */ | ||||||
|  |             void operator()(const osmium::memory::Item& item) { | ||||||
|  |                 ensure_cleanup([&](){ | ||||||
|  |                     if (!m_buffer) { | ||||||
|  |                         m_buffer = osmium::memory::Buffer{m_buffer_size, | ||||||
|  |                                                           osmium::memory::Buffer::auto_grow::no}; | ||||||
|  |                     } | ||||||
|  |                     try { | ||||||
|  |                         m_buffer.push_back(item); | ||||||
|  |                     } catch (osmium::buffer_is_full&) { | ||||||
|  |                         do_flush(); | ||||||
|  |                         m_buffer.push_back(item); | ||||||
|  |                     } | ||||||
|  |                 }); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             /**
 | ||||||
|  |              * Flushes internal buffer and closes output file. If you do not | ||||||
|  |              * call this, the destructor of Writer will also do the same | ||||||
|  |              * thing. But because this call might throw an exception, which | ||||||
|  |              * the destructor will ignore, it is better to call close() | ||||||
|  |              * explicitly. | ||||||
|  |              * | ||||||
|  |              * @throws Some form of osmium::io_error when there is a problem. | ||||||
|              */ |              */ | ||||||
|             void close() { |             void close() { | ||||||
|                 m_output->close(); |                 if (m_status == status::okay) { | ||||||
|                 osmium::thread::wait_until_done(m_write_future); |                     ensure_cleanup([&](){ | ||||||
|  |                         do_write(std::move(m_buffer)); | ||||||
|  |                         m_output->write_end(); | ||||||
|  |                         m_status = status::closed; | ||||||
|  |                         detail::add_end_of_data_to_queue(m_output_queue); | ||||||
|  |                     }); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 if (m_write_future.valid()) { | ||||||
|  |                     m_write_future.get(); | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|         }; // class Writer
 |         }; // class Writer
 | ||||||
|  | |||||||
							
								
								
									
										60
									
								
								third_party/libosmium/include/osmium/io/writer_options.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								third_party/libosmium/include/osmium/io/writer_options.hpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,60 @@ | |||||||
|  | #ifndef OSMIUM_IO_WRITER_OPTIONS_HPP | ||||||
|  | #define OSMIUM_IO_WRITER_OPTIONS_HPP | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  | 
 | ||||||
|  | This file is part of Osmium (http://osmcode.org/libosmium).
 | ||||||
|  | 
 | ||||||
|  | Copyright 2013-2015 Jochen Topf <jochen@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 | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         /**
 | ||||||
|  |          * Should writer do an fsync before closing the file? | ||||||
|  |          */ | ||||||
|  |         enum class fsync : bool { | ||||||
|  |             no  = false, | ||||||
|  |             yes = true | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |     } // namespace io
 | ||||||
|  | 
 | ||||||
|  | } // namespace osmium
 | ||||||
|  | 
 | ||||||
|  | #endif // OSMIUM_IO_WRITER_OPTIONS_HPP
 | ||||||
| @ -46,6 +46,7 @@ DEALINGS IN THE SOFTWARE. | |||||||
| #include <osmium/memory/item.hpp> | #include <osmium/memory/item.hpp> | ||||||
| #include <osmium/memory/item_iterator.hpp> | #include <osmium/memory/item_iterator.hpp> | ||||||
| #include <osmium/osm/entity.hpp> | #include <osmium/osm/entity.hpp> | ||||||
|  | #include <osmium/util/compatibility.hpp> | ||||||
| 
 | 
 | ||||||
| namespace osmium { | namespace osmium { | ||||||
| 
 | 
 | ||||||
| @ -89,12 +90,17 @@ namespace osmium { | |||||||
|          * |          * | ||||||
|          * By default, if a buffer gets full it will throw a buffer_is_full exception. |          * 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 |          * You can use the set_full_callback() method to set a callback functor | ||||||
|          * which will be called instead of throwing an exception. |          * which will be called instead of throwing an exception. The full | ||||||
|  |          * callback functionality is deprecated and will be removed in the | ||||||
|  |          * future. See the documentation for set_full_callback() for alternatives. | ||||||
|          */ |          */ | ||||||
|         class Buffer { |         class Buffer { | ||||||
| 
 | 
 | ||||||
|         public: |         public: | ||||||
| 
 | 
 | ||||||
|  |             // This is needed so we can call std::back_inserter() on a Buffer.
 | ||||||
|  |             using value_type = Item; | ||||||
|  | 
 | ||||||
|             enum class auto_grow : bool { |             enum class auto_grow : bool { | ||||||
|                 yes = true, |                 yes = true, | ||||||
|                 no  = false |                 no  = false | ||||||
| @ -112,12 +118,13 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|         public: |         public: | ||||||
| 
 | 
 | ||||||
|             typedef Item value_type; |  | ||||||
| 
 |  | ||||||
|             /**
 |             /**
 | ||||||
|              * The constructor without any parameters creates a non-initialized |              * The constructor without any parameters creates an invalid, | ||||||
|              * buffer, ie an empty hull of a buffer that has no actual memory |              * 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. |              * associated with it. It can be used to signify end-of-data. | ||||||
|  |              * | ||||||
|  |              * Most methods of the Buffer class will not work with an invalid | ||||||
|  |              * buffer. | ||||||
|              */ |              */ | ||||||
|             Buffer() noexcept : |             Buffer() noexcept : | ||||||
|                 m_memory(), |                 m_memory(), | ||||||
| @ -128,12 +135,14 @@ namespace osmium { | |||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             /**
 |             /**
 | ||||||
|              * Constructs an externally memory-managed buffer using the given |              * Constructs a valid externally memory-managed buffer using the | ||||||
|              * memory and size. |              * given memory and size. | ||||||
|              * |              * | ||||||
|              * @param data A pointer to some already initialized data. |              * @param data A pointer to some already initialized data. | ||||||
|              * @param size The size of the initialized data. |              * @param size The size of the initialized data. | ||||||
|              * @throws std::invalid_argument When the size isn't a multiple of the alignment. |              * | ||||||
|  |              * @throws std::invalid_argument if the size isn't a multiple of | ||||||
|  |              *         the alignment. | ||||||
|              */ |              */ | ||||||
|             explicit Buffer(unsigned char* data, size_t size) : |             explicit Buffer(unsigned char* data, size_t size) : | ||||||
|                 m_memory(), |                 m_memory(), | ||||||
| @ -147,13 +156,15 @@ namespace osmium { | |||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             /**
 |             /**
 | ||||||
|              * Constructs an externally memory-managed buffer with the given |              * Constructs a valid externally memory-managed buffer with the | ||||||
|              * capacity that already contains 'committed' bytes of data. |              * given capacity that already contains 'committed' bytes of data. | ||||||
|              * |              * | ||||||
|              * @param data A pointer to some (possibly initialized) data. |              * @param data A pointer to some (possibly initialized) data. | ||||||
|              * @param capacity The size of the memory for this buffer. |              * @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. |              * @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. |              * | ||||||
|  |              * @throws std::invalid_argument if the capacity or committed isn't | ||||||
|  |              *         a multiple of the alignment. | ||||||
|              */ |              */ | ||||||
|             explicit Buffer(unsigned char* data, size_t capacity, size_t committed) : |             explicit Buffer(unsigned char* data, size_t capacity, size_t committed) : | ||||||
|                 m_memory(), |                 m_memory(), | ||||||
| @ -170,10 +181,18 @@ namespace osmium { | |||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             /**
 |             /**
 | ||||||
|              * Create an internally memory-managed buffer with the given capacity. |              * Constructs a valid internally memory-managed buffer with the | ||||||
|              * different in that it internally gets dynamic memory of the |              * given capacity. | ||||||
|              * required size. The dynamic memory will be automatically |              * Will internally get dynamic memory of the required size. | ||||||
|              * freed when the Buffer is destroyed. |              * The dynamic memory will be automatically freed when the Buffer | ||||||
|  |              * is destroyed. | ||||||
|  |              * | ||||||
|  |              * @param capacity The (initial) size of the memory for this buffer. | ||||||
|  |              * @param auto_grow Should this buffer automatically grow when it | ||||||
|  |              *        becomes to small? | ||||||
|  |              * | ||||||
|  |              * @throws std::invalid_argument if the capacity isn't a multiple | ||||||
|  |              *         of the alignment. | ||||||
|              */ |              */ | ||||||
|             explicit Buffer(size_t capacity, auto_grow auto_grow = auto_grow::yes) : |             explicit Buffer(size_t capacity, auto_grow auto_grow = auto_grow::yes) : | ||||||
|                 m_memory(capacity), |                 m_memory(capacity), | ||||||
| @ -199,13 +218,17 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|             /**
 |             /**
 | ||||||
|              * Return a pointer to data inside the buffer. |              * Return a pointer to data inside the buffer. | ||||||
|  |              * | ||||||
|  |              * @pre The buffer must be valid. | ||||||
|              */ |              */ | ||||||
|             unsigned char* data() const noexcept { |             unsigned char* data() const noexcept { | ||||||
|  |                 assert(m_data); | ||||||
|                 return m_data; |                 return m_data; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             /**
 |             /**
 | ||||||
|              * Returns the capacity of the buffer, ie how many bytes it can contain. |              * Returns the capacity of the buffer, ie how many bytes it can | ||||||
|  |              * contain. Always returns 0 on invalid buffers. | ||||||
|              */ |              */ | ||||||
|             size_t capacity() const noexcept { |             size_t capacity() const noexcept { | ||||||
|                 return m_capacity; |                 return m_capacity; | ||||||
| @ -213,6 +236,7 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|             /**
 |             /**
 | ||||||
|              * Returns the number of bytes already filled in this buffer. |              * Returns the number of bytes already filled in this buffer. | ||||||
|  |              * Always returns 0 on invalid buffers. | ||||||
|              */ |              */ | ||||||
|             size_t committed() const noexcept { |             size_t committed() const noexcept { | ||||||
|                 return m_committed; |                 return m_committed; | ||||||
| @ -221,6 +245,7 @@ namespace osmium { | |||||||
|             /**
 |             /**
 | ||||||
|              * Returns the number of bytes currently filled in this buffer that |              * Returns the number of bytes currently filled in this buffer that | ||||||
|              * are not yet committed. |              * are not yet committed. | ||||||
|  |              * Always returns 0 on invalid buffers. | ||||||
|              */ |              */ | ||||||
|             size_t written() const noexcept { |             size_t written() const noexcept { | ||||||
|                 return m_written; |                 return m_written; | ||||||
| @ -229,28 +254,57 @@ namespace osmium { | |||||||
|             /**
 |             /**
 | ||||||
|              * This tests if the current state of the buffer is aligned |              * This tests if the current state of the buffer is aligned | ||||||
|              * properly. Can be used for asserts. |              * properly. Can be used for asserts. | ||||||
|  |              * | ||||||
|  |              * @pre The buffer must be valid. | ||||||
|              */ |              */ | ||||||
|             bool is_aligned() const noexcept { |             bool is_aligned() const noexcept { | ||||||
|  |                 assert(m_data); | ||||||
|                 return (m_written % align_bytes == 0) && (m_committed % align_bytes == 0); |                 return (m_written % align_bytes == 0) && (m_committed % align_bytes == 0); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             /**
 |             /**
 | ||||||
|              * Set functor to be called whenever the buffer is full |              * Set functor to be called whenever the buffer is full | ||||||
|              * instead of throwing buffer_is_full. |              * instead of throwing buffer_is_full. | ||||||
|  |              * | ||||||
|  |              * The behaviour is undefined if you call this on an invalid | ||||||
|  |              * buffer. | ||||||
|  |              * | ||||||
|  |              * @pre The buffer must be valid. | ||||||
|  |              * | ||||||
|  |              * @deprecated | ||||||
|  |              * Callback functionality will be removed in the future. Either | ||||||
|  |              * detect the buffer_is_full exception or use a buffer with | ||||||
|  |              * auto_grow::yes. If you want to avoid growing buffers, check | ||||||
|  |              * that the used size of the buffer (committed()) is small enough | ||||||
|  |              * compared to the capacity (for instance small than 90% of the | ||||||
|  |              * capacity) before adding anything to the Buffer. If the buffer | ||||||
|  |              * is initialized with auto_grow::yes, it will still grow in the | ||||||
|  |              * rare case that a very large object will be added taking more | ||||||
|  |              * than the difference between committed() and capacity(). | ||||||
|              */ |              */ | ||||||
|             void set_full_callback(std::function<void(Buffer&)> full) { |             OSMIUM_DEPRECATED void set_full_callback(std::function<void(Buffer&)> full) { | ||||||
|  |                 assert(m_data); | ||||||
|                 m_full = full; |                 m_full = full; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             /**
 |             /**
 | ||||||
|              * Grow capacity of this buffer to the given size. |              * Grow capacity of this buffer to the given size. | ||||||
|              * This works only with internally memory-managed buffers. |              * This works only with internally memory-managed buffers. | ||||||
|              * If the given size is not larger than the current capacity, nothing is done. |              * If the given size is not larger than the current capacity, | ||||||
|  |              * nothing is done. | ||||||
|              * Already written but not committed data is discarded. |              * Already written but not committed data is discarded. | ||||||
|              * |              * | ||||||
|  |              * @pre The buffer must be valid. | ||||||
|  |              * | ||||||
|              * @param size New capacity. |              * @param size New capacity. | ||||||
|  |              * | ||||||
|  |              * @throws std::logic_error if the buffer doesn't use internal | ||||||
|  |              *         memory management. | ||||||
|  |              * @throws std::invalid_argument if the size isn't a multiple | ||||||
|  |              *         of the alignment. | ||||||
|              */ |              */ | ||||||
|             void grow(size_t size) { |             void grow(size_t size) { | ||||||
|  |                 assert(m_data); | ||||||
|                 if (m_memory.empty()) { |                 if (m_memory.empty()) { | ||||||
|                     throw std::logic_error("Can't grow Buffer if it doesn't use internal memory management."); |                     throw std::logic_error("Can't grow Buffer if it doesn't use internal memory management."); | ||||||
|                 } |                 } | ||||||
| @ -267,9 +321,15 @@ namespace osmium { | |||||||
|             /**
 |             /**
 | ||||||
|              * Mark currently written bytes in the buffer as committed. |              * Mark currently written bytes in the buffer as committed. | ||||||
|              * |              * | ||||||
|              * @returns Last number of committed bytes before this commit. |              * @pre The buffer must be valid and aligned properly (as indicated | ||||||
|  |              *      by is_aligned(). | ||||||
|  |              * | ||||||
|  |              * @returns Number of committed bytes before this commit. Can be | ||||||
|  |              *          used as an offset into the buffer to get to the | ||||||
|  |              *          object being committed by this call. | ||||||
|              */ |              */ | ||||||
|             size_t commit() { |             size_t commit() { | ||||||
|  |                 assert(m_data); | ||||||
|                 assert(is_aligned()); |                 assert(is_aligned()); | ||||||
| 
 | 
 | ||||||
|                 const size_t offset = m_committed; |                 const size_t offset = m_committed; | ||||||
| @ -279,14 +339,19 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|             /**
 |             /**
 | ||||||
|              * Roll back changes in buffer to last committed state. |              * Roll back changes in buffer to last committed state. | ||||||
|  |              * | ||||||
|  |              * @pre The buffer must be valid. | ||||||
|              */ |              */ | ||||||
|             void rollback() { |             void rollback() { | ||||||
|  |                 assert(m_data); | ||||||
|                 m_written = m_committed; |                 m_written = m_committed; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             /**
 |             /**
 | ||||||
|              * Clear the buffer. |              * Clear the buffer. | ||||||
|              * |              * | ||||||
|  |              * No-op on an invalid buffer. | ||||||
|  |              * | ||||||
|              * @returns Number of bytes in the buffer before it was cleared. |              * @returns Number of bytes in the buffer before it was cleared. | ||||||
|              */ |              */ | ||||||
|             size_t clear() { |             size_t clear() { | ||||||
| @ -299,11 +364,16 @@ namespace osmium { | |||||||
|             /**
 |             /**
 | ||||||
|              * Get the data in the buffer at the given offset. |              * Get the data in the buffer at the given offset. | ||||||
|              * |              * | ||||||
|  |              * @pre The buffer must be valid. | ||||||
|  |              * | ||||||
|              * @tparam T Type we want to the data to be interpreted as. |              * @tparam T Type we want to the data to be interpreted as. | ||||||
|              * @returns Reference of given type pointing to the data in the buffer. |              * | ||||||
|  |              * @returns Reference of given type pointing to the data in the | ||||||
|  |              *          buffer. | ||||||
|              */ |              */ | ||||||
|             template <class T> |             template <typename T> | ||||||
|             T& get(const size_t offset) const { |             T& get(const size_t offset) const { | ||||||
|  |                 assert(m_data); | ||||||
|                 return *reinterpret_cast<T*>(&m_data[offset]); |                 return *reinterpret_cast<T*>(&m_data[offset]); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
| @ -320,23 +390,35 @@ namespace osmium { | |||||||
|              * |              * | ||||||
|              * * If you have set a callback with set_full_callback(), it is |              * * If you have set a callback with set_full_callback(), it is | ||||||
|              *   called. After the call returns, you must have either grown |              *   called. After the call returns, you must have either grown | ||||||
|              *   the buffer or cleared it by calling buffer.clear(). |              *   the buffer or cleared it by calling buffer.clear(). (Usage | ||||||
|  |              *   of the full callback is deprecated and this functionality | ||||||
|  |              *   will be removed in the future. See the documentation for | ||||||
|  |              *   set_full_callback() for alternatives. | ||||||
|              * * If no callback is defined and this buffer uses internal |              * * If no callback is defined and this buffer uses internal | ||||||
|              *   memory management, the buffers capacity is grown, so that |              *   memory management, the buffers capacity is grown, so that | ||||||
|              *   the new data will fit. |              *   the new data will fit. | ||||||
|              * * Else the buffer_is_full exception is thrown. |              * * Else the buffer_is_full exception is thrown. | ||||||
|              * |              * | ||||||
|  |              * @pre The buffer must be valid. | ||||||
|  |              * | ||||||
|              * @param size Number of bytes to reserve. |              * @param size Number of bytes to reserve. | ||||||
|  |              * | ||||||
|              * @returns Pointer to reserved space. Note that this pointer is |              * @returns Pointer to reserved space. Note that this pointer is | ||||||
|              *         only guaranteed to be valid until the next call to |              *          only guaranteed to be valid until the next call to | ||||||
|              *         reserve_space(). |              *          reserve_space(). | ||||||
|              * @throws osmium::buffer_is_full Might be thrown if the buffer is full. |              * | ||||||
|  |              * @throws osmium::buffer_is_full if the buffer is full there is | ||||||
|  |              *         no callback defined and the buffer isn't auto-growing. | ||||||
|              */ |              */ | ||||||
|             unsigned char* reserve_space(const size_t size) { |             unsigned char* reserve_space(const size_t size) { | ||||||
|  |                 assert(m_data); | ||||||
|  |                 // try to flush the buffer empty first.
 | ||||||
|  |                 if (m_written + size > m_capacity && m_full) { | ||||||
|  |                     m_full(*this); | ||||||
|  |                 } | ||||||
|  |                 // if there's still not enough space, then try growing the buffer.
 | ||||||
|                 if (m_written + size > m_capacity) { |                 if (m_written + size > m_capacity) { | ||||||
|                     if (m_full) { |                     if (!m_memory.empty() && (m_auto_grow == auto_grow::yes)) { | ||||||
|                         m_full(*this); |  | ||||||
|                     } else if (!m_memory.empty() && (m_auto_grow == auto_grow::yes)) { |  | ||||||
|                         // double buffer size until there is enough space
 |                         // double buffer size until there is enough space
 | ||||||
|                         size_t new_capacity = m_capacity * 2; |                         size_t new_capacity = m_capacity * 2; | ||||||
|                         while (m_written + size > new_capacity) { |                         while (m_written + size > new_capacity) { | ||||||
| @ -359,12 +441,17 @@ namespace osmium { | |||||||
|              * Note that you have to eventually call commit() to actually |              * Note that you have to eventually call commit() to actually | ||||||
|              * commit this data. |              * commit this data. | ||||||
|              * |              * | ||||||
|  |              * @pre The buffer must be valid. | ||||||
|  |              * | ||||||
|              * @tparam T Class of the item to be copied. |              * @tparam T Class of the item to be copied. | ||||||
|  |              * | ||||||
|              * @param item Reference to the item to be copied. |              * @param item Reference to the item to be copied. | ||||||
|  |              * | ||||||
|              * @returns Reference to newly copied data in the buffer. |              * @returns Reference to newly copied data in the buffer. | ||||||
|              */ |              */ | ||||||
|             template <class T> |             template <typename T> | ||||||
|             T& add_item(const T& item) { |             T& add_item(const T& item) { | ||||||
|  |                 assert(m_data); | ||||||
|                 unsigned char* target = reserve_space(item.padded_size()); |                 unsigned char* target = reserve_space(item.padded_size()); | ||||||
|                 std::copy_n(reinterpret_cast<const unsigned char*>(&item), item.padded_size(), target); |                 std::copy_n(reinterpret_cast<const unsigned char*>(&item), item.padded_size(), target); | ||||||
|                 return *reinterpret_cast<T*>(target); |                 return *reinterpret_cast<T*>(target); | ||||||
| @ -373,91 +460,176 @@ namespace osmium { | |||||||
|             /**
 |             /**
 | ||||||
|              * Add committed contents of the given buffer to this buffer. |              * Add committed contents of the given buffer to this buffer. | ||||||
|              * |              * | ||||||
|  |              * @pre The buffer must be valid. | ||||||
|  |              * | ||||||
|              * Note that you have to eventually call commit() to actually |              * Note that you have to eventually call commit() to actually | ||||||
|              * commit this data. |              * commit this data. | ||||||
|  |              * | ||||||
|  |              * @param buffer The source of the copy. Must be valid. | ||||||
|              */ |              */ | ||||||
|             void add_buffer(const Buffer& buffer) { |             void add_buffer(const Buffer& buffer) { | ||||||
|  |                 assert(m_data && buffer); | ||||||
|                 unsigned char* target = reserve_space(buffer.committed()); |                 unsigned char* target = reserve_space(buffer.committed()); | ||||||
|                 std::copy_n(reinterpret_cast<const unsigned char*>(buffer.data()), buffer.committed(), target); |                 std::copy_n(buffer.data(), buffer.committed(), target); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             /**
 |             /**
 | ||||||
|              * Add an item to the buffer. This function is provided so that |              * Add an item to the buffer. This function is provided so that | ||||||
|              * you can use std::back_inserter. |              * you can use std::back_inserter. | ||||||
|  |              * | ||||||
|  |              * @pre The buffer must be valid. | ||||||
|  |              * | ||||||
|  |              * @param item The item to be added. | ||||||
|              */ |              */ | ||||||
|             void push_back(const osmium::memory::Item& item) { |             void push_back(const osmium::memory::Item& item) { | ||||||
|  |                 assert(m_data); | ||||||
|                 add_item(item); |                 add_item(item); | ||||||
|                 commit(); |                 commit(); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             /**
 |             /**
 | ||||||
|              * These iterators can be used to iterate over all items in |              * An iterator that can be used to iterate over all items of | ||||||
|              * a buffer. |              * type T in a buffer. | ||||||
|              */ |              */ | ||||||
|             template <class T> |             template <typename T> | ||||||
|             using t_iterator = osmium::memory::ItemIterator<T>; |             using t_iterator = osmium::memory::ItemIterator<T>; | ||||||
| 
 | 
 | ||||||
|             template <class T> |             /**
 | ||||||
|  |              * A const iterator that can be used to iterate over all items of | ||||||
|  |              * type T in a buffer. | ||||||
|  |              */ | ||||||
|  |             template <typename T> | ||||||
|             using t_const_iterator = osmium::memory::ItemIterator<const T>; |             using t_const_iterator = osmium::memory::ItemIterator<const T>; | ||||||
| 
 | 
 | ||||||
|             typedef t_iterator<osmium::OSMEntity> iterator; |             /**
 | ||||||
|             typedef t_const_iterator<osmium::OSMEntity> const_iterator; |              * An iterator that can be used to iterate over all OSMEntity | ||||||
|  |              * objects in a buffer. | ||||||
|  |              */ | ||||||
|  |             using iterator = t_iterator<osmium::OSMEntity>; | ||||||
| 
 | 
 | ||||||
|             template <class T> |             /**
 | ||||||
|  |              * A const iterator that can be used to iterate over all OSMEntity | ||||||
|  |              * objects in a buffer. | ||||||
|  |              */ | ||||||
|  |             using const_iterator = t_const_iterator<osmium::OSMEntity>; | ||||||
|  | 
 | ||||||
|  |             /**
 | ||||||
|  |              * Get iterator for iterating over all items of type T in the | ||||||
|  |              * buffer. | ||||||
|  |              * | ||||||
|  |              * @pre The buffer must be valid. | ||||||
|  |              * | ||||||
|  |              * @returns Iterator to first item of type T in the buffer. | ||||||
|  |              */ | ||||||
|  |             template <typename T> | ||||||
|             t_iterator<T> begin() { |             t_iterator<T> begin() { | ||||||
|  |                 assert(m_data); | ||||||
|                 return t_iterator<T>(m_data, m_data + m_committed); |                 return t_iterator<T>(m_data, m_data + m_committed); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  |             /**
 | ||||||
|  |              * Get iterator for iterating over all objects of class OSMEntity | ||||||
|  |              * in the buffer. | ||||||
|  |              * | ||||||
|  |              * @pre The buffer must be valid. | ||||||
|  |              * | ||||||
|  |              * @returns Iterator to first OSMEntity in the buffer. | ||||||
|  |              */ | ||||||
|             iterator begin() { |             iterator begin() { | ||||||
|  |                 assert(m_data); | ||||||
|                 return iterator(m_data, m_data + m_committed); |                 return iterator(m_data, m_data + m_committed); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             template <class T> |             /**
 | ||||||
|  |              * Get iterator for iterating over all items of type T in the | ||||||
|  |              * buffer. | ||||||
|  |              * | ||||||
|  |              * @pre The buffer must be valid. | ||||||
|  |              * | ||||||
|  |              * @returns Iterator to first item of type T after given offset | ||||||
|  |              *          in the buffer. | ||||||
|  |              */ | ||||||
|  |             template <typename T> | ||||||
|             t_iterator<T> get_iterator(size_t offset) { |             t_iterator<T> get_iterator(size_t offset) { | ||||||
|  |                 assert(m_data); | ||||||
|                 return t_iterator<T>(m_data + offset, m_data + m_committed); |                 return t_iterator<T>(m_data + offset, m_data + m_committed); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  |             /**
 | ||||||
|  |              * Get iterator for iterating over all objects of class OSMEntity | ||||||
|  |              * in the buffer. | ||||||
|  |              * | ||||||
|  |              * @pre The buffer must be valid. | ||||||
|  |              * | ||||||
|  |              * @returns Iterator to first OSMEntity after given offset in the | ||||||
|  |              *          buffer. | ||||||
|  |              */ | ||||||
|             iterator get_iterator(size_t offset) { |             iterator get_iterator(size_t offset) { | ||||||
|  |                 assert(m_data); | ||||||
|                 return iterator(m_data + offset, m_data + m_committed); |                 return iterator(m_data + offset, m_data + m_committed); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             template <class T> |             /**
 | ||||||
|  |              * Get iterator for iterating over all items of type T in the | ||||||
|  |              * buffer. | ||||||
|  |              * | ||||||
|  |              * @pre The buffer must be valid. | ||||||
|  |              * | ||||||
|  |              * @returns End iterator. | ||||||
|  |              */ | ||||||
|  |             template <typename T> | ||||||
|             t_iterator<T> end() { |             t_iterator<T> end() { | ||||||
|  |                 assert(m_data); | ||||||
|                 return t_iterator<T>(m_data + m_committed, m_data + m_committed); |                 return t_iterator<T>(m_data + m_committed, m_data + m_committed); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  |             /**
 | ||||||
|  |              * Get iterator for iterating over all objects of class OSMEntity | ||||||
|  |              * in the buffer. | ||||||
|  |              * | ||||||
|  |              * @pre The buffer must be valid. | ||||||
|  |              * | ||||||
|  |              * @returns End iterator. | ||||||
|  |              */ | ||||||
|             iterator end() { |             iterator end() { | ||||||
|  |                 assert(m_data); | ||||||
|                 return iterator(m_data + m_committed, m_data + m_committed); |                 return iterator(m_data + m_committed, m_data + m_committed); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             template <class T> |             template <typename T> | ||||||
|             t_const_iterator<T> cbegin() const { |             t_const_iterator<T> cbegin() const { | ||||||
|  |                 assert(m_data); | ||||||
|                 return t_const_iterator<T>(m_data, m_data + m_committed); |                 return t_const_iterator<T>(m_data, m_data + m_committed); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             const_iterator cbegin() const { |             const_iterator cbegin() const { | ||||||
|  |                 assert(m_data); | ||||||
|                 return const_iterator(m_data, m_data + m_committed); |                 return const_iterator(m_data, m_data + m_committed); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             template <class T> |             template <typename T> | ||||||
|             t_const_iterator<T> get_iterator(size_t offset) const { |             t_const_iterator<T> get_iterator(size_t offset) const { | ||||||
|  |                 assert(m_data); | ||||||
|                 return t_const_iterator<T>(m_data + offset, m_data + m_committed); |                 return t_const_iterator<T>(m_data + offset, m_data + m_committed); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             const_iterator get_iterator(size_t offset) const { |             const_iterator get_iterator(size_t offset) const { | ||||||
|  |                 assert(m_data); | ||||||
|                 return const_iterator(m_data + offset, m_data + m_committed); |                 return const_iterator(m_data + offset, m_data + m_committed); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             template <class T> |             template <typename T> | ||||||
|             t_const_iterator<T> cend() const { |             t_const_iterator<T> cend() const { | ||||||
|  |                 assert(m_data); | ||||||
|                 return t_const_iterator<T>(m_data + m_committed, m_data + m_committed); |                 return t_const_iterator<T>(m_data + m_committed, m_data + m_committed); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             const_iterator cend() const { |             const_iterator cend() const { | ||||||
|  |                 assert(m_data); | ||||||
|                 return const_iterator(m_data + m_committed, m_data + m_committed); |                 return const_iterator(m_data + m_committed, m_data + m_committed); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             template <class T> |             template <typename T> | ||||||
|             t_const_iterator<T> begin() const { |             t_const_iterator<T> begin() const { | ||||||
|                 return cbegin<T>(); |                 return cbegin<T>(); | ||||||
|             } |             } | ||||||
| @ -466,7 +638,7 @@ namespace osmium { | |||||||
|                 return cbegin(); |                 return cbegin(); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             template <class T> |             template <typename T> | ||||||
|             t_const_iterator<T> end() const { |             t_const_iterator<T> end() const { | ||||||
|                 return cend<T>(); |                 return cend<T>(); | ||||||
|             } |             } | ||||||
| @ -476,9 +648,9 @@ namespace osmium { | |||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             /**
 |             /**
 | ||||||
|              * In a bool context any initialized buffer is true. |              * In a bool context any valid buffer is true. | ||||||
|              */ |              */ | ||||||
|             explicit operator bool() const { |             explicit operator bool() const noexcept { | ||||||
|                 return m_data != nullptr; |                 return m_data != nullptr; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
| @ -490,6 +662,8 @@ namespace osmium { | |||||||
|                 swap(lhs.m_capacity, rhs.m_capacity); |                 swap(lhs.m_capacity, rhs.m_capacity); | ||||||
|                 swap(lhs.m_written, rhs.m_written); |                 swap(lhs.m_written, rhs.m_written); | ||||||
|                 swap(lhs.m_committed, rhs.m_committed); |                 swap(lhs.m_committed, rhs.m_committed); | ||||||
|  |                 swap(lhs.m_auto_grow, rhs.m_auto_grow); | ||||||
|  |                 swap(lhs.m_full, rhs.m_full); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             /**
 |             /**
 | ||||||
| @ -497,17 +671,20 @@ namespace osmium { | |||||||
|              * non-removed items forward in the buffer overwriting removed |              * non-removed items forward in the buffer overwriting removed | ||||||
|              * items and then correcting the m_written and m_committed numbers. |              * items and then correcting the m_written and m_committed numbers. | ||||||
|              * |              * | ||||||
|              * Note that calling this function invalidates all iterators on this |              * Note that calling this function invalidates all iterators on | ||||||
|              * buffer and all offsets in this buffer. |              * this buffer and all offsets in this buffer. | ||||||
|              * |              * | ||||||
|              * For every non-removed item that moves its position, the function |              * For every non-removed item that moves its position, the function | ||||||
|              * 'moving_in_buffer' is called on the given callback object with |              * 'moving_in_buffer' is called on the given callback object with | ||||||
|              * the old and new offsets in the buffer where the object used to |              * 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 |              * be and is now, respectively. This call can be used to update any | ||||||
|              * indexes. |              * indexes. | ||||||
|  |              * | ||||||
|  |              * @pre The buffer must be valid. | ||||||
|              */ |              */ | ||||||
|             template <class TCallbackClass> |             template <typename TCallbackClass> | ||||||
|             void purge_removed(TCallbackClass* callback) { |             void purge_removed(TCallbackClass* callback) { | ||||||
|  |                 assert(m_data); | ||||||
|                 if (begin() == end()) { |                 if (begin() == end()) { | ||||||
|                     return; |                     return; | ||||||
|                 } |                 } | ||||||
| @ -537,7 +714,17 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|         }; // class Buffer
 |         }; // class Buffer
 | ||||||
| 
 | 
 | ||||||
|  |         /**
 | ||||||
|  |          * Compare two buffers for equality. | ||||||
|  |          * | ||||||
|  |          * Buffers are equal if they are both invalid or if they are both | ||||||
|  |          * valid and have the same data pointer, capacity and committed | ||||||
|  |          * data. | ||||||
|  |          */ | ||||||
|         inline bool operator==(const Buffer& lhs, const Buffer& rhs) noexcept { |         inline bool operator==(const Buffer& lhs, const Buffer& rhs) noexcept { | ||||||
|  |             if (!lhs || !rhs) { | ||||||
|  |                 return !lhs && !rhs; | ||||||
|  |             } | ||||||
|             return lhs.data() == rhs.data() && lhs.capacity() == rhs.capacity() && lhs.committed() == rhs.committed(); |             return lhs.data() == rhs.data() && lhs.capacity() == rhs.capacity() && lhs.committed() == rhs.committed(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -43,7 +43,7 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|     namespace memory { |     namespace memory { | ||||||
| 
 | 
 | ||||||
|         template <class TMember> |         template <typename TMember> | ||||||
|         class CollectionIterator : public std::iterator<std::forward_iterator_tag, TMember> { |         class CollectionIterator : public std::iterator<std::forward_iterator_tag, TMember> { | ||||||
| 
 | 
 | ||||||
|             // This data_type is either 'unsigned char*' or 'const unsigned char*' depending
 |             // This data_type is either 'unsigned char*' or 'const unsigned char*' depending
 | ||||||
| @ -59,7 +59,7 @@ namespace osmium { | |||||||
|                 m_data(nullptr) { |                 m_data(nullptr) { | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             CollectionIterator(data_type data) noexcept : |             explicit CollectionIterator(data_type data) noexcept : | ||||||
|                 m_data(data) { |                 m_data(data) { | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
| @ -101,7 +101,7 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|         }; // class CollectionIterator
 |         }; // class CollectionIterator
 | ||||||
| 
 | 
 | ||||||
|         template <class TMember, osmium::item_type TCollectionItemType> |         template <typename TMember, osmium::item_type TCollectionItemType> | ||||||
|         class Collection : public Item { |         class Collection : public Item { | ||||||
| 
 | 
 | ||||||
|         public: |         public: | ||||||
|  | |||||||
| @ -43,7 +43,7 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|     namespace builder { |     namespace builder { | ||||||
|         class Builder; |         class Builder; | ||||||
|     } |     } // namespace builder
 | ||||||
| 
 | 
 | ||||||
|     namespace memory { |     namespace memory { | ||||||
| 
 | 
 | ||||||
| @ -102,10 +102,10 @@ namespace osmium { | |||||||
|             uint16_t m_removed : 1; |             uint16_t m_removed : 1; | ||||||
|             uint16_t m_padding : 15; |             uint16_t m_padding : 15; | ||||||
| 
 | 
 | ||||||
|             template <class TMember> |             template <typename TMember> | ||||||
|             friend class CollectionIterator; |             friend class CollectionIterator; | ||||||
| 
 | 
 | ||||||
|             template <class TMember> |             template <typename TMember> | ||||||
|             friend class ItemIterator; |             friend class ItemIterator; | ||||||
| 
 | 
 | ||||||
|             friend class osmium::builder::Builder; |             friend class osmium::builder::Builder; | ||||||
|  | |||||||
| @ -38,29 +38,17 @@ DEALINGS IN THE SOFTWARE. | |||||||
| #include <iosfwd> | #include <iosfwd> | ||||||
| #include <type_traits> | #include <type_traits> | ||||||
| 
 | 
 | ||||||
|  | #include <osmium/fwd.hpp> | ||||||
| #include <osmium/memory/item.hpp> | #include <osmium/memory/item.hpp> | ||||||
| #include <osmium/osm/item_type.hpp> | #include <osmium/osm/item_type.hpp> | ||||||
| 
 | 
 | ||||||
| namespace osmium { | 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 memory { | ||||||
| 
 | 
 | ||||||
|         namespace detail { |         namespace detail { | ||||||
| 
 | 
 | ||||||
|             template <class T> |             template <typename T> | ||||||
|             inline bool type_is_compatible(osmium::item_type) noexcept { |             inline bool type_is_compatible(osmium::item_type) noexcept { | ||||||
|                 return true; |                 return true; | ||||||
|             } |             } | ||||||
| @ -127,7 +115,7 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|         } // namespace detail
 |         } // namespace detail
 | ||||||
| 
 | 
 | ||||||
|         template <class TMember> |         template <typename TMember> | ||||||
|         class ItemIterator : public std::iterator<std::forward_iterator_tag, 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"); |             static_assert(std::is_base_of<osmium::memory::Item, TMember>::value, "TMember must derive from osmium::memory::Item"); | ||||||
| @ -160,7 +148,7 @@ namespace osmium { | |||||||
|                 advance_to_next_item_of_right_type(); |                 advance_to_next_item_of_right_type(); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             template <class T> |             template <typename T> | ||||||
|             ItemIterator<T> cast() const { |             ItemIterator<T> cast() const { | ||||||
|                 return ItemIterator<T>(m_data, m_end); |                 return ItemIterator<T>(m_data, m_end); | ||||||
|             } |             } | ||||||
| @ -217,7 +205,7 @@ namespace osmium { | |||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             explicit operator bool() const { |             explicit operator bool() const { | ||||||
|                 return m_data != nullptr; |                 return (m_data != nullptr) && (m_data != m_end); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             template <typename TChar, typename TTraits> |             template <typename TChar, typename TTraits> | ||||||
|  | |||||||
| @ -84,7 +84,7 @@ namespace osmium { | |||||||
|         /**
 |         /**
 | ||||||
|          * Sort objects according to the given order functor. |          * Sort objects according to the given order functor. | ||||||
|          */ |          */ | ||||||
|         template <class TCompare> |         template <typename TCompare> | ||||||
|         void sort(TCompare&& compare) { |         void sort(TCompare&& compare) { | ||||||
|             std::sort(m_objects.begin(), m_objects.end(), std::forward<TCompare>(compare)); |             std::sort(m_objects.begin(), m_objects.end(), std::forward<TCompare>(compare)); | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -48,7 +48,7 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|     namespace builder { |     namespace builder { | ||||||
|         template <class T> class ObjectBuilder; |         template <class T> class ObjectBuilder; | ||||||
|     } |     } // namespace builder
 | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|      * An outer ring of an Area. |      * An outer ring of an Area. | ||||||
| @ -167,6 +167,7 @@ namespace osmium { | |||||||
|                     case osmium::item_type::way_node_list: |                     case osmium::item_type::way_node_list: | ||||||
|                     case osmium::item_type::relation_member_list: |                     case osmium::item_type::relation_member_list: | ||||||
|                     case osmium::item_type::relation_member_list_with_full_members: |                     case osmium::item_type::relation_member_list_with_full_members: | ||||||
|  |                     case osmium::item_type::changeset_discussion: | ||||||
|                         assert(false && "Children of Area can only be outer/inner_ring and tag_list."); |                         assert(false && "Children of Area can only be outer/inner_ring and tag_list."); | ||||||
|                         break; |                         break; | ||||||
|                 } |                 } | ||||||
|  | |||||||
| @ -154,14 +154,14 @@ namespace osmium { | |||||||
|          * Box is valid, ie. defined and inside usual bounds |          * Box is valid, ie. defined and inside usual bounds | ||||||
|          * (-180<=lon<=180, -90<=lat<=90). |          * (-180<=lon<=180, -90<=lat<=90). | ||||||
|          */ |          */ | ||||||
|         OSMIUM_CONSTEXPR bool valid() const noexcept { |         constexpr bool valid() const noexcept { | ||||||
|             return bottom_left().valid() && top_right().valid(); |             return bottom_left().valid() && top_right().valid(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         /**
 |         /**
 | ||||||
|          * Access bottom-left location. |          * Access bottom-left location. | ||||||
|          */ |          */ | ||||||
|         OSMIUM_CONSTEXPR Location bottom_left() const noexcept { |         constexpr Location bottom_left() const noexcept { | ||||||
|             return m_bottom_left; |             return m_bottom_left; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| @ -175,7 +175,7 @@ namespace osmium { | |||||||
|         /**
 |         /**
 | ||||||
|          * Access top-right location. |          * Access top-right location. | ||||||
|          */ |          */ | ||||||
|         OSMIUM_CONSTEXPR Location top_right() const noexcept { |         constexpr Location top_right() const noexcept { | ||||||
|             return m_top_right; |             return m_top_right; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| @ -216,7 +216,7 @@ namespace osmium { | |||||||
|      * Boxes are equal if both locations are equal. Undefined boxes will |      * Boxes are equal if both locations are equal. Undefined boxes will | ||||||
|      * compare equal. |      * compare equal. | ||||||
|      */ |      */ | ||||||
|     inline OSMIUM_CONSTEXPR bool operator==(const Box& lhs, const Box& rhs) noexcept { |     inline constexpr bool operator==(const Box& lhs, const Box& rhs) noexcept { | ||||||
|         return lhs.bottom_left() == rhs.bottom_left() && |         return lhs.bottom_left() == rhs.bottom_left() && | ||||||
|                lhs.top_right() == rhs.top_right(); |                lhs.top_right() == rhs.top_right(); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -48,8 +48,102 @@ DEALINGS IN THE SOFTWARE. | |||||||
| namespace osmium { | namespace osmium { | ||||||
| 
 | 
 | ||||||
|     namespace builder { |     namespace builder { | ||||||
|         template <class T> class ObjectBuilder; |         class ChangesetDiscussionBuilder; | ||||||
|     } |         template <typename T> class ObjectBuilder; | ||||||
|  |     } // namespace builder
 | ||||||
|  | 
 | ||||||
|  |     class Changeset; | ||||||
|  | 
 | ||||||
|  |     class ChangesetComment : public osmium::memory::detail::ItemHelper { | ||||||
|  | 
 | ||||||
|  |         friend class osmium::builder::ChangesetDiscussionBuilder; | ||||||
|  | 
 | ||||||
|  |         osmium::Timestamp m_date; | ||||||
|  |         osmium::user_id_type m_uid {0}; | ||||||
|  |         string_size_type m_user_size; | ||||||
|  |         string_size_type m_text_size; | ||||||
|  | 
 | ||||||
|  |         ChangesetComment(const ChangesetComment&) = delete; | ||||||
|  |         ChangesetComment(ChangesetComment&&) = delete; | ||||||
|  | 
 | ||||||
|  |         ChangesetComment& operator=(const ChangesetComment&) = delete; | ||||||
|  |         ChangesetComment& operator=(ChangesetComment&&) = delete; | ||||||
|  | 
 | ||||||
|  |         unsigned char* endpos() { | ||||||
|  |             return data() + osmium::memory::padded_length(sizeof(ChangesetComment) + m_user_size + m_text_size); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         const unsigned char* endpos() const { | ||||||
|  |             return data() + osmium::memory::padded_length(sizeof(ChangesetComment) + m_user_size + m_text_size); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         template <typename TMember> | ||||||
|  |         friend class osmium::memory::CollectionIterator; | ||||||
|  | 
 | ||||||
|  |         unsigned char* next() { | ||||||
|  |             return endpos(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         unsigned const char* next() const { | ||||||
|  |             return endpos(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         void set_user_size(string_size_type size) noexcept { | ||||||
|  |             m_user_size = size; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         void set_text_size(string_size_type size) noexcept { | ||||||
|  |             m_text_size = size; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     public: | ||||||
|  | 
 | ||||||
|  |         static constexpr item_type collection_type = item_type::changeset_discussion; | ||||||
|  | 
 | ||||||
|  |         ChangesetComment(osmium::Timestamp date, osmium::user_id_type uid) noexcept : | ||||||
|  |             m_date(date), | ||||||
|  |             m_uid(uid), | ||||||
|  |             m_user_size(0), | ||||||
|  |             m_text_size(0) { | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         osmium::Timestamp date() const noexcept { | ||||||
|  |             return m_date; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         osmium::user_id_type uid() const noexcept { | ||||||
|  |             return m_uid; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         const char* user() const noexcept { | ||||||
|  |             return reinterpret_cast<const char*>(data() + sizeof(ChangesetComment)); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         const char* text() const noexcept { | ||||||
|  |             return reinterpret_cast<const char*>(data() + sizeof(ChangesetComment) + m_user_size); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     }; // class ChangesetComment
 | ||||||
|  | 
 | ||||||
|  |     class ChangesetDiscussion : public osmium::memory::Collection<ChangesetComment, osmium::item_type::changeset_discussion> { | ||||||
|  | 
 | ||||||
|  |         friend class osmium::builder::ObjectBuilder<osmium::Changeset>; | ||||||
|  | 
 | ||||||
|  |     public: | ||||||
|  | 
 | ||||||
|  |         typedef size_t size_type; | ||||||
|  | 
 | ||||||
|  |         ChangesetDiscussion() : | ||||||
|  |             osmium::memory::Collection<ChangesetComment, osmium::item_type::changeset_discussion>() { | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         size_type size() const noexcept { | ||||||
|  |             return static_cast<size_type>(std::distance(begin(), end())); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     }; // class ChangesetDiscussion
 | ||||||
|  | 
 | ||||||
|  |     static_assert(sizeof(ChangesetDiscussion) % osmium::memory::align_bytes == 0, "Class osmium::ChangesetDiscussion has wrong size to be aligned properly!"); | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|      * \brief An OSM Changeset, a group of changes made by a single user over |      * \brief An OSM Changeset, a group of changes made by a single user over | ||||||
| @ -62,13 +156,16 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|         friend class osmium::builder::ObjectBuilder<osmium::Changeset>; |         friend class osmium::builder::ObjectBuilder<osmium::Changeset>; | ||||||
| 
 | 
 | ||||||
|  |         osmium::Box       m_bounds; | ||||||
|         osmium::Timestamp m_created_at; |         osmium::Timestamp m_created_at; | ||||||
|         osmium::Timestamp m_closed_at; |         osmium::Timestamp m_closed_at; | ||||||
|         osmium::Box       m_bounds; |  | ||||||
|         changeset_id_type m_id {0}; |         changeset_id_type m_id {0}; | ||||||
|         num_changes_type  m_num_changes {0}; |         num_changes_type  m_num_changes {0}; | ||||||
|  |         num_comments_type m_num_comments {0}; | ||||||
|         user_id_type      m_uid {0}; |         user_id_type      m_uid {0}; | ||||||
|         string_size_type  m_user_size; |         string_size_type  m_user_size; | ||||||
|  |         int16_t           m_padding1 {0}; | ||||||
|  |         int32_t           m_padding2 {0}; | ||||||
| 
 | 
 | ||||||
|         Changeset() : |         Changeset() : | ||||||
|             OSMEntity(sizeof(Changeset), osmium::item_type::changeset) { |             OSMEntity(sizeof(Changeset), osmium::item_type::changeset) { | ||||||
| @ -188,7 +285,7 @@ namespace osmium { | |||||||
|          * @param timestamp Timestamp |          * @param timestamp Timestamp | ||||||
|          * @returns Reference to changeset to make calls chainable. |          * @returns Reference to changeset to make calls chainable. | ||||||
|          */ |          */ | ||||||
|         Changeset& set_created_at(const osmium::Timestamp timestamp) { |         Changeset& set_created_at(const osmium::Timestamp& timestamp) { | ||||||
|             m_created_at = timestamp; |             m_created_at = timestamp; | ||||||
|             return *this; |             return *this; | ||||||
|         } |         } | ||||||
| @ -199,7 +296,7 @@ namespace osmium { | |||||||
|          * @param timestamp Timestamp |          * @param timestamp Timestamp | ||||||
|          * @returns Reference to changeset to make calls chainable. |          * @returns Reference to changeset to make calls chainable. | ||||||
|          */ |          */ | ||||||
|         Changeset& set_closed_at(const osmium::Timestamp timestamp) { |         Changeset& set_closed_at(const osmium::Timestamp& timestamp) { | ||||||
|             m_closed_at = timestamp; |             m_closed_at = timestamp; | ||||||
|             return *this; |             return *this; | ||||||
|         } |         } | ||||||
| @ -216,10 +313,26 @@ namespace osmium { | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         /// Set the number of changes in this changeset
 |         /// Set the number of changes in this changeset
 | ||||||
|         Changeset& set_num_changes(const char* num_changes) noexcept { |         Changeset& set_num_changes(const char* num_changes) { | ||||||
|             return set_num_changes(osmium::string_to_num_changes(num_changes)); |             return set_num_changes(osmium::string_to_num_changes(num_changes)); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         /// Get the number of comments in this changeset
 | ||||||
|  |         num_comments_type num_comments() const noexcept { | ||||||
|  |             return m_num_comments; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         /// Set the number of comments in this changeset
 | ||||||
|  |         Changeset& set_num_comments(num_comments_type num_comments) noexcept { | ||||||
|  |             m_num_comments = num_comments; | ||||||
|  |             return *this; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         /// Set the number of comments in this changeset
 | ||||||
|  |         Changeset& set_num_comments(const char* num_comments) { | ||||||
|  |             return set_num_comments(osmium::string_to_num_comments(num_comments)); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         /**
 |         /**
 | ||||||
|          * Get the bounding box of this changeset. |          * Get the bounding box of this changeset. | ||||||
|          * |          * | ||||||
| @ -260,6 +373,8 @@ namespace osmium { | |||||||
|                 set_id(value); |                 set_id(value); | ||||||
|             } else if (!strcmp(attr, "num_changes")) { |             } else if (!strcmp(attr, "num_changes")) { | ||||||
|                 set_num_changes(value); |                 set_num_changes(value); | ||||||
|  |             } else if (!strcmp(attr, "comments_count")) { | ||||||
|  |                 set_num_comments(value); | ||||||
|             } else if (!strcmp(attr, "created_at")) { |             } else if (!strcmp(attr, "created_at")) { | ||||||
|                 set_created_at(osmium::Timestamp(value)); |                 set_created_at(osmium::Timestamp(value)); | ||||||
|             } else if (!strcmp(attr, "closed_at")) { |             } else if (!strcmp(attr, "closed_at")) { | ||||||
| @ -296,6 +411,14 @@ namespace osmium { | |||||||
|             return cend(); |             return cend(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         ChangesetDiscussion& discussion() { | ||||||
|  |             return osmium::detail::subitem_of_type<ChangesetDiscussion>(begin(), end()); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         const ChangesetDiscussion& discussion() const { | ||||||
|  |             return osmium::detail::subitem_of_type<const ChangesetDiscussion>(cbegin(), cend()); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|     }; // class Changeset
 |     }; // class Changeset
 | ||||||
| 
 | 
 | ||||||
|     static_assert(sizeof(Changeset) % osmium::memory::align_bytes == 0, "Class osmium::Changeset has wrong size to be aligned properly!"); |     static_assert(sizeof(Changeset) % osmium::memory::align_bytes == 0, "Class osmium::Changeset has wrong size to be aligned properly!"); | ||||||
|  | |||||||
							
								
								
									
										53
									
								
								third_party/libosmium/include/osmium/osm/crc.hpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										53
									
								
								third_party/libosmium/include/osmium/osm/crc.hpp
									
									
									
									
										vendored
									
									
								
							| @ -46,10 +46,9 @@ DEALINGS IN THE SOFTWARE. | |||||||
| 
 | 
 | ||||||
| namespace osmium { | namespace osmium { | ||||||
| 
 | 
 | ||||||
|     template <class TCRC> |     namespace util { | ||||||
|     class CRC { |  | ||||||
| 
 | 
 | ||||||
|         static inline uint16_t byte_swap_16(uint16_t value) noexcept { |         inline uint16_t byte_swap_16(uint16_t value) noexcept { | ||||||
| # if defined(__GNUC__) || defined(__clang__) | # if defined(__GNUC__) || defined(__clang__) | ||||||
|             return __builtin_bswap16(value); |             return __builtin_bswap16(value); | ||||||
| # else | # else | ||||||
| @ -57,27 +56,32 @@ namespace osmium { | |||||||
| # endif | # endif | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         static inline uint32_t byte_swap_32(uint32_t value) noexcept { |         inline uint32_t byte_swap_32(uint32_t value) noexcept { | ||||||
| # if defined(__GNUC__) || defined(__clang__) | # if defined(__GNUC__) || defined(__clang__) | ||||||
|             return __builtin_bswap32(value); |             return __builtin_bswap32(value); | ||||||
| # else | # else | ||||||
|             return  (value >> 24) | |             return  (value >> 24) | | ||||||
|                     ((value >>  8) & 0x0000FF00) | |                    ((value >>  8) & 0x0000FF00) | | ||||||
|                     ((value <<  8) & 0x00FF0000) | |                    ((value <<  8) & 0x00FF0000) | | ||||||
|                     (value << 24); |                     (value << 24); | ||||||
| # endif | # endif | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         static inline uint64_t byte_swap_64(uint64_t value) noexcept { |         inline uint64_t byte_swap_64(uint64_t value) noexcept { | ||||||
| # if defined(__GNUC__) || defined(__clang__) | # if defined(__GNUC__) || defined(__clang__) | ||||||
|             return __builtin_bswap64(value); |             return __builtin_bswap64(value); | ||||||
| # else | # else | ||||||
|             uint64_t val1 = byte_swap_32(value & 0xFFFFFFFF); |             uint64_t val1 = byte_swap_32(value & 0xFFFFFFFF); | ||||||
|             uint64_t val2 = byte_swap_32(value >> 32); |             uint64_t val2 = byte_swap_32(value >> 32); | ||||||
|             return (val1 << 32) & val2; |             return (val1 << 32) | val2; | ||||||
| # endif | # endif | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |     } // namespace util
 | ||||||
|  | 
 | ||||||
|  |     template <typename TCRC> | ||||||
|  |     class CRC { | ||||||
|  | 
 | ||||||
|         TCRC m_crc; |         TCRC m_crc; | ||||||
| 
 | 
 | ||||||
|     public: |     public: | ||||||
| @ -90,37 +94,37 @@ namespace osmium { | |||||||
|             return m_crc; |             return m_crc; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         void update_bool(bool value) { |         void update_bool(const bool value) { | ||||||
|             m_crc.process_byte(value); |             m_crc.process_byte(value); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         void update_int8(uint8_t value) { |         void update_int8(const uint8_t value) { | ||||||
|             m_crc.process_byte(value); |             m_crc.process_byte(value); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         void update_int16(uint16_t value) { |         void update_int16(const uint16_t value) { | ||||||
| #if __BYTE_ORDER == __LITTLE_ENDIAN | #if __BYTE_ORDER == __LITTLE_ENDIAN | ||||||
|             m_crc.process_bytes(&value, sizeof(uint16_t)); |             m_crc.process_bytes(&value, sizeof(uint16_t)); | ||||||
| #else | #else | ||||||
|             uint16_t v = byte_swap_16(value); |             uint16_t v = osmium::util::byte_swap_16(value); | ||||||
|             m_crc.process_bytes(&v, sizeof(uint16_t)); |             m_crc.process_bytes(&v, sizeof(uint16_t)); | ||||||
| #endif | #endif | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         void update_int32(uint32_t value) { |         void update_int32(const uint32_t value) { | ||||||
| #if __BYTE_ORDER == __LITTLE_ENDIAN | #if __BYTE_ORDER == __LITTLE_ENDIAN | ||||||
|             m_crc.process_bytes(&value, sizeof(uint32_t)); |             m_crc.process_bytes(&value, sizeof(uint32_t)); | ||||||
| #else | #else | ||||||
|             uint32_t v = byte_swap_32(value); |             uint32_t v = osmium::util::byte_swap_32(value); | ||||||
|             m_crc.process_bytes(&v, sizeof(uint32_t)); |             m_crc.process_bytes(&v, sizeof(uint32_t)); | ||||||
| #endif | #endif | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         void update_int64(uint64_t value) { |         void update_int64(const uint64_t value) { | ||||||
| #if __BYTE_ORDER == __LITTLE_ENDIAN | #if __BYTE_ORDER == __LITTLE_ENDIAN | ||||||
|             m_crc.process_bytes(&value, sizeof(uint64_t)); |             m_crc.process_bytes(&value, sizeof(uint64_t)); | ||||||
| #else | #else | ||||||
|             uint64_t v = byte_swap_64(value); |             uint64_t v = osmium::util::byte_swap_64(value); | ||||||
|             m_crc.process_bytes(&v, sizeof(uint64_t)); |             m_crc.process_bytes(&v, sizeof(uint64_t)); | ||||||
| #endif | #endif | ||||||
|         } |         } | ||||||
| @ -156,7 +160,10 @@ namespace osmium { | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         void update(const TagList& tags) { |         void update(const TagList& tags) { | ||||||
|             m_crc.process_bytes(tags.data(), tags.byte_size()); |             for (const Tag& tag : tags) { | ||||||
|  |                 update_string(tag.key()); | ||||||
|  |                 update_string(tag.value()); | ||||||
|  |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         void update(const osmium::RelationMember& member) { |         void update(const osmium::RelationMember& member) { | ||||||
| @ -206,14 +213,26 @@ namespace osmium { | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         void update(const osmium::ChangesetDiscussion& discussion) { | ||||||
|  |             for (const auto& comment : discussion) { | ||||||
|  |                 update(comment.date()); | ||||||
|  |                 update_int32(comment.uid()); | ||||||
|  |                 update_string(comment.user()); | ||||||
|  |                 update_string(comment.text()); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         void update(const osmium::Changeset& changeset) { |         void update(const osmium::Changeset& changeset) { | ||||||
|             update_int64(changeset.id()); |             update_int64(changeset.id()); | ||||||
|             update(changeset.created_at()); |             update(changeset.created_at()); | ||||||
|             update(changeset.closed_at()); |             update(changeset.closed_at()); | ||||||
|             update(changeset.bounds()); |             update(changeset.bounds()); | ||||||
|             update_int32(changeset.num_changes()); |             update_int32(changeset.num_changes()); | ||||||
|  |             update_int32(changeset.num_comments()); | ||||||
|             update_int32(changeset.uid()); |             update_int32(changeset.uid()); | ||||||
|             update_string(changeset.user()); |             update_string(changeset.user()); | ||||||
|  |             update(changeset.tags()); | ||||||
|  |             update(changeset.discussion()); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|     }; // class CRC
 |     }; // class CRC
 | ||||||
|  | |||||||
| @ -33,6 +33,9 @@ DEALINGS IN THE SOFTWARE. | |||||||
| 
 | 
 | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
|  | #include <cassert> | ||||||
|  | 
 | ||||||
|  | #include <osmium/fwd.hpp> | ||||||
| #include <osmium/osm/item_type.hpp> | #include <osmium/osm/item_type.hpp> | ||||||
| #include <osmium/osm/object.hpp> | #include <osmium/osm/object.hpp> | ||||||
| #include <osmium/osm/timestamp.hpp> | #include <osmium/osm/timestamp.hpp> | ||||||
| @ -40,75 +43,158 @@ DEALINGS IN THE SOFTWARE. | |||||||
| 
 | 
 | ||||||
| namespace osmium { | namespace osmium { | ||||||
| 
 | 
 | ||||||
|     class Node; |     /**
 | ||||||
|     class Way; |      * A DiffObject holds pointers to three OSMObjects, the current object, | ||||||
|     class Relation; |      * the previous, and the next. They always have the same type (Node, Way, | ||||||
| 
 |      * or Relation) and the same ID, but may have different versions. | ||||||
|  |      * | ||||||
|  |      * It is used when iterating over OSM files with history data to make | ||||||
|  |      * working with versioned OSM objects easier. Because you have access to | ||||||
|  |      * the previous and next objects as well as the current one, comparisons | ||||||
|  |      * between object versions is easy. | ||||||
|  |      * | ||||||
|  |      * If the current object is the first version available, the previous | ||||||
|  |      * pointer must be the same as the current one. If the current object is | ||||||
|  |      * the last version available, the next pointer must be the same as the | ||||||
|  |      * current one. | ||||||
|  |      * | ||||||
|  |      * DiffObjects are immutable. | ||||||
|  |      */ | ||||||
|     class DiffObject { |     class DiffObject { | ||||||
| 
 | 
 | ||||||
|     protected: |         const osmium::OSMObject* m_prev; | ||||||
| 
 |         const osmium::OSMObject* m_curr; | ||||||
|         osmium::OSMObject* m_prev; |         const osmium::OSMObject* m_next; | ||||||
|         osmium::OSMObject* m_curr; |  | ||||||
|         osmium::OSMObject* m_next; |  | ||||||
| 
 | 
 | ||||||
|     public: |     public: | ||||||
| 
 | 
 | ||||||
|  |         /**
 | ||||||
|  |          * Default construct an empty DiffObject. Most methods of this class | ||||||
|  |          * can not be called on empty DiffObjects. | ||||||
|  |          */ | ||||||
|         DiffObject() noexcept : |         DiffObject() noexcept : | ||||||
|             m_prev(nullptr), |             m_prev(nullptr), | ||||||
|             m_curr(nullptr), |             m_curr(nullptr), | ||||||
|             m_next(nullptr) { |             m_next(nullptr) { | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         explicit DiffObject(osmium::OSMObject& prev, osmium::OSMObject& curr, osmium::OSMObject& next) noexcept : |         /**
 | ||||||
|  |          * Construct a non-empty DiffObject from the given OSMObjects. All | ||||||
|  |          * OSMObjects must be of the same type (Node, Way, or Relation) and | ||||||
|  |          * have the same ID. | ||||||
|  |          */ | ||||||
|  |         DiffObject(const osmium::OSMObject& prev, const osmium::OSMObject& curr, const osmium::OSMObject& next) noexcept : | ||||||
|             m_prev(&prev), |             m_prev(&prev), | ||||||
|             m_curr(&curr), |             m_curr(&curr), | ||||||
|             m_next(&next) { |             m_next(&next) { | ||||||
|  |             assert(prev.type() == curr.type() && curr.type() == next.type()); | ||||||
|  |             assert(prev.id()   == curr.id()   && curr.id()   == next.id()); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         DiffObject(const DiffObject&) = default; |         /**
 | ||||||
|         DiffObject& operator=(const DiffObject&) = default; |          * Check whether the DiffObject was created empty. | ||||||
| 
 |          */ | ||||||
|         DiffObject(DiffObject&&) = default; |         bool empty() const noexcept { | ||||||
|         DiffObject& operator=(DiffObject&&) = default; |             return m_prev == nullptr; | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|  |         /**
 | ||||||
|  |          * Get the previous object stored. | ||||||
|  |          * | ||||||
|  |          * @pre DiffObject must not be empty. | ||||||
|  |          */ | ||||||
|         const osmium::OSMObject& prev() const noexcept { |         const osmium::OSMObject& prev() const noexcept { | ||||||
|  |             assert(m_prev && m_curr && m_next); | ||||||
|             return *m_prev; |             return *m_prev; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         /**
 | ||||||
|  |          * Get the current object stored. | ||||||
|  |          * | ||||||
|  |          * @pre DiffObject must not be empty. | ||||||
|  |          */ | ||||||
|         const osmium::OSMObject& curr() const noexcept { |         const osmium::OSMObject& curr() const noexcept { | ||||||
|  |             assert(m_prev && m_curr && m_next); | ||||||
|             return *m_curr; |             return *m_curr; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         /**
 | ||||||
|  |          * Get the next object stored. | ||||||
|  |          * | ||||||
|  |          * @pre DiffObject must not be empty. | ||||||
|  |          */ | ||||||
|         const osmium::OSMObject& next() const noexcept { |         const osmium::OSMObject& next() const noexcept { | ||||||
|  |             assert(m_prev && m_curr && m_next); | ||||||
|             return *m_next; |             return *m_next; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         /**
 | ||||||
|  |          * Is the current object version the first (with this type and ID)? | ||||||
|  |          * | ||||||
|  |          * @pre DiffObject must not be empty. | ||||||
|  |          */ | ||||||
|         bool first() const noexcept { |         bool first() const noexcept { | ||||||
|  |             assert(m_prev && m_curr && m_next); | ||||||
|             return m_prev == m_curr; |             return m_prev == m_curr; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         /**
 | ||||||
|  |          * Is the current object version the last (with this type and ID)? | ||||||
|  |          * | ||||||
|  |          * @pre DiffObject must not be empty. | ||||||
|  |          */ | ||||||
|         bool last() const noexcept { |         bool last() const noexcept { | ||||||
|  |             assert(m_prev && m_curr && m_next); | ||||||
|             return m_curr == m_next; |             return m_curr == m_next; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         /**
 | ||||||
|  |          * Return the type of the current object. | ||||||
|  |          * | ||||||
|  |          * @pre DiffObject must not be empty. | ||||||
|  |          */ | ||||||
|         osmium::item_type type() const noexcept { |         osmium::item_type type() const noexcept { | ||||||
|  |             assert(m_prev && m_curr && m_next); | ||||||
|             return m_curr->type(); |             return m_curr->type(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         /**
 | ||||||
|  |          * Return the ID of the current object. | ||||||
|  |          * | ||||||
|  |          * @pre DiffObject must not be empty. | ||||||
|  |          */ | ||||||
|         osmium::object_id_type id() const noexcept { |         osmium::object_id_type id() const noexcept { | ||||||
|  |             assert(m_prev && m_curr && m_next); | ||||||
|             return m_curr->id(); |             return m_curr->id(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         /**
 | ||||||
|  |          * Return the version of the current object. | ||||||
|  |          * | ||||||
|  |          * @pre DiffObject must not be empty. | ||||||
|  |          */ | ||||||
|         osmium::object_version_type version() const noexcept { |         osmium::object_version_type version() const noexcept { | ||||||
|  |             assert(m_prev && m_curr && m_next); | ||||||
|             return m_curr->version(); |             return m_curr->version(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         /**
 | ||||||
|  |          * Return the changeset ID of the current object. | ||||||
|  |          * | ||||||
|  |          * @pre DiffObject must not be empty. | ||||||
|  |          */ | ||||||
|         osmium::changeset_id_type changeset() const noexcept { |         osmium::changeset_id_type changeset() const noexcept { | ||||||
|  |             assert(m_prev && m_curr && m_next); | ||||||
|             return m_curr->changeset(); |             return m_curr->changeset(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         /**
 | ||||||
|  |          * Return the timestamp when the current object version was created. | ||||||
|  |          * | ||||||
|  |          * @pre DiffObject must not be empty. | ||||||
|  |          */ | ||||||
|         const osmium::Timestamp start_time() const noexcept { |         const osmium::Timestamp start_time() const noexcept { | ||||||
|  |             assert(m_prev && m_curr && m_next); | ||||||
|             return m_curr->timestamp(); |             return m_curr->timestamp(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| @ -118,8 +204,11 @@ namespace osmium { | |||||||
|          * is valid. If this is the last version of the object, this will |          * is valid. If this is the last version of the object, this will | ||||||
|          * return a special "end of time" timestamp that is guaranteed to |          * return a special "end of time" timestamp that is guaranteed to | ||||||
|          * be larger than any normal timestamp. |          * be larger than any normal timestamp. | ||||||
|  |          * | ||||||
|  |          * @pre DiffObject must not be empty. | ||||||
|          */ |          */ | ||||||
|         const osmium::Timestamp end_time() const noexcept { |         const osmium::Timestamp end_time() const noexcept { | ||||||
|  |             assert(m_prev && m_curr && m_next); | ||||||
|             return last() ? osmium::end_of_time() : m_next->timestamp(); |             return last() ? osmium::end_of_time() : m_next->timestamp(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| @ -129,8 +218,11 @@ namespace osmium { | |||||||
|          * |          * | ||||||
|          * This is a bit more complex than you'd think, because we have to |          * This is a bit more complex than you'd think, because we have to | ||||||
|          * handle the case properly where the start_time() == end_time(). |          * handle the case properly where the start_time() == end_time(). | ||||||
|  |          * | ||||||
|  |          * @pre DiffObject must not be empty. | ||||||
|          */ |          */ | ||||||
|         bool is_between(const osmium::Timestamp& from, const osmium::Timestamp& to) const noexcept { |         bool is_between(const osmium::Timestamp& from, const osmium::Timestamp& to) const noexcept { | ||||||
|  |             assert(m_prev && m_curr && m_next); | ||||||
|             return start_time() < to && |             return start_time() < to && | ||||||
|                    ((start_time() != end_time() && end_time() >  from) || |                    ((start_time() != end_time() && end_time() >  from) || | ||||||
|                     (start_time() == end_time() && end_time() >= from)); |                     (start_time() == end_time() && end_time() >= from)); | ||||||
| @ -138,45 +230,42 @@ namespace osmium { | |||||||
| 
 | 
 | ||||||
|         /**
 |         /**
 | ||||||
|          * Current object version is visible at the given timestamp. |          * Current object version is visible at the given timestamp. | ||||||
|  |          * | ||||||
|  |          * @pre DiffObject must not be empty. | ||||||
|          */ |          */ | ||||||
|         bool is_visible_at(const osmium::Timestamp& timestamp) const noexcept { |         bool is_visible_at(const osmium::Timestamp& timestamp) const noexcept { | ||||||
|  |             assert(m_prev && m_curr && m_next); | ||||||
|             return start_time() <= timestamp && end_time() > timestamp && m_curr->visible(); |             return start_time() <= timestamp && end_time() > timestamp && m_curr->visible(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|     }; // class DiffObject
 |     }; // class DiffObject
 | ||||||
| 
 | 
 | ||||||
|     template <class T> |     template <typename T> | ||||||
|     class DiffObjectDerived : public DiffObject { |     class DiffObjectDerived : public DiffObject { | ||||||
| 
 | 
 | ||||||
|     public: |     public: | ||||||
| 
 | 
 | ||||||
|         DiffObjectDerived(T& prev, T& curr, T& next) noexcept : |         DiffObjectDerived(const T& prev, const T& curr, const T& next) noexcept : | ||||||
|             DiffObject(prev, curr, next) { |             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 { |         const T& prev() const noexcept { | ||||||
|             return *static_cast<const T*>(m_prev); |             return static_cast<const T&>(DiffObject::prev()); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         const T& curr() const noexcept { |         const T& curr() const noexcept { | ||||||
|             return *static_cast<const T*>(m_curr); |             return static_cast<const T&>(DiffObject::curr()); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         const T& next() const noexcept { |         const T& next() const noexcept { | ||||||
|             return *static_cast<const T*>(m_next); |             return static_cast<const T&>(DiffObject::next()); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|     }; // class DiffObjectDerived
 |     }; // class DiffObjectDerived
 | ||||||
| 
 | 
 | ||||||
|     typedef DiffObjectDerived<osmium::Node>     DiffNode; |     using DiffNode     = DiffObjectDerived<osmium::Node>; | ||||||
|     typedef DiffObjectDerived<osmium::Way>      DiffWay; |     using DiffWay      = DiffObjectDerived<osmium::Way>; | ||||||
|     typedef DiffObjectDerived<osmium::Relation> DiffRelation; |     using DiffRelation = DiffObjectDerived<osmium::Relation>; | ||||||
| 
 | 
 | ||||||
| } // namespace osmium
 | } // namespace osmium
 | ||||||
| 
 | 
 | ||||||
|  | |||||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
		Reference in New Issue
	
	Block a user