[libosmium] 01/05: New upstream version 2.13.0
Bas Couwenberg
sebastic at debian.org
Tue Aug 15 17:27:41 UTC 2017
This is an automated email from the git hooks/post-receive script.
sebastic pushed a commit to branch master
in repository libosmium.
commit 89fd4ab1f5e243e62a769df212997caef5c7d3a1
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date: Tue Aug 15 19:02:20 2017 +0200
New upstream version 2.13.0
---
.codecov.yml | 7 +
.gitignore | 2 +
.travis.yml | 25 +-
CHANGELOG.md | 75 +-
CMakeLists.txt | 40 +-
README.md | 5 +-
examples/CMakeLists.txt | 4 +
examples/osmium_amenity_list.cpp | 44 +-
examples/osmium_area_test.cpp | 60 +-
examples/osmium_change_tags.cpp | 4 +-
examples/osmium_convert.cpp | 16 +-
examples/osmium_create_pois.cpp | 6 +-
examples/osmium_debug.cpp | 16 +-
examples/osmium_dump_internal.cpp | 2 +-
examples/osmium_index_lookup.cpp | 16 +-
examples/osmium_location_cache_create.cpp | 2 +-
examples/osmium_road_length.cpp | 6 +-
include/osmium/area/assembler.hpp | 230 +---
include/osmium/area/assembler_config.hpp | 8 +-
.../area/{assembler.hpp => assembler_legacy.hpp} | 84 +-
include/osmium/area/detail/basic_assembler.hpp | 135 ++-
.../area/detail/basic_assembler_with_tags.hpp | 93 ++
include/osmium/area/detail/node_ref_segment.hpp | 35 +-
include/osmium/area/detail/segment_list.hpp | 50 +-
include/osmium/area/geom_assembler.hpp | 5 +-
include/osmium/area/multipolygon_collector.hpp | 16 +-
...ygon_collector.hpp => multipolygon_manager.hpp} | 167 ++-
...llector.hpp => multipolygon_manager_legacy.hpp} | 148 +--
include/osmium/area/problem_reporter.hpp | 12 +
include/osmium/area/problem_reporter_exception.hpp | 6 +
include/osmium/area/problem_reporter_ogr.hpp | 4 +
include/osmium/area/problem_reporter_stream.hpp | 6 +
include/osmium/area/stats.hpp | 1 +
include/osmium/builder/builder.hpp | 16 +-
include/osmium/builder/osm_object_builder.hpp | 117 +-
include/osmium/diff_handler.hpp | 6 +-
include/osmium/diff_iterator.hpp | 6 +-
include/osmium/diff_visitor.hpp | 6 +-
include/osmium/dynamic_handler.hpp | 9 +-
include/osmium/experimental/flex_reader.hpp | 2 +-
include/osmium/geom/factory.hpp | 15 +-
include/osmium/geom/geos.hpp | 22 +-
include/osmium/geom/mercator_projection.hpp | 3 +
include/osmium/geom/projection.hpp | 3 +-
include/osmium/geom/relations.hpp | 12 +-
include/osmium/geom/tile.hpp | 26 +-
include/osmium/geom/wkb.hpp | 22 +-
include/osmium/handler/check_order.hpp | 23 +-
include/osmium/handler/disk_store.hpp | 4 +-
include/osmium/handler/dump.hpp | 4 +-
include/osmium/handler/node_locations_for_ways.hpp | 14 +-
include/osmium/index/detail/create_map_with_fd.hpp | 6 +-
include/osmium/index/detail/mmap_vector_file.hpp | 6 +-
include/osmium/index/detail/tmpfile.hpp | 2 +-
include/osmium/index/detail/vector_map.hpp | 15 +-
include/osmium/index/id_set.hpp | 53 +-
include/osmium/index/index.hpp | 3 +-
include/osmium/index/map.hpp | 9 +-
include/osmium/index/map/all.hpp | 1 +
include/osmium/index/map/flex_mem.hpp | 285 +++++
include/osmium/index/node_locations_map.hpp | 4 +
include/osmium/index/relations_map.hpp | 16 +-
include/osmium/io/bzip2_compression.hpp | 28 +-
include/osmium/io/compression.hpp | 49 +-
include/osmium/io/detail/debug_output_format.hpp | 17 +-
include/osmium/io/detail/input_format.hpp | 10 +-
include/osmium/io/detail/o5m_input_format.hpp | 8 +-
include/osmium/io/detail/opl_input_format.hpp | 9 +-
include/osmium/io/detail/opl_output_format.hpp | 15 +-
include/osmium/io/detail/opl_parser_functions.hpp | 23 +-
include/osmium/io/detail/output_format.hpp | 19 +-
include/osmium/io/detail/pbf_decoder.hpp | 94 +-
include/osmium/io/detail/pbf_input_format.hpp | 31 +-
include/osmium/io/detail/pbf_output_format.hpp | 54 +-
include/osmium/io/detail/read_write.hpp | 10 +-
include/osmium/io/detail/string_table.hpp | 16 +-
include/osmium/io/detail/string_util.hpp | 8 +-
include/osmium/io/detail/write_thread.hpp | 2 +-
include/osmium/io/detail/xml_input_format.hpp | 2 +-
include/osmium/io/detail/xml_output_format.hpp | 17 +-
include/osmium/io/detail/zlib.hpp | 4 +-
include/osmium/io/file.hpp | 32 +-
include/osmium/io/gzip_compression.hpp | 26 +-
include/osmium/io/header.hpp | 12 +-
include/osmium/io/reader.hpp | 44 +-
include/osmium/io/writer.hpp | 14 +-
include/osmium/memory/buffer.hpp | 91 +-
include/osmium/memory/callback_buffer.hpp | 189 +++
include/osmium/memory/item.hpp | 2 +-
include/osmium/object_pointer_collection.hpp | 10 +-
include/osmium/opl.hpp | 2 +-
include/osmium/osm/area.hpp | 4 +-
include/osmium/osm/changeset.hpp | 24 +-
include/osmium/osm/location.hpp | 36 +-
include/osmium/osm/object.hpp | 13 +-
include/osmium/osm/object_comparisons.hpp | 33 +-
include/osmium/osm/relation.hpp | 9 +-
include/osmium/osm/types.hpp | 7 +
include/osmium/osm/types_from_string.hpp | 16 +-
include/osmium/relations/collector.hpp | 7 +-
include/osmium/relations/manager_util.hpp | 197 ++++
include/osmium/relations/members_database.hpp | 406 +++++++
include/osmium/relations/relations_database.hpp | 335 ++++++
include/osmium/relations/relations_manager.hpp | 567 +++++++++
include/osmium/storage/item_stash.hpp | 342 ++++++
include/osmium/thread/function_wrapper.hpp | 3 +-
include/osmium/thread/pool.hpp | 35 +-
include/osmium/thread/queue.hpp | 9 +-
include/osmium/util/config.hpp | 5 +-
include/osmium/util/file.hpp | 26 +-
include/osmium/util/iterator.hpp | 21 +-
include/osmium/util/memory_mapping.hpp | 91 +-
include/osmium/util/options.hpp | 12 +-
include/osmium/util/progress_bar.hpp | 21 +-
include/osmium/util/string.hpp | 14 +-
include/osmium/util/verbose_output.hpp | 4 +-
include/osmium/version.hpp | 6 +-
include/protozero/pbf_builder.hpp | 18 +-
include/protozero/pbf_message.hpp | 4 +
include/protozero/pbf_reader.hpp | 8 +-
include/protozero/pbf_writer.hpp | 11 +
include/protozero/types.hpp | 8 +-
include/protozero/version.hpp | 4 +-
test/CMakeLists.txt | 16 +
test/data-tests/testdata-multipolygon.cpp | 6 +-
test/data-tests/testdata-xml.cpp | 4 +-
test/examples/t/amenity_list/CMakeLists.txt | 10 +-
test/examples/t/amenity_list/area.osm | 18 +
test/examples/t/area_test/CMakeLists.txt | 25 +
test/examples/t/area_test/data.osm | 34 +
test/examples/t/change_tags/CMakeLists.txt | 9 +
test/examples/t/change_tags/data.osm | 20 +
test/examples/t/change_tags/result.osm | 16 +
test/examples/t/convert/CMakeLists.txt | 46 +
test/examples/t/convert/data.osm | 34 +
test/examples/t/count/CMakeLists.txt | 8 +
test/examples/t/count/data.osm | 12 +
test/examples/t/create_pois/CMakeLists.txt | 13 +
test/examples/t/debug/CMakeLists.txt | 55 +
test/examples/t/debug/changesets.osm | 7 +
test/examples/t/debug/data.osm | 13 +
test/examples/t/dump_internal/CMakeLists.txt | 41 +
test/examples/t/dump_internal/data.osm | 34 +
test/examples/t/filter_discussions/CMakeLists.txt | 10 +
test/examples/t/filter_discussions/changesets.osm | 11 +
test/examples/t/index_lookup/CMakeLists.txt | 46 +
test/examples/t/location_cache/CMakeLists.txt | 36 +
test/examples/t/location_cache/data.osm | 7 +
test/examples/t/location_cache/way.osm | 9 +
test/examples/t/pub_names/CMakeLists.txt | 22 +-
.../t/pub_names/{pubs.osm => pub-addr.osm} | 3 +
.../t/pub_names/{pubs.osm => pub-node.osm} | 0
.../t/pub_names/{pubs.osm => pub-noname.osm} | 1 -
test/examples/t/pub_names/pub-way.osm | 21 +
test/examples/t/read/CMakeLists.txt | 4 +
test/examples/t/read/data.osm | 29 +
test/examples/t/read_with_progress/CMakeLists.txt | 4 +
test/examples/t/read_with_progress/data.osm | 29 +
test/examples/t/tiles/CMakeLists.txt | 18 +
test/include/catch.hpp | 1222 +++++++++++++-------
test/t/area/test_node_ref_segment.cpp | 10 +-
test/t/geom/test_geojson.cpp | 20 +-
test/t/geom/test_geos.cpp | 2 +-
test/t/geom/test_mercator.cpp | 57 +-
test/t/geom/test_ogr.cpp | 2 +-
test/t/geom/test_projection.cpp | 4 +-
test/t/geom/test_tile.cpp | 28 +-
test/t/geom/test_wkb.cpp | 16 +-
test/t/geom/test_wkt.cpp | 36 +-
test/t/handler/test_check_order_handler.cpp | 128 ++
test/t/handler/test_dynamic_handler.cpp | 116 ++
test/t/index/test_file_based_index.cpp | 78 +-
test/t/index/test_id_to_location.cpp | 89 +-
test/t/io/test_bzip2.cpp | 2 +-
test/t/io/test_compression_factory.cpp | 27 +-
test/t/io/test_file_formats.cpp | 82 +-
test/t/io/test_opl_parser.cpp | 20 +-
test/t/io/test_output_iterator.cpp | 41 +-
test/t/io/test_reader.cpp | 21 +-
test/t/io/test_reader_fileformat.cpp | 2 +-
test/t/io/test_reader_with_mock_parser.cpp | 4 +-
test/t/io/test_string_table.cpp | 178 +--
test/t/io/test_writer.cpp | 45 +-
test/t/io/test_writer_with_mock_compression.cpp | 6 +-
test/t/io/test_writer_with_mock_encoder.cpp | 14 +-
test/t/memory/test_buffer_basics.cpp | 85 +-
test/t/memory/test_buffer_node.cpp | 2 +-
test/t/memory/test_callback_buffer.cpp | 101 ++
test/t/memory/test_item.cpp | 25 +
test/t/osm/test_area.cpp | 2 +-
test/t/osm/test_box.cpp | 228 ++--
test/t/osm/test_changeset.cpp | 2 +-
test/t/osm/test_crc.cpp | 92 +-
test/t/osm/test_location.cpp | 283 +++--
test/t/osm/test_node.cpp | 25 +-
test/t/osm/test_node_ref.cpp | 34 +-
test/t/osm/test_object_comparisons.cpp | 72 +-
test/t/osm/test_timestamp.cpp | 164 ++-
test/t/osm/test_types_from_string.cpp | 78 +-
test/t/osm/test_way.cpp | 4 +-
test/t/relations/data.osm | 32 +
test/t/relations/dupl_member.osm | 17 +
test/t/relations/test_members_database.cpp | 194 ++++
test/t/relations/test_read_relations.cpp | 77 ++
test/t/relations/test_relations_database.cpp | 105 ++
test/t/relations/test_relations_manager.cpp | 248 ++++
test/t/storage/test_item_stash.cpp | 167 +++
test/t/tags/test_filter.cpp | 22 +-
test/t/tags/test_operators.cpp | 93 +-
test/t/thread/test_pool.cpp | 56 +-
test/t/thread/test_util.cpp | 37 +
test/t/util/test_cast_with_assert.cpp | 10 +-
test/t/util/test_config.cpp | 75 ++
test/t/util/test_delta.cpp | 31 +
test/t/util/test_file.cpp | 8 +-
test/t/util/test_options.cpp | 117 +-
test/t/util/test_string.cpp | 57 +-
test/t/util/test_string_matcher.cpp | 41 +-
test/t/util/test_timer_disabled.cpp | 15 +
test/t/util/test_timer_enabled.cpp | 16 +
220 files changed, 8044 insertions(+), 2666 deletions(-)
diff --git a/.codecov.yml b/.codecov.yml
new file mode 100644
index 0000000..79204cd
--- /dev/null
+++ b/.codecov.yml
@@ -0,0 +1,7 @@
+
+ignore:
+ - "include/gdalcpp.hpp"
+ - "include/protozero"
+ - "include/utf8"
+ - "test/include/catch.hpp"
+
diff --git a/.gitignore b/.gitignore
index 79e5e65..bfc4ceb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,6 @@
*.swp
.ycm_extra_conf.pyc
+/_build*
/build
/libosmium-deps
+/.vs*
diff --git a/.travis.yml b/.travis.yml
index 91ee842..3323963 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -141,6 +141,14 @@ matrix:
packages: ['g++-6', 'libboost1.55-all-dev', 'libgdal-dev', 'libgeos++-dev', 'libproj-dev', 'libsparsehash-dev', 'spatialite-bin']
env: COMPILER='g++-6' BUILD_TYPE='Dev'
+ - os: linux
+ compiler: linux-gcc6-coverage
+ addons:
+ apt:
+ sources: ['ubuntu-toolchain-r-test', 'boost-latest']
+ packages: ['g++-6', 'libboost1.55-all-dev', 'libgdal-dev', 'libgeos++-dev', 'libproj-dev', 'libsparsehash-dev', 'spatialite-bin']
+ env: COMPILER='g++-6' BUILD_TYPE='Coverage'
+
# 3/ OSX Clang Builds
- os: osx
@@ -166,12 +174,12 @@ matrix:
- os: osx
- osx_image: xcode8
+ osx_image: xcode8.3
compiler: xcode8-clang-release
env: COMPILER='clang++' BUILD_TYPE='Release'
- os: osx
- osx_image: xcode8
+ osx_image: xcode8.3
compiler: xcode8-clang-dev
env: COMPILER='clang++' BUILD_TYPE='Dev'
@@ -195,3 +203,16 @@ before_script:
script:
- make VERBOSE=1 && ctest --output-on-failure
+after_success:
+ - |
+ if [ "${BUILD_TYPE}" = "Coverage" ]; then
+ curl -S -f https://codecov.io/bash -o codecov
+ chmod +x codecov
+ gcov-${COMPILER#g++-} -p $(find test/CMakeFiles -name '*.o')
+ ./codecov -Z -c -F unit_tests
+ gcov-${COMPILER#g++-} -p $(find test/data-tests -name '*.o')
+ ./codecov -Z -c -F data_tests
+ gcov-${COMPILER#g++-} -p $(find examples -name '*.o')
+ ./codecov -Z -c -F examples
+ fi
+
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a7ddcc3..9d90ae3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,7 +13,77 @@ This project adheres to [Semantic Versioning](http://semver.org/).
### Fixed
-## [2.12.2] - 2017-05-3
+## [2.13.0] - 2017-08-15
+
+### Added
+
+- New `RelationsManager` class superseeds the `relations::Collector` class.
+ The new class is much more modular and easier to extend. If you are using
+ the Collector class, you are encouraged to switch.
+- New `MultipolygonManager` based on the `RelationsManager` class superseeds
+ the `MultipolygonCollector` class. The examples have been changed to use the
+ new class and all users are encouraged to switch. There is also a
+ `MultipolygonManagerLegacy` class if you still need old-style multipolygon
+ support (see below).
+- New `FlexMem` index class that works with input files of any size and
+ stores the index in memory. This should now be used as the default index
+ for node location stores. Several example programs now use this index.
+- New `CallbackBuffer` class, basically a convenient wrapper around the
+ `Buffer` class with an additional callback function that is called whenever
+ the buffer is full.
+- Introduce new `ItemStash` class for storing OSM objects in memory.
+- New `osmium::geom::overlaps()` function to check if two `Box` objects
+ overlap.
+- Add function `IdSet::used_memory()` to get estimate of memory used in the
+ set.
+- New `is_defined()` and `is_undefined()` methods on `Location` class.
+- Tests for all provided example programs. (Some tests currently fail
+ on Windows for the `osmium_index_lookup` program.)
+
+### Changed
+
+- The area `Assembler` now doesn't work with old-style multipolygons (those
+ are multipolygon relations with the tags on the outer ways(s) instead of
+ on the relation) any more. Because old-style multipolygons are now (mostly)
+ gone from the OSM database this is usually what you want. The new
+ `AssemblerLegacy` class can be used if you actually need support for
+ old-style multipolygons, for instance if you are working with historical
+ data. (In that case you also need to use the `MultipolygonManagerLegacy`
+ class instead of the `MultipolygonManager` class.)
+- Changes for consistent ordering of OSM data: OSM data can come in any order,
+ but usual OSM files are ordered by type, ID, and version. These changes
+ extend this ordering to negative IDs which are sometimes used for objects
+ that have not been uploaded to the OSM server yet. The negative IDs are
+ ordered now before the positive ones, both in order of their absolute value.
+ This is the same ordering as JOSM uses.
+- Multipolygon assembler now checks for three or more overlapping segments
+ which are always an error and can report them.
+- Enable use of user-provided `thread::Pool` instances in `Reader` and
+ `Writer` for special use cases.
+- Growing a `Buffer` will now work with any capacity parameter, it is
+ always rounded up for proper alignment. Buffer constructor with three
+ arguments will now check that commmitted is not larger than capacity.
+- Updated embedded protozero to 1.5.2.
+- Update version of Catch unit test framework to 1.9.7.
+- And, as always, lots of small code cleanups and more tests.
+
+### Fixed
+
+- Buffers larger than 2^32 bytes do now work.
+- Output coordinate with value of -2^31 correctly.
+- Changeset comments with more than 2^16 characters are now allowed. The new
+ maximum size is 2^32.
+- `ChangesetDiscussionBuilder::add_comment_text()` could fail silently instead
+ of throwing an exception.
+- Changeset bounding boxes are now always output to OSM files (any format)
+ if at least one of the corners is defined. This is needed to handle broken
+ data from the main OSM database which contains such cases. The OPL reader
+ has also been fixed to handle this case.
+- In the example `osmium_location_cache_create`, the index file written is
+ always truncated first.
+
+
+## [2.12.2] - 2017-05-03
### Added
@@ -640,7 +710,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
Doxygen (up to version 1.8.8). This version contains a workaround to fix
this.
-[unreleased]: https://github.com/osmcode/libosmium/compare/v2.12.2...HEAD
+[unreleased]: https://github.com/osmcode/libosmium/compare/v2.13.0...HEAD
+[2.13.0]: https://github.com/osmcode/libosmium/compare/v2.12.2...v2.13.0
[2.12.2]: https://github.com/osmcode/libosmium/compare/v2.12.1...v2.12.2
[2.12.1]: https://github.com/osmcode/libosmium/compare/v2.12.0...v2.12.1
[2.12.0]: https://github.com/osmcode/libosmium/compare/v2.11.0...v2.12.0
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 264c3ed..3c5e62f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -24,8 +24,8 @@ set(CMAKE_CONFIGURATION_TYPES "Debug;Release;RelWithDebInfo;MinSizeRel;Dev;Cover
project(libosmium)
set(LIBOSMIUM_VERSION_MAJOR 2)
-set(LIBOSMIUM_VERSION_MINOR 12)
-set(LIBOSMIUM_VERSION_PATCH 2)
+set(LIBOSMIUM_VERSION_MINOR 13)
+set(LIBOSMIUM_VERSION_PATCH 0)
set(LIBOSMIUM_VERSION
"${LIBOSMIUM_VERSION_MAJOR}.${LIBOSMIUM_VERSION_MINOR}.${LIBOSMIUM_VERSION_PATCH}")
@@ -43,8 +43,14 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
if(CMAKE_BUILD_TYPE STREQUAL "Dev")
set(dev_build ON)
+ set(data_test_build ON)
else()
set(dev_build OFF)
+ set(data_test_build OFF)
+endif()
+
+if(CMAKE_BUILD_TYPE STREQUAL "Coverage")
+ set(data_test_build ON)
endif()
option(BUILD_EXAMPLES "compile example programs" ON)
@@ -52,7 +58,8 @@ option(BUILD_TESTING "compile unit tests, please run them with ctest" ON)
option(BUILD_HEADERS "compile every header file on its own" ${dev_build})
option(BUILD_BENCHMARKS "compile benchmark programs" ${dev_build})
-option(BUILD_DATA_TESTS "compile data tests, please run them with ctest" ${dev_build})
+
+option(BUILD_DATA_TESTS "compile data tests, please run them with ctest" ${data_test_build})
option(INSTALL_GDALCPP "also install gdalcpp headers" OFF)
option(INSTALL_PROTOZERO "also install protozero headers" OFF)
@@ -88,11 +95,12 @@ endif()
#
#-----------------------------------------------------------------------------
-include(CheckCXXCompilerFlag)
-check_cxx_compiler_flag("-fkeep-inline-functions" HAS_KEEP_INLINE_FUNCTIONS)
-if(HAS_KEEP_INLINE_FUNCTIONS)
- set(extra_coverage_flags_ "-fkeep-inline-functions")
-endif()
+## This leads to all sorts of compile problems, so disable for now
+#include(CheckCXXCompilerFlag)
+#check_cxx_compiler_flag("-fkeep-inline-functions" HAS_KEEP_INLINE_FUNCTIONS)
+#if(HAS_KEEP_INLINE_FUNCTIONS)
+# set(extra_coverage_flags_ "-fkeep-inline-functions")
+#endif()
set(CMAKE_CXX_FLAGS_COVERAGE
"-g -O0 -fno-inline-functions -fno-inline --coverage ${extra_coverage_flags_}"
@@ -103,8 +111,8 @@ set(CMAKE_EXE_LINKER_FLAGS_COVERAGE
CACHE STRING "Flags used by the linker during coverage builds.")
if(CMAKE_BUILD_TYPE STREQUAL "Coverage")
- if(BUILD_EXAMPLES OR BUILD_HEADERS OR BUILD_BENCHMARKS OR BUILD_DATA_TESTS)
- message(WARNING "Coverage builds don't work for anything but the unit tests")
+ if(BUILD_EXAMPLES OR BUILD_HEADERS OR BUILD_BENCHMARKS)
+ message(WARNING "Coverage builds don't work for anything but the tests")
endif()
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
@@ -314,7 +322,13 @@ find_program(CPPCHECK cppcheck)
if(CPPCHECK)
message(STATUS "Looking for cppcheck - found")
set(CPPCHECK_OPTIONS
- --enable=warning,style,performance,portability,information,missingInclude --force -Uassert)
+ --language=c++
+ --quiet
+ -j4
+ --inline-suppr
+ --enable=warning,style,performance,portability,information,missingInclude
+ --force
+ -Uassert -DPROTOZERO_STRICT_API -DPROTOZERO_USE_BUILTIN_BSWAP -UPROTOZERO_USE_VIEW)
# cpp doesn't find system includes for some reason, suppress that report
set(CPPCHECK_OPTIONS ${CPPCHECK_OPTIONS} --suppress=missingIncludeSystem)
@@ -473,10 +487,12 @@ if(CLANG_TIDY)
list(APPEND CT_CHECKS "misc-*"
"-misc-argument-comment")
- list(APPEND CT_CHECKS "modernize-*")
+ list(APPEND CT_CHECKS "modernize-*"
+ "-modernize-make-unique") # not available in C++11
list(APPEND CT_CHECKS "readability-*"
"-readability-identifier-naming"
+ "-readability-implicit-bool-cast"
"-readability-named-parameter")
string(REPLACE ";" "," ALL_CHECKS "${CT_CHECKS}")
diff --git a/README.md b/README.md
index ce27fea..b4fc4dc 100644
--- a/README.md
+++ b/README.md
@@ -6,8 +6,9 @@ A fast and flexible C++ library for working with OpenStreetMap data.
Libosmium works on Linux, Mac OSX and Windows.
-[](https://travis-ci.org/osmcode/libosmium)
-[](https://ci.appveyor.com/project/Mapbox/libosmium)
+[](https://travis-ci.org/osmcode/libosmium)
+[](https://ci.appveyor.com/project/Mapbox/libosmium)
+[](https://codecov.io/gh/osmcode/libosmium)
Please see the [Libosmium manual](http://osmcode.org/libosmium/manual.html)
for more details than this README can provide.
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index 43c7277..c4f875f 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -60,6 +60,10 @@ foreach(example ${EXAMPLES})
add_executable(osmium_${example} "osmium_${example}.cpp")
set_pthread_on_target(osmium_${example})
target_link_libraries(osmium_${example} ${OSMIUM_IO_LIBRARIES} ${EXAMPLE_LIBS_${example}})
+ add_test(NAME examples_usage_${example} COMMAND osmium_${example})
+ set_tests_properties(examples_usage_${example} PROPERTIES
+ PASS_REGULAR_EXPRESSION "^Usage: "
+ )
endforeach()
diff --git a/examples/osmium_amenity_list.cpp b/examples/osmium_amenity_list.cpp
index 502b44b..7e8d79a 100644
--- a/examples/osmium_amenity_list.cpp
+++ b/examples/osmium_amenity_list.cpp
@@ -9,7 +9,7 @@
DEMONSTRATES USE OF:
* file input
* location indexes and the NodeLocationsForWays handler
- * the MultipolygonCollector and Assembler to assemble areas (multipolygons)
+ * the MultipolygonManager and Assembler to assemble areas (multipolygons)
* your own handler that works with areas (multipolygons)
* accessing tags
* osmium::geom::Coordinates
@@ -29,17 +29,22 @@
#include <iostream> // for std::cerr
#include <string> // for std::string
-// For memory based sparse index
-#include <osmium/index/map/sparse_mem_array.hpp>
+// For the location index. There are different types of indexes available.
+// This will work for all input files keeping the index in memory.
+#include <osmium/index/map/flex_mem.hpp>
// For the NodeLocationForWays handler
#include <osmium/handler/node_locations_for_ways.hpp>
-using index_type = osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, osmium::Location>;
+
+// The type of index used. This must match the include file above
+using index_type = osmium::index::map::FlexMem<osmium::unsigned_object_id_type, osmium::Location>;
+
+// The location handler always depends on the index type
using location_handler_type = osmium::handler::NodeLocationsForWays<index_type>;
// For assembling multipolygons
#include <osmium/area/assembler.hpp>
-#include <osmium/area/multipolygon_collector.hpp>
+#include <osmium/area/multipolygon_manager.hpp>
// Allow any format of input files (XML, PBF, ...)
#include <osmium/io/any_input.hpp>
@@ -108,8 +113,8 @@ int main(int argc, char* argv[]) {
std::exit(1);
}
- // The input file name
- const std::string input_file_name{argv[1]};
+ // The input file
+ const osmium::io::File input_file{argv[1]};
// Configuration for the multipolygon assembler. We disable the option to
// create empty areas when invalid multipolygons are encountered. This
@@ -118,21 +123,16 @@ int main(int argc, char* argv[]) {
osmium::area::Assembler::config_type assembler_config;
assembler_config.create_empty_areas = false;
- // Initialize the MultipolygonCollector. Its job is to collect all
+ // Initialize the MultipolygonManager. Its job is to collect all
// relations and member ways needed for each area. It then calls an
// instance of the osmium::area::Assembler class (with the given config)
// to actually assemble one area.
- osmium::area::MultipolygonCollector<osmium::area::Assembler> collector{assembler_config};
+ osmium::area::MultipolygonManager<osmium::area::Assembler> mp_manager{assembler_config};
// We read the input file twice. In the first pass, only relations are
- // read and fed into the multipolygon collector. The read_meta::no option
- // disables reading of meta data (such as version numbers, timestamps, etc.)
- // which are not needed in this case. Disabling this can speed up your
- // program.
+ // read and fed into the multipolygon manager.
std::cerr << "Pass 1...\n";
- osmium::io::Reader reader1{input_file_name, osmium::osm_entity_bits::relation, osmium::io::read_meta::no};
- collector.read_relations(reader1);
- reader1.close();
+ osmium::relations::read_relations(input_file, mp_manager);
std::cerr << "Pass 1 done\n";
// The index storing all node locations.
@@ -151,17 +151,21 @@ int main(int argc, char* argv[]) {
AmenityHandler data_handler;
// On the second pass we read all objects and run them first through the
- // node location handler and then the multipolygon collector. The collector
+ // node location handler and then the multipolygon manager. The manager
// will put the areas it has created into the "buffer" which are then
// fed through our handler.
+ //
+ // The read_meta::no option disables reading of meta data (such as version
+ // numbers, timestamps, etc.) which are not needed in this case. Disabling
+ // this can speed up your program.
std::cerr << "Pass 2...\n";
- osmium::io::Reader reader2{input_file_name, osmium::io::read_meta::no};
+ osmium::io::Reader reader{input_file, osmium::io::read_meta::no};
- osmium::apply(reader2, location_handler, data_handler, collector.handler([&data_handler](const osmium::memory::Buffer& area_buffer) {
+ osmium::apply(reader, location_handler, data_handler, mp_manager.handler([&data_handler](const osmium::memory::Buffer& area_buffer) {
osmium::apply(area_buffer, data_handler);
}));
- reader2.close();
+ reader.close();
std::cerr << "Pass 2 done\n";
}
diff --git a/examples/osmium_area_test.cpp b/examples/osmium_area_test.cpp
index 4bfff72..948c032 100644
--- a/examples/osmium_area_test.cpp
+++ b/examples/osmium_area_test.cpp
@@ -8,7 +8,7 @@
DEMONSTRATES USE OF:
* file input
* location indexes and the NodeLocationsForWays handler
- * the MultipolygonCollector and Assembler to assemble areas (multipolygons)
+ * the MultipolygonManager and Assembler to assemble areas (multipolygons)
* your own handler that works with areas (multipolygons)
* the WKTFactory to write geometries in WKT format
* the Dump handler
@@ -31,7 +31,7 @@
// For assembling multipolygons
#include <osmium/area/assembler.hpp>
-#include <osmium/area/multipolygon_collector.hpp>
+#include <osmium/area/multipolygon_manager.hpp>
// For the DynamicHandler class
#include <osmium/dynamic_handler.hpp>
@@ -52,11 +52,11 @@
#include <osmium/visitor.hpp>
// For the location index. There are different types of indexes available.
-// This will work for small and medium sized input files.
-#include <osmium/index/map/sparse_mem_array.hpp>
+// This will work for all input files keeping the index in memory.
+#include <osmium/index/map/flex_mem.hpp>
// The type of index used. This must match the include file above
-using index_type = osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, osmium::Location>;
+using index_type = osmium::index::map::FlexMem<osmium::unsigned_object_id_type, osmium::Location>;
// The location handler always depends on the index type
using location_handler_type = osmium::handler::NodeLocationsForWays<index_type>;
@@ -93,10 +93,10 @@ void print_help() {
int main(int argc, char* argv[]) {
static struct option long_options[] = {
- {"help", no_argument, 0, 'h'},
- {"dump-wkt", no_argument, 0, 'w'},
- {"dump-objects", no_argument, 0, 'o'},
- {0, 0, 0, 0}
+ {"help", no_argument, nullptr, 'h'},
+ {"dump-wkt", no_argument, nullptr, 'w'},
+ {"dump-objects", no_argument, nullptr, 'o'},
+ {nullptr, 0, nullptr, 0}
};
// Initialize an empty DynamicHandler. Later it will be associated
@@ -107,7 +107,7 @@ int main(int argc, char* argv[]) {
// Read options from command line.
while (true) {
- const int c = getopt_long(argc, argv, "hwo", long_options, 0);
+ const int c = getopt_long(argc, argv, "hwo", long_options, nullptr);
if (c == -1) {
break;
}
@@ -139,24 +139,29 @@ int main(int argc, char* argv[]) {
// are used, but you could change multiple settings.
osmium::area::Assembler::config_type assembler_config;
- // Initialize the MultipolygonCollector. Its job is to collect all
+ // Set up a filter matching only forests. This will be used to only build
+ // areas with matching tags.
+ osmium::TagsFilter filter{false};
+ filter.add_rule(true, "landuse", "forest");
+ filter.add_rule(true, "natural", "wood");
+
+ // Initialize the MultipolygonManager. Its job is to collect all
// relations and member ways needed for each area. It then calls an
// instance of the osmium::area::Assembler class (with the given config)
- // to actually assemble one area.
- osmium::area::MultipolygonCollector<osmium::area::Assembler> collector{assembler_config};
+ // to actually assemble one area. The filter parameter is optional, if
+ // it is not set, all areas will be built.
+ osmium::area::MultipolygonManager<osmium::area::Assembler> mp_manager{assembler_config, filter};
// We read the input file twice. In the first pass, only relations are
- // read and fed into the multipolygon collector.
+ // read and fed into the multipolygon manager.
std::cerr << "Pass 1...\n";
- osmium::io::Reader reader1{input_file, osmium::osm_entity_bits::relation};
- collector.read_relations(reader1);
- reader1.close();
+ osmium::relations::read_relations(input_file, mp_manager);
std::cerr << "Pass 1 done\n";
// Output the amount of main memory used so far. All multipolygon relations
// are in memory now.
std::cerr << "Memory:\n";
- collector.used_memory();
+ osmium::relations::print_used_memory(std::cerr, mp_manager.used_memory());
// The index storing all node locations.
index_type index;
@@ -175,26 +180,29 @@ int main(int argc, char* argv[]) {
// will put the areas it has created into the "buffer" which are then
// fed through our "handler".
std::cerr << "Pass 2...\n";
- osmium::io::Reader reader2{input_file};
- osmium::apply(reader2, location_handler, collector.handler([&handler](osmium::memory::Buffer&& buffer) {
+ osmium::io::Reader reader{input_file};
+ osmium::apply(reader, location_handler, mp_manager.handler([&handler](osmium::memory::Buffer&& buffer) {
osmium::apply(buffer, handler);
}));
- reader2.close();
+ reader.close();
std::cerr << "Pass 2 done\n";
// Output the amount of main memory used so far. All complete multipolygon
// relations have been cleaned up.
std::cerr << "Memory:\n";
- collector.used_memory();
+ osmium::relations::print_used_memory(std::cerr, mp_manager.used_memory());
// If there were multipolgyon relations in the input, but some of their
// members are not in the input file (which often happens for extracts)
// this will write the IDs of the incomplete relations to stderr.
- std::vector<const osmium::Relation*> incomplete_relations = collector.get_incomplete_relations();
- if (!incomplete_relations.empty()) {
+ std::vector<osmium::object_id_type> incomplete_relations_ids;
+ mp_manager.for_each_incomplete_relation([&](const osmium::relations::RelationHandle& handle){
+ incomplete_relations_ids.push_back(handle->id());
+ });
+ if (!incomplete_relations_ids.empty()) {
std::cerr << "Warning! Some member ways missing for these multipolygon relations:";
- for (const auto* relation : incomplete_relations) {
- std::cerr << " " << relation->id();
+ for (const auto id : incomplete_relations_ids) {
+ std::cerr << " " << id;
}
std::cerr << "\n";
}
diff --git a/examples/osmium_change_tags.cpp b/examples/osmium_change_tags.cpp
index 216d730..ae2e99e 100644
--- a/examples/osmium_change_tags.cpp
+++ b/examples/osmium_change_tags.cpp
@@ -119,7 +119,7 @@ public:
m_buffer.commit();
}
- // The way handler is called for each node in the input data.
+ // The way handler is called for each way in the input data.
void way(const osmium::Way& way) {
{
osmium::builder::WayBuilder builder{m_buffer};
@@ -132,7 +132,7 @@ public:
m_buffer.commit();
}
- // The relation handler is called for each node in the input data.
+ // The relation handler is called for each relation in the input data.
void relation(const osmium::Relation& relation) {
{
osmium::builder::RelationBuilder builder{m_buffer};
diff --git a/examples/osmium_convert.cpp b/examples/osmium_convert.cpp
index 0ced82c..dfa0abd 100644
--- a/examples/osmium_convert.cpp
+++ b/examples/osmium_convert.cpp
@@ -53,10 +53,10 @@ void print_help() {
int main(int argc, char* argv[]) {
static struct option long_options[] = {
- {"help", no_argument, 0, 'h'},
- {"from-format", required_argument, 0, 'f'},
- {"to-format", required_argument, 0, 't'},
- {0, 0, 0, 0}
+ {"help", no_argument, nullptr, 'h'},
+ {"from-format", required_argument, nullptr, 'f'},
+ {"to-format", required_argument, nullptr, 't'},
+ {nullptr, 0, nullptr, 0}
};
// Input and output format are empty by default. Later this will mean that
@@ -67,7 +67,7 @@ int main(int argc, char* argv[]) {
// Read options from command line.
while (true) {
- const int c = getopt_long(argc, argv, "dhf:t:", long_options, 0);
+ const int c = getopt_long(argc, argv, "dhf:t:", long_options, nullptr);
if (c == -1) {
break;
}
@@ -88,7 +88,7 @@ int main(int argc, char* argv[]) {
}
const int remaining_args = argc - optind;
- if (remaining_args > 2) {
+ if (remaining_args == 0 || remaining_args > 2) {
std::cerr << "Usage: " << argv[0] << " [OPTIONS] [INFILE [OUTFILE]]\n";
std::exit(1);
}
@@ -108,8 +108,8 @@ int main(int argc, char* argv[]) {
// This declares the input and output files using either the suffix of
// the file names or the format in the 2nd argument. It does not yet open
// the files.
- osmium::io::File input_file{input_file_name, input_format};
- osmium::io::File output_file{output_file_name, output_format};
+ const osmium::io::File input_file{input_file_name, input_format};
+ const osmium::io::File output_file{output_file_name, output_format};
// Input and output files can be OSM data files (without history) or
// OSM history files. History files are detected if they use the '.osh'
diff --git a/examples/osmium_create_pois.cpp b/examples/osmium_create_pois.cpp
index ff79cbb..df27bfe 100644
--- a/examples/osmium_create_pois.cpp
+++ b/examples/osmium_create_pois.cpp
@@ -46,6 +46,10 @@ int main(int argc, char* argv[]) {
// Get output file name from command line.
std::string output_file_name{argv[1]};
+ // If output file name is "-", this means STDOUT. Set the OPL file type
+ // in this case. Otherwise take the file type from the file name suffix.
+ osmium::io::File output_file{output_file_name, output_file_name == "-" ? ".opl" : ""};
+
try {
// Create a buffer where all objects will live. Use a sensible initial
// buffer size and set the buffer to automatically grow if needed.
@@ -78,7 +82,7 @@ int main(int argc, char* argv[]) {
// Initialize Writer using the header from above and tell it that it
// is allowed to overwrite a possibly existing file.
- osmium::io::Writer writer{output_file_name, header, osmium::io::overwrite::allow};
+ osmium::io::Writer writer{output_file, header, osmium::io::overwrite::allow};
// Write out the contents of the output buffer.
writer(std::move(buffer));
diff --git a/examples/osmium_debug.cpp b/examples/osmium_debug.cpp
index 8133491..ed68596 100644
--- a/examples/osmium_debug.cpp
+++ b/examples/osmium_debug.cpp
@@ -44,10 +44,18 @@ int main(int argc, char* argv[]) {
if (argc == 3) {
read_types = osmium::osm_entity_bits::nothing;
std::string types = argv[2];
- if (types.find('n') != std::string::npos) read_types |= osmium::osm_entity_bits::node;
- if (types.find('w') != std::string::npos) read_types |= osmium::osm_entity_bits::way;
- if (types.find('r') != std::string::npos) read_types |= osmium::osm_entity_bits::relation;
- if (types.find('c') != std::string::npos) read_types |= osmium::osm_entity_bits::changeset;
+ if (types.find('n') != std::string::npos) {
+ read_types |= osmium::osm_entity_bits::node;
+ }
+ if (types.find('w') != std::string::npos) {
+ read_types |= osmium::osm_entity_bits::way;
+ }
+ if (types.find('r') != std::string::npos) {
+ read_types |= osmium::osm_entity_bits::relation;
+ }
+ if (types.find('c') != std::string::npos) {
+ read_types |= osmium::osm_entity_bits::changeset;
+ }
}
// Initialize Reader with file name and the types of entities we want to
diff --git a/examples/osmium_dump_internal.cpp b/examples/osmium_dump_internal.cpp
index e1656ef..58f49b3 100644
--- a/examples/osmium_dump_internal.cpp
+++ b/examples/osmium_dump_internal.cpp
@@ -6,7 +6,7 @@
indexes to find objects and object relations.
Note that this example programm will only work with small and medium sized
- OSM file, not with the planet.
+ OSM files, not with the planet.
You can use the osmium_index example program to inspect the indexes.
diff --git a/examples/osmium_index_lookup.cpp b/examples/osmium_index_lookup.cpp
index c7f2bb4..4449e70 100644
--- a/examples/osmium_index_lookup.cpp
+++ b/examples/osmium_index_lookup.cpp
@@ -192,17 +192,17 @@ public:
}
static struct option long_options[] = {
- {"array", required_argument, 0, 'a'},
- {"dump", no_argument, 0, 'd'},
- {"help", no_argument, 0, 'h'},
- {"list", required_argument, 0, 'l'},
- {"search", required_argument, 0, 's'},
- {"type", required_argument, 0, 't'},
- {0, 0, 0, 0}
+ {"array", required_argument, nullptr, 'a'},
+ {"dump", no_argument, nullptr, 'd'},
+ {"help", no_argument, nullptr, 'h'},
+ {"list", required_argument, nullptr, 'l'},
+ {"search", required_argument, nullptr, 's'},
+ {"type", required_argument, nullptr, 't'},
+ {nullptr, 0, nullptr, 0}
};
while (true) {
- const int c = getopt_long(argc, argv, "a:dhl:s:t:", long_options, 0);
+ const int c = getopt_long(argc, argv, "a:dhl:s:t:", long_options, nullptr);
if (c == -1) {
break;
}
diff --git a/examples/osmium_location_cache_create.cpp b/examples/osmium_location_cache_create.cpp
index 9de41d1..c01dd97 100644
--- a/examples/osmium_location_cache_create.cpp
+++ b/examples/osmium_location_cache_create.cpp
@@ -68,7 +68,7 @@ int main(int argc, char* argv[]) {
osmium::io::Reader reader{input_filename, osmium::osm_entity_bits::node};
// Initialize location index on disk creating a new file.
- const int fd = open(cache_filename.c_str(), O_RDWR | O_CREAT, 0666);
+ const int fd = open(cache_filename.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0666);
if (fd == -1) {
std::cerr << "Can not open location cache file '" << cache_filename << "': " << std::strerror(errno) << "\n";
std::exit(1);
diff --git a/examples/osmium_road_length.cpp b/examples/osmium_road_length.cpp
index 2e1be90..4aced95 100644
--- a/examples/osmium_road_length.cpp
+++ b/examples/osmium_road_length.cpp
@@ -33,14 +33,14 @@
#include <osmium/visitor.hpp>
// For the location index. There are different types of indexes available.
-// This will work for small and medium sized input files.
-#include <osmium/index/map/sparse_mem_array.hpp>
+// This will work for all input files keeping the index in memory.
+#include <osmium/index/map/flex_mem.hpp>
// For the NodeLocationForWays handler
#include <osmium/handler/node_locations_for_ways.hpp>
// The type of index used. This must match the include file above
-using index_type = osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, osmium::Location>;
+using index_type = osmium::index::map::FlexMem<osmium::unsigned_object_id_type, osmium::Location>;
// The location handler always depends on the index type
using location_handler_type = osmium::handler::NodeLocationsForWays<index_type>;
diff --git a/include/osmium/area/assembler.hpp b/include/osmium/area/assembler.hpp
index 9e8541a..461a183 100644
--- a/include/osmium/area/assembler.hpp
+++ b/include/osmium/area/assembler.hpp
@@ -33,32 +33,22 @@ DEALINGS IN THE SOFTWARE.
*/
-#include <algorithm>
#include <cassert>
-#include <cstdint>
-#include <cstdlib>
-#include <cstring>
-#include <functional>
#include <iostream>
-#include <iterator>
-#include <set>
-#include <string>
-#include <map>
-#include <utility>
#include <vector>
-#include <osmium/area/detail/basic_assembler.hpp>
+#include <osmium/area/assembler_config.hpp>
+#include <osmium/area/detail/basic_assembler_with_tags.hpp>
+#include <osmium/area/detail/segment_list.hpp>
+#include <osmium/area/problem_reporter.hpp>
+#include <osmium/area/stats.hpp>
#include <osmium/builder/osm_object_builder.hpp>
#include <osmium/memory/buffer.hpp>
-#include <osmium/osm/area.hpp>
#include <osmium/osm/item_type.hpp>
-#include <osmium/osm/location.hpp>
+#include <osmium/osm/node_ref.hpp>
#include <osmium/osm/relation.hpp>
#include <osmium/osm/tag.hpp>
-#include <osmium/osm/types.hpp>
#include <osmium/osm/way.hpp>
-#include <osmium/tags/filter.hpp>
-#include <osmium/util/compatibility.hpp>
namespace osmium {
@@ -68,118 +58,7 @@ namespace osmium {
* Assembles area objects from closed ways or multipolygon relations
* and their members.
*/
- class Assembler : public detail::BasicAssembler {
-
- bool report_ways() const noexcept {
- if (!config().problem_reporter) {
- return false;
- }
- return stats().duplicate_nodes ||
- stats().duplicate_segments ||
- stats().intersections ||
- stats().open_rings ||
- stats().short_ways ||
- stats().touching_rings ||
- stats().ways_in_multiple_rings ||
- stats().wrong_role;
- }
-
- void add_tags_to_area(osmium::builder::AreaBuilder& builder, const osmium::Way& way) const {
- builder.add_item(way.tags());
- }
-
- void add_common_tags(osmium::builder::TagListBuilder& tl_builder, std::set<const osmium::Way*>& ways) const {
- std::map<std::string, size_t> counter;
- for (const osmium::Way* way : ways) {
- for (const auto& tag : way->tags()) {
- std::string kv{tag.key()};
- kv.append(1, '\0');
- kv.append(tag.value());
- ++counter[kv];
- }
- }
-
- const size_t num_ways = ways.size();
- for (const auto& t_c : counter) {
- if (debug()) {
- std::cerr << " tag " << t_c.first << " is used " << t_c.second << " times in " << num_ways << " ways\n";
- }
- if (t_c.second == num_ways) {
- const size_t len = std::strlen(t_c.first.c_str());
- tl_builder.add_tag(t_c.first.c_str(), t_c.first.c_str() + len + 1);
- }
- }
- }
-
- struct MPFilter : public osmium::tags::KeyFilter {
-
- MPFilter() : osmium::tags::KeyFilter(true) {
- add(false, "type");
- add(false, "created_by");
- add(false, "source");
- add(false, "note");
- add(false, "test:id");
- add(false, "test:section");
- }
-
- }; // struct MPFilter
-
- static const MPFilter& filter() noexcept {
- static const MPFilter filter;
- return filter;
- }
-
- static void copy_tags_without_type(osmium::builder::AreaBuilder& builder, const osmium::TagList& tags) {
- osmium::builder::TagListBuilder tl_builder{builder};
- for (const osmium::Tag& tag : tags) {
- if (std::strcmp(tag.key(), "type")) {
- tl_builder.add_tag(tag.key(), tag.value());
- }
- }
- }
-
- void add_tags_to_area(osmium::builder::AreaBuilder& builder, const osmium::Relation& relation) {
- const auto count = std::count_if(relation.tags().cbegin(), relation.tags().cend(), std::cref(filter()));
-
- if (debug()) {
- std::cerr << " found " << count << " tags on relation (without ignored ones)\n";
- }
-
- if (count > 0) {
- if (debug()) {
- std::cerr << " use tags from relation\n";
- }
-
- if (config().keep_type_tag) {
- builder.add_item(relation.tags());
- } else {
- copy_tags_without_type(builder, relation.tags());
- }
- } else {
- ++stats().no_tags_on_relation;
- if (debug()) {
- std::cerr << " use tags from outer ways\n";
- }
- std::set<const osmium::Way*> ways;
- for (const auto& ring : rings()) {
- if (ring.is_outer()) {
- ring.get_ways(ways);
- }
- }
- if (ways.size() == 1) {
- if (debug()) {
- std::cerr << " only one outer way\n";
- }
- builder.add_item((*ways.cbegin())->tags());
- } else {
- if (debug()) {
- std::cerr << " multiple outer ways, get common tags\n";
- }
- osmium::builder::TagListBuilder tl_builder{builder};
- add_common_tags(tl_builder, ways);
- }
- }
- }
+ class Assembler : public detail::BasicAssemblerWithTags {
bool create_area(osmium::memory::Buffer& out_buffer, const osmium::Way& way) {
osmium::builder::AreaBuilder builder{out_buffer};
@@ -187,7 +66,7 @@ namespace osmium {
const bool area_okay = create_rings();
if (area_okay || config().create_empty_areas) {
- add_tags_to_area(builder, way);
+ builder.add_item(way.tags());
}
if (area_okay) {
add_rings_to_area(builder);
@@ -207,7 +86,11 @@ namespace osmium {
const bool area_okay = create_rings();
if (area_okay || config().create_empty_areas) {
- add_tags_to_area(builder, relation);
+ if (config().keep_type_tag) {
+ builder.add_item(relation.tags());
+ } else {
+ copy_tags_without_type(builder, relation.tags());
+ }
}
if (area_okay) {
add_rings_to_area(builder);
@@ -224,10 +107,8 @@ namespace osmium {
public:
- using config_type = osmium::area::AssemblerConfig;
-
explicit Assembler(const config_type& config) :
- detail::BasicAssembler(config) {
+ detail::BasicAssemblerWithTags(config) {
}
~Assembler() noexcept = default;
@@ -244,10 +125,6 @@ namespace osmium {
return true;
}
- if (way.tags().has_tag("area", "no")) {
- return true;
- }
-
if (config().problem_reporter) {
config().problem_reporter->set_object(osmium::item_type::way, way.id());
config().problem_reporter->set_nodes(way.nodes().size());
@@ -296,32 +173,17 @@ namespace osmium {
/**
* Assemble an area from the given relation and its members.
- * All members are to be found in the in_buffer at the offsets
- * given by the members parameter.
- * The resulting area is put into the out_buffer.
- *
- * @deprecated
- * This function is deprecated. Use the other form of the function
- * instead.
- */
- OSMIUM_DEPRECATED void operator()(const osmium::Relation& relation, const std::vector<size_t>& members, const osmium::memory::Buffer& in_buffer, osmium::memory::Buffer& out_buffer) {
- std::vector<const osmium::Way*> ways;
- for (size_t offset : members) {
- const osmium::Way& way = in_buffer.get<const osmium::Way>(offset);
- ways.push_back(&way);
- }
- operator()(relation, ways, out_buffer);
- }
-
- /**
- * Assemble an area from the given relation and its members.
* The resulting area is put into the out_buffer.
*
* @returns false if there was some kind of error building the
* area(s), true otherwise.
*/
bool operator()(const osmium::Relation& relation, const std::vector<const osmium::Way*>& members, osmium::memory::Buffer& out_buffer) {
- assert(relation.members().size() >= members.size());
+ if (!config().create_new_style_polygons) {
+ return true;
+ }
+
+ assert(relation.cmembers().size() >= members.size());
if (config().problem_reporter) {
config().problem_reporter->set_object(osmium::item_type::relation, relation.id());
@@ -351,67 +213,15 @@ namespace osmium {
std::cerr << "\nAssembling relation " << relation.id() << " containing " << members.size() << " way members with " << segment_list().size() << " nodes\n";
}
- const size_t area_offset = out_buffer.committed();
-
// Now create the Area object and add the attributes and tags
// from the relation.
bool okay = create_area(out_buffer, relation, members);
if (okay) {
- if ((config().create_new_style_polygons && stats().no_tags_on_relation == 0) ||
- (config().create_old_style_polygons && stats().no_tags_on_relation != 0)) {
- out_buffer.commit();
- } else {
- out_buffer.rollback();
- }
+ out_buffer.commit();
} else {
out_buffer.rollback();
}
- const osmium::TagList& area_tags = out_buffer.get<osmium::Area>(area_offset).tags(); // tags of the area we just built
-
- // Find all closed ways that are inner rings and check their
- // tags. If they are not the same as the tags of the area we
- // just built, add them to a list and later build areas for
- // them, too.
- std::vector<const osmium::Way*> ways_that_should_be_areas;
- if (stats().wrong_role == 0) {
- detail::for_each_member(relation, members, [this, &ways_that_should_be_areas, &area_tags](const osmium::RelationMember& member, const osmium::Way& way) {
- if (!std::strcmp(member.role(), "inner")) {
- if (!way.nodes().empty() && way.is_closed() && way.tags().size() > 0) {
- const auto d = std::count_if(way.tags().cbegin(), way.tags().cend(), std::cref(filter()));
- if (d > 0) {
- osmium::tags::KeyFilter::iterator way_fi_begin(std::cref(filter()), way.tags().cbegin(), way.tags().cend());
- osmium::tags::KeyFilter::iterator way_fi_end(std::cref(filter()), way.tags().cend(), way.tags().cend());
- osmium::tags::KeyFilter::iterator area_fi_begin(std::cref(filter()), area_tags.cbegin(), area_tags.cend());
- osmium::tags::KeyFilter::iterator area_fi_end(std::cref(filter()), area_tags.cend(), area_tags.cend());
-
- if (!std::equal(way_fi_begin, way_fi_end, area_fi_begin) || d != std::distance(area_fi_begin, area_fi_end)) {
- ways_that_should_be_areas.push_back(&way);
- } else {
- ++stats().inner_with_same_tags;
- if (config().problem_reporter) {
- config().problem_reporter->report_inner_with_same_tags(way);
- }
- }
- }
- }
- }
- });
- }
-
- if (debug()) {
- std::cerr << "Done: " << stats() << "\n";
- }
-
- // Now build areas for all ways found in the last step.
- for (const osmium::Way* way : ways_that_should_be_areas) {
- Assembler assembler{config()};
- if (!assembler(*way, out_buffer)) {
- okay = false;
- }
- stats() += assembler.stats();
- }
-
return okay;
}
diff --git a/include/osmium/area/assembler_config.hpp b/include/osmium/area/assembler_config.hpp
index 2e49080..24bd60a 100644
--- a/include/osmium/area/assembler_config.hpp
+++ b/include/osmium/area/assembler_config.hpp
@@ -51,7 +51,7 @@ namespace osmium {
/**
* Optional pointer to problem reporter.
*/
- osmium::area::ProblemReporter* problem_reporter = nullptr;
+ ProblemReporter* problem_reporter = nullptr;
/**
* Debug level. If this is greater than zero, debug messages will
@@ -90,7 +90,9 @@ namespace osmium {
/**
* Create areas for (multi)polygons where the tags are on the
- * outer way(s).
+ * outer way(s). This is ignored by the area::Assembler which
+ * doesn't support old-style multipolygons any more. Use the
+ * area::AssemblerLegacy if you need this.
*
* If this is set to false, those areas will simply be discarded.
*/
@@ -128,7 +130,7 @@ namespace osmium {
* Constructor
* @deprecated Use default constructor and set values afterwards.
*/
- explicit AssemblerConfig(osmium::area::ProblemReporter* pr, bool d = false) :
+ explicit AssemblerConfig(ProblemReporter* pr, bool d = false) :
problem_reporter(pr),
debug_level(d) {
}
diff --git a/include/osmium/area/assembler.hpp b/include/osmium/area/assembler_legacy.hpp
similarity index 84%
copy from include/osmium/area/assembler.hpp
copy to include/osmium/area/assembler_legacy.hpp
index 9e8541a..e616c94 100644
--- a/include/osmium/area/assembler.hpp
+++ b/include/osmium/area/assembler_legacy.hpp
@@ -1,5 +1,5 @@
-#ifndef OSMIUM_AREA_ASSEMBLER_HPP
-#define OSMIUM_AREA_ASSEMBLER_HPP
+#ifndef OSMIUM_AREA_ASSEMBLER_LEGACY_HPP
+#define OSMIUM_AREA_ASSEMBLER_LEGACY_HPP
/*
@@ -35,8 +35,6 @@ DEALINGS IN THE SOFTWARE.
#include <algorithm>
#include <cassert>
-#include <cstdint>
-#include <cstdlib>
#include <cstring>
#include <functional>
#include <iostream>
@@ -47,18 +45,22 @@ DEALINGS IN THE SOFTWARE.
#include <utility>
#include <vector>
-#include <osmium/area/detail/basic_assembler.hpp>
+#include <osmium/area/assembler_config.hpp>
+#include <osmium/area/detail/basic_assembler_with_tags.hpp>
+#include <osmium/area/detail/proto_ring.hpp>
+#include <osmium/area/detail/segment_list.hpp>
+#include <osmium/area/problem_reporter.hpp>
+#include <osmium/area/stats.hpp>
#include <osmium/builder/osm_object_builder.hpp>
#include <osmium/memory/buffer.hpp>
+#include <osmium/memory/collection.hpp>
#include <osmium/osm/area.hpp>
#include <osmium/osm/item_type.hpp>
-#include <osmium/osm/location.hpp>
+#include <osmium/osm/node_ref.hpp>
#include <osmium/osm/relation.hpp>
#include <osmium/osm/tag.hpp>
-#include <osmium/osm/types.hpp>
#include <osmium/osm/way.hpp>
#include <osmium/tags/filter.hpp>
-#include <osmium/util/compatibility.hpp>
namespace osmium {
@@ -68,28 +70,14 @@ namespace osmium {
* Assembles area objects from closed ways or multipolygon relations
* and their members.
*/
- class Assembler : public detail::BasicAssembler {
-
- bool report_ways() const noexcept {
- if (!config().problem_reporter) {
- return false;
- }
- return stats().duplicate_nodes ||
- stats().duplicate_segments ||
- stats().intersections ||
- stats().open_rings ||
- stats().short_ways ||
- stats().touching_rings ||
- stats().ways_in_multiple_rings ||
- stats().wrong_role;
- }
+ class AssemblerLegacy : public detail::BasicAssemblerWithTags {
void add_tags_to_area(osmium::builder::AreaBuilder& builder, const osmium::Way& way) const {
builder.add_item(way.tags());
}
void add_common_tags(osmium::builder::TagListBuilder& tl_builder, std::set<const osmium::Way*>& ways) const {
- std::map<std::string, size_t> counter;
+ std::map<std::string, std::size_t> counter;
for (const osmium::Way* way : ways) {
for (const auto& tag : way->tags()) {
std::string kv{tag.key()};
@@ -99,13 +87,13 @@ namespace osmium {
}
}
- const size_t num_ways = ways.size();
+ const std::size_t num_ways = ways.size();
for (const auto& t_c : counter) {
if (debug()) {
std::cerr << " tag " << t_c.first << " is used " << t_c.second << " times in " << num_ways << " ways\n";
}
if (t_c.second == num_ways) {
- const size_t len = std::strlen(t_c.first.c_str());
+ const std::size_t len = std::strlen(t_c.first.c_str());
tl_builder.add_tag(t_c.first.c_str(), t_c.first.c_str() + len + 1);
}
}
@@ -129,15 +117,6 @@ namespace osmium {
return filter;
}
- static void copy_tags_without_type(osmium::builder::AreaBuilder& builder, const osmium::TagList& tags) {
- osmium::builder::TagListBuilder tl_builder{builder};
- for (const osmium::Tag& tag : tags) {
- if (std::strcmp(tag.key(), "type")) {
- tl_builder.add_tag(tag.key(), tag.value());
- }
- }
- }
-
void add_tags_to_area(osmium::builder::AreaBuilder& builder, const osmium::Relation& relation) {
const auto count = std::count_if(relation.tags().cbegin(), relation.tags().cend(), std::cref(filter()));
@@ -224,13 +203,11 @@ namespace osmium {
public:
- using config_type = osmium::area::AssemblerConfig;
-
- explicit Assembler(const config_type& config) :
- detail::BasicAssembler(config) {
+ explicit AssemblerLegacy(const config_type& config) :
+ detail::BasicAssemblerWithTags(config) {
}
- ~Assembler() noexcept = default;
+ ~AssemblerLegacy() noexcept = default;
/**
* Assemble an area from the given way.
@@ -296,25 +273,6 @@ namespace osmium {
/**
* Assemble an area from the given relation and its members.
- * All members are to be found in the in_buffer at the offsets
- * given by the members parameter.
- * The resulting area is put into the out_buffer.
- *
- * @deprecated
- * This function is deprecated. Use the other form of the function
- * instead.
- */
- OSMIUM_DEPRECATED void operator()(const osmium::Relation& relation, const std::vector<size_t>& members, const osmium::memory::Buffer& in_buffer, osmium::memory::Buffer& out_buffer) {
- std::vector<const osmium::Way*> ways;
- for (size_t offset : members) {
- const osmium::Way& way = in_buffer.get<const osmium::Way>(offset);
- ways.push_back(&way);
- }
- operator()(relation, ways, out_buffer);
- }
-
- /**
- * Assemble an area from the given relation and its members.
* The resulting area is put into the out_buffer.
*
* @returns false if there was some kind of error building the
@@ -351,7 +309,7 @@ namespace osmium {
std::cerr << "\nAssembling relation " << relation.id() << " containing " << members.size() << " way members with " << segment_list().size() << " nodes\n";
}
- const size_t area_offset = out_buffer.committed();
+ const std::size_t area_offset = out_buffer.committed();
// Now create the Area object and add the attributes and tags
// from the relation.
@@ -405,7 +363,7 @@ namespace osmium {
// Now build areas for all ways found in the last step.
for (const osmium::Way* way : ways_that_should_be_areas) {
- Assembler assembler{config()};
+ AssemblerLegacy assembler{config()};
if (!assembler(*way, out_buffer)) {
okay = false;
}
@@ -415,10 +373,10 @@ namespace osmium {
return okay;
}
- }; // class Assembler
+ }; // class AssemblerLegacy
} // namespace area
} // namespace osmium
-#endif // OSMIUM_AREA_ASSEMBLER_HPP
+#endif // OSMIUM_AREA_ASSEMBLER_LEGACY_HPP
diff --git a/include/osmium/area/detail/basic_assembler.hpp b/include/osmium/area/detail/basic_assembler.hpp
index 1337611..94168a1 100644
--- a/include/osmium/area/detail/basic_assembler.hpp
+++ b/include/osmium/area/detail/basic_assembler.hpp
@@ -37,7 +37,6 @@ DEALINGS IN THE SOFTWARE.
#include <cassert>
#include <cstdint>
#include <cstdlib>
-#include <cstring>
#include <iostream>
#include <iterator>
#include <list>
@@ -47,12 +46,8 @@ DEALINGS IN THE SOFTWARE.
#include <vector>
#include <osmium/builder/osm_object_builder.hpp>
-#include <osmium/memory/buffer.hpp>
-#include <osmium/osm/area.hpp>
-#include <osmium/osm/item_type.hpp>
#include <osmium/osm/location.hpp>
#include <osmium/osm/node_ref.hpp>
-#include <osmium/osm/relation.hpp>
#include <osmium/osm/types.hpp>
#include <osmium/osm/way.hpp>
#include <osmium/util/iterator.hpp>
@@ -71,7 +66,7 @@ namespace osmium {
namespace detail {
- using open_ring_its_type = std::list<std::list<detail::ProtoRing>::iterator>;
+ using open_ring_its_type = std::list<std::list<ProtoRing>::iterator>;
struct location_to_ring_map {
osmium::Location location;
@@ -90,7 +85,7 @@ namespace osmium {
start(false) {
}
- const detail::ProtoRing& ring() const noexcept {
+ const ProtoRing& ring() const noexcept {
return **ring_it;
}
@@ -128,17 +123,17 @@ namespace osmium {
reverse(r) {
}
- osmium::Location location(const detail::SegmentList& segment_list) const noexcept {
+ osmium::Location location(const SegmentList& segment_list) const noexcept {
const auto& segment = segment_list[item];
return reverse ? segment.second().location() : segment.first().location();
}
- const osmium::NodeRef& node_ref(const detail::SegmentList& segment_list) const noexcept {
+ const osmium::NodeRef& node_ref(const SegmentList& segment_list) const noexcept {
const auto& segment = segment_list[item];
return reverse ? segment.second() : segment.first();
}
- osmium::Location location(const detail::SegmentList& segment_list, const osmium::Location& default_location) const noexcept {
+ osmium::Location location(const SegmentList& segment_list, const osmium::Location& default_location) const noexcept {
if (item == invalid_item) {
return default_location;
}
@@ -151,10 +146,10 @@ namespace osmium {
const AssemblerConfig& m_config;
// List of segments (connection between two nodes)
- osmium::area::detail::SegmentList m_segment_list;
+ SegmentList m_segment_list;
// The rings we are building from the segments
- std::list<detail::ProtoRing> m_rings;
+ std::list<ProtoRing> m_rings;
// All node locations
std::vector<slocation> m_locations;
@@ -166,10 +161,10 @@ namespace osmium {
area_stats m_stats;
// The number of members the multipolygon relation has
- size_t m_num_members = 0;
+ std::size_t m_num_members = 0;
template <typename TBuilder>
- static void build_ring_from_proto_ring(osmium::builder::AreaBuilder& builder, const detail::ProtoRing& ring) {
+ static void build_ring_from_proto_ring(osmium::builder::AreaBuilder& builder, const ProtoRing& ring) {
TBuilder ring_builder{builder};
ring_builder.add_node_ref(ring.get_node_ref_start());
for (const auto& segment : ring.segments()) {
@@ -182,10 +177,10 @@ namespace osmium {
std::cerr << " Checking inner/outer roles\n";
}
- std::unordered_map<const osmium::Way*, const detail::ProtoRing*> way_rings;
+ std::unordered_map<const osmium::Way*, const ProtoRing*> way_rings;
std::unordered_set<const osmium::Way*> ways_in_multiple_rings;
- for (const detail::ProtoRing& ring : m_rings) {
+ for (const ProtoRing& ring : m_rings) {
for (const auto& segment : ring.segments()) {
assert(segment->way());
@@ -226,7 +221,7 @@ namespace osmium {
}
- detail::NodeRefSegment* get_next_segment(const osmium::Location& location) {
+ NodeRefSegment* get_next_segment(const osmium::Location& location) {
auto it = std::lower_bound(m_locations.begin(), m_locations.end(), slocation{}, [this, &location](const slocation& lhs, const slocation& rhs) {
return lhs.location(m_segment_list, location) < rhs.location(m_segment_list, location);
});
@@ -244,11 +239,11 @@ namespace osmium {
class rings_stack_element {
double m_y;
- detail::ProtoRing* m_ring_ptr;
+ ProtoRing* m_ring_ptr;
public:
- rings_stack_element(double y, detail::ProtoRing* ring_ptr) :
+ rings_stack_element(double y, ProtoRing* ring_ptr) :
m_y(y),
m_ring_ptr(ring_ptr) {
}
@@ -257,11 +252,11 @@ namespace osmium {
return m_y;
}
- const detail::ProtoRing& ring() const noexcept {
+ const ProtoRing& ring() const noexcept {
return *m_ring_ptr;
}
- detail::ProtoRing* ring_ptr() noexcept {
+ ProtoRing* ring_ptr() noexcept {
return m_ring_ptr;
}
@@ -273,7 +268,7 @@ namespace osmium {
return m_y < rhs.m_y;
}
- }; // class ring_stack_element
+ }; // class rings_stack_element
using rings_stack = std::vector<rings_stack_element>;
@@ -287,7 +282,7 @@ namespace osmium {
}
}
- detail::ProtoRing* find_enclosing_ring(detail::NodeRefSegment* segment) {
+ ProtoRing* find_enclosing_ring(NodeRefSegment* segment) {
if (debug()) {
std::cerr << " Looking for ring enclosing " << *segment << "\n";
}
@@ -374,30 +369,30 @@ namespace osmium {
std::cerr << " Decided that this is an outer ring\n";
}
return nullptr;
- } else {
- if (debug()) {
- std::cerr << " Decided that this is an inner ring\n";
- }
- assert(!outer_rings.empty());
+ }
- std::sort(outer_rings.rbegin(), outer_rings.rend());
- if (debug()) {
- for (const auto& o : outer_rings) {
- std::cerr << " y=" << o.y() << " " << o.ring() << "\n";
- }
- }
+ if (debug()) {
+ std::cerr << " Decided that this is an inner ring\n";
+ }
+ assert(!outer_rings.empty());
- remove_duplicates(outer_rings);
- if (debug()) {
- std::cerr << " after remove duplicates:\n";
- for (const auto& o : outer_rings) {
- std::cerr << " y=" << o.y() << " " << o.ring() << "\n";
- }
+ std::sort(outer_rings.rbegin(), outer_rings.rend());
+ if (debug()) {
+ for (const auto& o : outer_rings) {
+ std::cerr << " y=" << o.y() << " " << o.ring() << "\n";
}
+ }
- assert(!outer_rings.empty());
- return outer_rings.front().ring_ptr();
+ remove_duplicates(outer_rings);
+ if (debug()) {
+ std::cerr << " after remove duplicates:\n";
+ for (const auto& o : outer_rings) {
+ std::cerr << " y=" << o.y() << " " << o.ring() << "\n";
+ }
}
+
+ assert(!outer_rings.empty());
+ return outer_rings.front().ring_ptr();
}
bool is_split_location(const osmium::Location& location) const noexcept {
@@ -405,7 +400,7 @@ namespace osmium {
}
uint32_t add_new_ring(slocation& node) {
- detail::NodeRefSegment* segment = &m_segment_list[node.item];
+ NodeRefSegment* segment = &m_segment_list[node.item];
assert(!segment->is_done());
if (debug()) {
@@ -416,7 +411,7 @@ namespace osmium {
segment->reverse();
}
- detail::ProtoRing* outer_ring = nullptr;
+ ProtoRing* outer_ring = nullptr;
if (segment != &m_segment_list.front()) {
outer_ring = find_enclosing_ring(segment);
@@ -424,7 +419,7 @@ namespace osmium {
segment->mark_direction_done();
m_rings.emplace_back(segment);
- detail::ProtoRing* ring = &m_rings.back();
+ ProtoRing* ring = &m_rings.back();
if (outer_ring) {
if (debug()) {
std::cerr << " This is an inner ring. Outer ring is " << *outer_ring << "\n";
@@ -441,7 +436,7 @@ namespace osmium {
uint32_t nodes = 1;
while (first_location != last_location) {
++nodes;
- detail::NodeRefSegment* next_segment = get_next_segment(last_location);
+ NodeRefSegment* next_segment = get_next_segment(last_location);
next_segment->mark_direction_done();
if (next_segment->start().location() != last_location) {
next_segment->reverse();
@@ -463,7 +458,7 @@ namespace osmium {
}
uint32_t add_new_ring_complex(slocation& node) {
- detail::NodeRefSegment* segment = &m_segment_list[node.item];
+ NodeRefSegment* segment = &m_segment_list[node.item];
assert(!segment->is_done());
if (debug()) {
@@ -475,7 +470,7 @@ namespace osmium {
}
m_rings.emplace_back(segment);
- detail::ProtoRing* ring = &m_rings.back();
+ ProtoRing* ring = &m_rings.back();
const osmium::Location& first_location = node.location(m_segment_list);
osmium::Location last_location = segment->stop().location();
@@ -483,7 +478,7 @@ namespace osmium {
uint32_t nodes = 1;
while (first_location != last_location && !is_split_location(last_location)) {
++nodes;
- detail::NodeRefSegment* next_segment = get_next_segment(last_location);
+ NodeRefSegment* next_segment = get_next_segment(last_location);
if (next_segment->start().location() != last_location) {
next_segment->reverse();
}
@@ -518,8 +513,8 @@ namespace osmium {
});
}
- void find_inner_outer_complex(detail::ProtoRing* ring) {
- detail::ProtoRing* outer_ring = find_enclosing_ring(ring->min_segment());
+ void find_inner_outer_complex(ProtoRing* ring) {
+ ProtoRing* outer_ring = find_enclosing_ring(ring->min_segment());
if (outer_ring) {
outer_ring->add_inner_ring(ring);
ring->set_outer_ring(outer_ring);
@@ -532,7 +527,7 @@ namespace osmium {
if (debug()) {
std::cerr << " Finding inner/outer rings\n";
}
- std::vector<detail::ProtoRing*> rings;
+ std::vector<ProtoRing*> rings;
rings.reserve(m_rings.size());
for (auto& ring : m_rings) {
if (ring.closed()) {
@@ -544,7 +539,7 @@ namespace osmium {
return;
}
- std::sort(rings.begin(), rings.end(), [](detail::ProtoRing* a, detail::ProtoRing* b) {
+ std::sort(rings.begin(), rings.end(), [](ProtoRing* a, ProtoRing* b) {
return a->min_segment() < b->min_segment();
});
@@ -600,7 +595,7 @@ namespace osmium {
void create_rings_simple_case() {
auto count_remaining = m_segment_list.size();
for (slocation& sl : m_locations) {
- const detail::NodeRefSegment& segment = m_segment_list[sl.item];
+ const NodeRefSegment& segment = m_segment_list[sl.item];
if (!segment.is_done()) {
count_remaining -= add_new_ring(sl);
if (count_remaining == 0) {
@@ -628,8 +623,8 @@ namespace osmium {
}
void merge_two_rings(open_ring_its_type& open_ring_its, const location_to_ring_map& m1, const location_to_ring_map& m2) {
- std::list<detail::ProtoRing>::iterator r1 = *m1.ring_it;
- std::list<detail::ProtoRing>::iterator r2 = *m2.ring_it;
+ std::list<ProtoRing>::iterator r1 = *m1.ring_it;
+ std::list<ProtoRing>::iterator r2 = *m2.ring_it;
if (r1->get_node_ref_stop().location() == r2->get_node_ref_start().location()) {
r1->join_forward(*r2);
@@ -687,7 +682,7 @@ namespace osmium {
}
bool there_are_open_rings() const noexcept {
- return std::any_of(m_rings.cbegin(), m_rings.cend(), [](const detail::ProtoRing& ring){
+ return std::any_of(m_rings.cbegin(), m_rings.cend(), [](const ProtoRing& ring){
return !ring.closed();
});
}
@@ -727,9 +722,9 @@ namespace osmium {
assert(connections.begin() != connections.end());
assert(!cand.rings.empty());
- const detail::ProtoRing* ring_leading_here = &cand.rings.back().first.ring();
+ const ProtoRing* ring_leading_here = &cand.rings.back().first.ring();
for (const location_to_ring_map& m : connections) {
- const detail::ProtoRing& ring = m.ring();
+ const ProtoRing& ring = m.ring();
if (&ring != ring_leading_here) {
if (debug()) {
@@ -790,7 +785,7 @@ namespace osmium {
});
find_inner_outer_complex();
- detail::ProtoRing* outer_ring = find_enclosing_ring(ring_min->ring().min_segment());
+ ProtoRing* outer_ring = find_enclosing_ring(ring_min->ring().min_segment());
bool ring_min_is_outer = !outer_ring;
if (debug()) {
std::cerr << " Open ring is " << (ring_min_is_outer ? "outer" : "inner") << " ring\n";
@@ -890,7 +885,7 @@ namespace osmium {
// Now find all the rest of the rings (ie not starting at split locations)
if (count_remaining > 0) {
for (slocation& sl : m_locations) {
- const detail::NodeRefSegment& segment = m_segment_list[sl.item];
+ const NodeRefSegment& segment = m_segment_list[sl.item];
if (!segment.is_done()) {
count_remaining -= add_new_ring_complex(sl);
if (count_remaining == 0) {
@@ -918,7 +913,9 @@ namespace osmium {
if (debug()) {
std::cerr << " There are " << open_ring_its.size() << " open rings\n";
}
- while (try_to_merge(open_ring_its));
+ while (try_to_merge(open_ring_its)) {
+ // intentionally left blank
+ }
if (!open_ring_its.empty()) {
if (debug()) {
@@ -970,15 +967,15 @@ namespace osmium {
protected:
- const std::list<detail::ProtoRing>& rings() const noexcept {
+ const std::list<ProtoRing>& rings() const noexcept {
return m_rings;
}
- void set_num_members(size_t size) noexcept {
+ void set_num_members(std::size_t size) noexcept {
m_num_members = size;
}
- osmium::area::detail::SegmentList& segment_list() noexcept {
+ SegmentList& segment_list() noexcept {
return m_segment_list;
}
@@ -987,10 +984,10 @@ namespace osmium {
* area in the buffer.
*/
void add_rings_to_area(osmium::builder::AreaBuilder& builder) const {
- for (const detail::ProtoRing& ring : m_rings) {
+ for (const ProtoRing& ring : m_rings) {
if (ring.is_outer()) {
build_ring_from_proto_ring<osmium::builder::OuterRingBuilder>(builder, ring);
- for (const detail::ProtoRing* inner : ring.inner_rings()) {
+ for (const ProtoRing* inner : ring.inner_rings()) {
build_ring_from_proto_ring<osmium::builder::InnerRingBuilder>(builder, *inner);
}
}
@@ -1013,7 +1010,7 @@ namespace osmium {
// are two identical segments, they will both be removed. If
// there are three, two will be removed and one remains.
osmium::Timer timer_dupl;
- m_stats.duplicate_segments = m_segment_list.erase_duplicate_segments(m_config.problem_reporter);
+ m_segment_list.erase_duplicate_segments(m_config.problem_reporter, m_stats.duplicate_segments, m_stats.overlapping_segments);
timer_dupl.stop();
// If there are no segments left at this point, this isn't
@@ -1128,7 +1125,7 @@ namespace osmium {
timer_roles.stop();
}
- m_stats.outer_rings = std::count_if(m_rings.cbegin(), m_rings.cend(), [](const detail::ProtoRing& ring){
+ m_stats.outer_rings = std::count_if(m_rings.cbegin(), m_rings.cend(), [](const ProtoRing& ring){
return ring.is_outer();
});
m_stats.inner_rings = m_rings.size() - m_stats.outer_rings;
diff --git a/include/osmium/area/detail/basic_assembler_with_tags.hpp b/include/osmium/area/detail/basic_assembler_with_tags.hpp
new file mode 100644
index 0000000..1e94680
--- /dev/null
+++ b/include/osmium/area/detail/basic_assembler_with_tags.hpp
@@ -0,0 +1,93 @@
+#ifndef OSMIUM_AREA_DETAIL_BASIC_ASSEMBLER_WITH_TAGS_HPP
+#define OSMIUM_AREA_DETAIL_BASIC_ASSEMBLER_WITH_TAGS_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2017 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstring>
+
+#include <osmium/area/assembler_config.hpp>
+#include <osmium/area/detail/basic_assembler.hpp>
+#include <osmium/area/stats.hpp>
+#include <osmium/builder/osm_object_builder.hpp>
+#include <osmium/osm/tag.hpp>
+
+namespace osmium {
+
+ namespace area {
+
+ namespace detail {
+
+ class BasicAssemblerWithTags : public detail::BasicAssembler {
+
+ protected:
+
+ bool report_ways() const noexcept {
+ if (!config().problem_reporter) {
+ return false;
+ }
+ return stats().duplicate_nodes ||
+ stats().duplicate_segments ||
+ stats().intersections ||
+ stats().open_rings ||
+ stats().short_ways ||
+ stats().touching_rings ||
+ stats().ways_in_multiple_rings ||
+ stats().wrong_role;
+ }
+
+ static void copy_tags_without_type(osmium::builder::AreaBuilder& builder, const osmium::TagList& tags) {
+ osmium::builder::TagListBuilder tl_builder{builder};
+ for (const osmium::Tag& tag : tags) {
+ if (std::strcmp(tag.key(), "type")) {
+ tl_builder.add_tag(tag.key(), tag.value());
+ }
+ }
+ }
+
+ public:
+
+ using config_type = osmium::area::AssemblerConfig;
+
+ explicit BasicAssemblerWithTags(const config_type& config) :
+ BasicAssembler(config) {
+ }
+
+ }; // class BasicAssemblerWithTags
+
+ } // namespace detail
+
+ } // namespace area
+
+} // namespace osmium
+
+#endif // OSMIUM_AREA_DETAIL_BASIC_ASSEMBLER_WITH_TAGS_HPP
diff --git a/include/osmium/area/detail/node_ref_segment.hpp b/include/osmium/area/detail/node_ref_segment.hpp
index 8b37437..8039579 100644
--- a/include/osmium/area/detail/node_ref_segment.hpp
+++ b/include/osmium/area/detail/node_ref_segment.hpp
@@ -262,18 +262,6 @@ namespace osmium {
return lhs.first().location() < rhs.first().location();
}
- inline bool operator>(const NodeRefSegment& lhs, const NodeRefSegment& rhs) noexcept {
- return rhs < lhs;
- }
-
- inline bool operator<=(const NodeRefSegment& lhs, const NodeRefSegment& rhs) noexcept {
- return ! (rhs < lhs);
- }
-
- inline bool operator>=(const NodeRefSegment& lhs, const NodeRefSegment& rhs) noexcept {
- return ! (lhs < rhs);
- }
-
template <typename TChar, typename TTraits>
inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const NodeRefSegment& segment) {
return out << segment.start() << "--" << segment.stop()
@@ -283,19 +271,13 @@ namespace osmium {
}
inline bool outside_x_range(const NodeRefSegment& s1, const NodeRefSegment& s2) noexcept {
- if (s1.first().location().x() > s2.second().location().x()) {
- return true;
- }
- return false;
+ return s1.first().location().x() > s2.second().location().x();
}
inline bool y_range_overlap(const NodeRefSegment& s1, const NodeRefSegment& s2) noexcept {
const std::pair<int32_t, int32_t> m1 = std::minmax(s1.first().location().y(), s1.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) {
- return false;
- }
- return true;
+ return !(m1.first > m2.second || m2.first > m1.second);
}
/**
@@ -331,7 +313,7 @@ namespace osmium {
if ((p0 == q0 && p1 == q1) ||
(p0 == q1 && p1 == q0)) {
// segments are the same
- return osmium::Location();
+ return osmium::Location{};
}
const vec pd = p1 - p0;
@@ -342,7 +324,7 @@ namespace osmium {
if (p0 == q0 || p0 == q1 || p1 == q0 || p1 == q1) {
// touching at an end point
- return osmium::Location();
+ return osmium::Location{};
}
// intersection in a point
@@ -357,10 +339,10 @@ namespace osmium {
(d < 0 && na <= 0 && na >= d && nb <= 0 && nb >= d)) {
const double ua = double(na) / d;
const vec i = p0 + ua * (p1 - p0);
- return osmium::Location(int32_t(i.x), int32_t(i.y));
+ return osmium::Location{int32_t(i.x), int32_t(i.y)};
}
- return osmium::Location();
+ return osmium::Location{};
}
// segments are collinear
@@ -390,13 +372,12 @@ namespace osmium {
if (sl[0].segment != sl[1].segment) {
if (sl[0].location == sl[1].location) {
return sl[2].location;
- } else {
- return sl[1].location;
}
+ return sl[1].location;
}
}
- return osmium::Location();
+ return osmium::Location{};
}
} // namespace detail
diff --git a/include/osmium/area/detail/segment_list.hpp b/include/osmium/area/detail/segment_list.hpp
index efc45a5..39e16ab 100644
--- a/include/osmium/area/detail/segment_list.hpp
+++ b/include/osmium/area/detail/segment_list.hpp
@@ -49,6 +49,7 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/osm/location.hpp>
#include <osmium/osm/node_ref.hpp>
#include <osmium/osm/relation.hpp>
+#include <osmium/osm/types.hpp>
#include <osmium/osm/way.hpp>
namespace osmium {
@@ -90,9 +91,11 @@ namespace osmium {
static role_type parse_role(const char* role) noexcept {
if (role[0] == '\0') {
return role_type::empty;
- } else if (!std::strcmp(role, "outer")) {
+ }
+ if (!std::strcmp(role, "outer")) {
return role_type::outer;
- } else if (!std::strcmp(role, "inner")) {
+ }
+ if (!std::strcmp(role, "inner")) {
return role_type::inner;
}
return role_type::unknown;
@@ -101,17 +104,16 @@ namespace osmium {
/**
* Calculate the number of segments in all the ways together.
*/
- static size_t get_num_segments(const std::vector<const osmium::Way*>& members) noexcept {
- return std::accumulate(members.cbegin(), members.cend(), static_cast<size_t>(0), [](size_t sum, const osmium::Way* way) {
+ static std::size_t get_num_segments(const std::vector<const osmium::Way*>& members) noexcept {
+ return std::accumulate(members.cbegin(), members.cend(), static_cast<std::size_t>(0), [](std::size_t sum, const osmium::Way* way) {
if (way->nodes().empty()) {
return sum;
- } else {
- return sum + way->nodes().size() - 1;
}
+ return sum + way->nodes().size() - 1;
});
}
- uint32_t extract_segments_from_way_impl(osmium::area::ProblemReporter* problem_reporter, uint64_t& duplicate_nodes, const osmium::Way& way, role_type role) {
+ uint32_t extract_segments_from_way_impl(ProblemReporter* problem_reporter, uint64_t& duplicate_nodes, const osmium::Way& way, role_type role) {
uint32_t invalid_locations = 0;
osmium::NodeRef previous_nr;
@@ -155,7 +157,7 @@ namespace osmium {
SegmentList& operator=(SegmentList&&) = delete;
/// The number of segments in the list.
- size_t size() const noexcept {
+ std::size_t size() const noexcept {
return m_segments.size();
}
@@ -175,12 +177,12 @@ namespace osmium {
return m_segments.back();
}
- const NodeRefSegment& operator[](size_t n) const noexcept {
+ const NodeRefSegment& operator[](std::size_t n) const noexcept {
assert(n < m_segments.size());
return m_segments[n];
}
- NodeRefSegment& operator[](size_t n) noexcept {
+ NodeRefSegment& operator[](std::size_t n) noexcept {
assert(n < m_segments.size());
return m_segments[n];
}
@@ -221,7 +223,7 @@ namespace osmium {
* same node or different nodes with same location) are
* removed after reporting the duplicate node.
*/
- uint32_t extract_segments_from_way(osmium::area::ProblemReporter* problem_reporter, uint64_t& duplicate_nodes, const osmium::Way& way) {
+ uint32_t extract_segments_from_way(ProblemReporter* problem_reporter, uint64_t& duplicate_nodes, const osmium::Way& way) {
if (way.nodes().empty()) {
return 0;
}
@@ -233,14 +235,14 @@ namespace osmium {
* Extract all segments from all ways that make up this
* multipolygon relation and add them to the list.
*/
- uint32_t extract_segments_from_ways(osmium::area::ProblemReporter* problem_reporter,
+ uint32_t extract_segments_from_ways(ProblemReporter* problem_reporter,
uint64_t& duplicate_nodes,
uint64_t& duplicate_ways,
const osmium::Relation& relation,
const std::vector<const osmium::Way*>& members) {
- assert(relation.members().size() >= members.size());
+ assert(relation.cmembers().size() >= members.size());
- const size_t num_segments = get_num_segments(members);
+ const std::size_t num_segments = get_num_segments(members);
if (problem_reporter) {
problem_reporter->set_nodes(num_segments);
}
@@ -271,9 +273,7 @@ namespace osmium {
* same segment. So if there are three, for instance, two will
* be removed and one will be left.
*/
- uint32_t erase_duplicate_segments(osmium::area::ProblemReporter* problem_reporter) {
- uint32_t duplicate_segments = 0;
-
+ void erase_duplicate_segments(ProblemReporter* problem_reporter, uint64_t& duplicate_segments, uint64_t& overlapping_segments) {
while (true) {
auto it = std::adjacent_find(m_segments.begin(), m_segments.end());
if (it == m_segments.end()) {
@@ -296,10 +296,16 @@ namespace osmium {
problem_reporter->report_duplicate_segment(it->first(), it->second());
}
}
+
+ if (it+2 != m_segments.end() && *it == *(it+2)) {
+ ++overlapping_segments;
+ if (problem_reporter) {
+ problem_reporter->report_overlapping_segment(it->first(), it->second());
+ }
+ }
+
m_segments.erase(it, it+2);
}
-
- return duplicate_segments;
}
/**
@@ -309,14 +315,14 @@ namespace osmium {
* reported to this object.
* @returns true if there are intersections.
*/
- uint32_t find_intersections(osmium::area::ProblemReporter* problem_reporter) const {
+ uint32_t find_intersections(ProblemReporter* problem_reporter) const {
if (m_segments.empty()) {
return 0;
}
uint32_t found_intersections = 0;
- for (auto it1 = m_segments.cbegin(); it1 != m_segments.cend()-1; ++it1) {
+ for (auto it1 = m_segments.cbegin(); it1 != m_segments.cend() - 1; ++it1) {
const NodeRefSegment& s1 = *it1;
for (auto it2 = it1+1; it2 != m_segments.end(); ++it2) {
const NodeRefSegment& s2 = *it2;
@@ -328,7 +334,7 @@ namespace osmium {
}
if (y_range_overlap(s1, s2)) {
- osmium::Location intersection = calculate_intersection(s1, s2);
+ osmium::Location intersection{calculate_intersection(s1, s2)};
if (intersection) {
++found_intersections;
if (m_debug) {
diff --git a/include/osmium/area/geom_assembler.hpp b/include/osmium/area/geom_assembler.hpp
index 84870ae..8fb3b3a 100644
--- a/include/osmium/area/geom_assembler.hpp
+++ b/include/osmium/area/geom_assembler.hpp
@@ -33,12 +33,13 @@ DEALINGS IN THE SOFTWARE.
*/
+#include <osmium/area/assembler_config.hpp>
#include <osmium/area/detail/basic_assembler.hpp>
+#include <osmium/area/detail/segment_list.hpp>
+#include <osmium/area/stats.hpp>
#include <osmium/builder/osm_object_builder.hpp>
#include <osmium/memory/buffer.hpp>
-#include <osmium/osm/item_type.hpp>
#include <osmium/osm/relation.hpp>
-#include <osmium/osm/types.hpp>
#include <osmium/osm/way.hpp>
namespace osmium {
diff --git a/include/osmium/area/multipolygon_collector.hpp b/include/osmium/area/multipolygon_collector.hpp
index ad2e56d..9ad68e1 100644
--- a/include/osmium/area/multipolygon_collector.hpp
+++ b/include/osmium/area/multipolygon_collector.hpp
@@ -81,7 +81,7 @@ namespace osmium {
osmium::memory::Buffer m_output_buffer;
- osmium::area::area_stats m_stats;
+ area_stats m_stats;
static constexpr size_t initial_output_buffer_size = 1024 * 1024;
static constexpr size_t max_buffer_size_for_flush = 100 * 1024;
@@ -109,7 +109,7 @@ namespace osmium {
m_output_buffer(initial_output_buffer_size, osmium::memory::Buffer::auto_grow::yes) {
}
- const osmium::area::area_stats& stats() const noexcept {
+ const area_stats& stats() const noexcept {
return m_stats;
}
@@ -127,11 +127,7 @@ namespace osmium {
return false;
}
- if ((!std::strcmp(type, "multipolygon")) || (!std::strcmp(type, "boundary"))) {
- return true;
- }
-
- return false;
+ return (!std::strcmp(type, "multipolygon")) || (!std::strcmp(type, "boundary"));
}
/**
@@ -155,11 +151,11 @@ namespace osmium {
}
try {
if (!way.nodes().front().location() || !way.nodes().back().location()) {
- throw osmium::invalid_location("invalid location");
+ throw osmium::invalid_location{"invalid location"};
}
if (way.ends_have_same_location()) {
// way is closed and has enough nodes, build simple multipolygon
- TAssembler assembler(m_assembler_config);
+ TAssembler assembler{m_assembler_config};
assembler(way, m_output_buffer);
m_stats += assembler.stats();
possibly_flush_output_buffer();
@@ -183,7 +179,7 @@ namespace osmium {
}
try {
- TAssembler assembler(m_assembler_config);
+ TAssembler assembler{m_assembler_config};
assembler(relation, ways, m_output_buffer);
m_stats += assembler.stats();
possibly_flush_output_buffer();
diff --git a/include/osmium/area/multipolygon_collector.hpp b/include/osmium/area/multipolygon_manager.hpp
similarity index 51%
copy from include/osmium/area/multipolygon_collector.hpp
copy to include/osmium/area/multipolygon_manager.hpp
index ad2e56d..e5ee2c8 100644
--- a/include/osmium/area/multipolygon_collector.hpp
+++ b/include/osmium/area/multipolygon_manager.hpp
@@ -1,5 +1,5 @@
-#ifndef OSMIUM_AREA_MULTIPOLYGON_COLLECTOR_HPP
-#define OSMIUM_AREA_MULTIPOLYGON_COLLECTOR_HPP
+#ifndef OSMIUM_AREA_MULTIPOLYGON_MANAGER_HPP
+#define OSMIUM_AREA_MULTIPOLYGON_MANAGER_HPP
/*
@@ -34,26 +34,27 @@ DEALINGS IN THE SOFTWARE.
*/
#include <algorithm>
+#include <cassert>
#include <cstddef>
+#include <cstdint>
#include <cstring>
#include <vector>
#include <osmium/area/stats.hpp>
-#include <osmium/memory/buffer.hpp>
#include <osmium/osm/item_type.hpp>
-#include <osmium/osm/location.hpp>
-#include <osmium/osm/node_ref.hpp>
#include <osmium/osm/relation.hpp>
#include <osmium/osm/tag.hpp>
#include <osmium/osm/way.hpp>
-#include <osmium/relations/collector.hpp>
+#include <osmium/relations/manager_util.hpp>
+#include <osmium/relations/members_database.hpp>
+#include <osmium/relations/relations_database.hpp>
+#include <osmium/relations/relations_manager.hpp>
+#include <osmium/storage/item_stash.hpp>
+#include <osmium/tags/taglist.hpp>
+#include <osmium/tags/tags_filter.hpp>
namespace osmium {
- namespace relations {
- class RelationMeta;
- } // namespace relations
-
/**
* @brief Code related to the building of areas (multipolygons) from relations.
*/
@@ -72,143 +73,117 @@ namespace osmium {
* @pre The Ids of all objects must be unique in the input data.
*/
template <typename TAssembler>
- class MultipolygonCollector : public osmium::relations::Collector<MultipolygonCollector<TAssembler>, false, true, false> {
-
- using collector_type = osmium::relations::Collector<MultipolygonCollector<TAssembler>, false, true, false>;
+ class MultipolygonManager : public osmium::relations::RelationsManager<MultipolygonManager<TAssembler>, false, true, false> {
using assembler_config_type = typename TAssembler::config_type;
const assembler_config_type m_assembler_config;
- osmium::memory::Buffer m_output_buffer;
+ area_stats m_stats;
- osmium::area::area_stats m_stats;
-
- static constexpr size_t initial_output_buffer_size = 1024 * 1024;
- static constexpr size_t max_buffer_size_for_flush = 100 * 1024;
-
- void flush_output_buffer() {
- if (this->callback()) {
- osmium::memory::Buffer buffer{initial_output_buffer_size};
- using std::swap;
- swap(buffer, m_output_buffer);
- this->callback()(std::move(buffer));
- }
- }
-
- void possibly_flush_output_buffer() {
- if (m_output_buffer.committed() > max_buffer_size_for_flush) {
- flush_output_buffer();
- }
- }
+ osmium::TagsFilter m_filter;
public:
- explicit MultipolygonCollector(const assembler_config_type& assembler_config) :
- collector_type(),
+ /**
+ * Construct a MultipolygonManager.
+ *
+ * @param assembler_config The configuration that will be given to
+ * any newly constructed area assembler.
+ * @param filter An optional filter specifying what tags are
+ * needed on closed ways or multipolygon relations
+ * to build the area.
+ */
+ explicit MultipolygonManager(const assembler_config_type& assembler_config, const osmium::TagsFilter& filter = osmium::TagsFilter{true}) :
m_assembler_config(assembler_config),
- m_output_buffer(initial_output_buffer_size, osmium::memory::Buffer::auto_grow::yes) {
+ m_filter(filter) {
}
- const osmium::area::area_stats& stats() const noexcept {
+ /**
+ * Access the aggregated statistics generated by the assemblers
+ * called from the manager.
+ */
+ const area_stats& stats() const noexcept {
return m_stats;
}
/**
* We are interested in all relations tagged with type=multipolygon
- * or type=boundary.
- *
- * Overwritten from the base class.
+ * or type=boundary with at least one way member.
*/
- bool keep_relation(const osmium::Relation& relation) const {
+ bool new_relation(const osmium::Relation& relation) const {
const char* type = relation.tags().get_value_by_key("type");
// ignore relations without "type" tag
- if (!type) {
+ if (type == nullptr) {
return false;
}
- if ((!std::strcmp(type, "multipolygon")) || (!std::strcmp(type, "boundary"))) {
- return true;
+ if (((!std::strcmp(type, "multipolygon")) || (!std::strcmp(type, "boundary"))) && osmium::tags::match_any_of(relation.tags(), m_filter)) {
+ return std::any_of(relation.members().cbegin(), relation.members().cend(), [](const RelationMember& member) {
+ return member.type() == osmium::item_type::way;
+ });
}
return false;
}
/**
- * Overwritten from the base class.
- */
- bool keep_member(const osmium::relations::RelationMeta& /*relation_meta*/, const osmium::RelationMember& member) const {
- // We are only interested in members of type way.
- return member.type() == osmium::item_type::way;
- }
-
- /**
- * This is called when a way is not in any multipolygon
- * relation.
- *
- * Overwritten from the base class.
+ * This is called when a relation is complete, ie. all members
+ * were found in the input. It will build the area using the
+ * assembler.
*/
- void way_not_in_any_relation(const osmium::Way& way) {
- // you need at least 4 nodes to make up a polygon
- if (way.nodes().size() <= 3) {
- return;
- }
- try {
- if (!way.nodes().front().location() || !way.nodes().back().location()) {
- throw osmium::invalid_location("invalid location");
- }
- if (way.ends_have_same_location()) {
- // way is closed and has enough nodes, build simple multipolygon
- TAssembler assembler(m_assembler_config);
- assembler(way, m_output_buffer);
- m_stats += assembler.stats();
- possibly_flush_output_buffer();
- }
- } catch (const osmium::invalid_location&) {
- // XXX ignore
- }
- }
-
- void complete_relation(osmium::relations::RelationMeta& relation_meta) {
- const osmium::Relation& relation = this->get_relation(relation_meta);
- const osmium::memory::Buffer& buffer = this->members_buffer();
-
+ void complete_relation(const osmium::Relation& relation) {
std::vector<const osmium::Way*> ways;
ways.reserve(relation.members().size());
for (const auto& member : relation.members()) {
if (member.ref() != 0) {
- const size_t offset = this->get_offset(member.type(), member.ref());
- ways.push_back(&buffer.get<const osmium::Way>(offset));
+ ways.push_back(this->get_member_way(member.ref()));
+ assert(ways.back() != nullptr);
}
}
try {
- TAssembler assembler(m_assembler_config);
- assembler(relation, ways, m_output_buffer);
+ TAssembler assembler{m_assembler_config};
+ assembler(relation, ways, this->buffer());
m_stats += assembler.stats();
- possibly_flush_output_buffer();
} catch (const osmium::invalid_location&) {
// XXX ignore
}
}
- void flush() {
- flush_output_buffer();
- }
+ void after_way(const osmium::Way& way) {
+ // you need at least 4 nodes to make up a polygon
+ if (way.nodes().size() <= 3) {
+ return;
+ }
- osmium::memory::Buffer read() {
- osmium::memory::Buffer buffer{initial_output_buffer_size, osmium::memory::Buffer::auto_grow::yes};
+ try {
+ if (!way.nodes().front().location() || !way.nodes().back().location()) {
+ throw osmium::invalid_location{"invalid location"};
+ }
+ if (way.ends_have_same_location()) {
+ if (way.tags().has_tag("area", "no")) {
+ return;
+ }
- using std::swap;
- swap(buffer, m_output_buffer);
+ if (osmium::tags::match_none_of(way.tags(), m_filter)) {
+ return;
+ }
- return buffer;
+ TAssembler assembler{m_assembler_config};
+ assembler(way, this->buffer());
+ m_stats += assembler.stats();
+ this->possibly_flush();
+ }
+ } catch (const osmium::invalid_location&) {
+ // XXX ignore
+ }
}
- }; // class MultipolygonCollector
+ }; // class MultipolygonManager
} // namespace area
} // namespace osmium
-#endif // OSMIUM_AREA_MULTIPOLYGON_COLLECTOR_HPP
+#endif // OSMIUM_AREA_MULTIPOLYGON_MANAGER_HPP
diff --git a/include/osmium/area/multipolygon_collector.hpp b/include/osmium/area/multipolygon_manager_legacy.hpp
similarity index 56%
copy from include/osmium/area/multipolygon_collector.hpp
copy to include/osmium/area/multipolygon_manager_legacy.hpp
index ad2e56d..491557a 100644
--- a/include/osmium/area/multipolygon_collector.hpp
+++ b/include/osmium/area/multipolygon_manager_legacy.hpp
@@ -1,5 +1,5 @@
-#ifndef OSMIUM_AREA_MULTIPOLYGON_COLLECTOR_HPP
-#define OSMIUM_AREA_MULTIPOLYGON_COLLECTOR_HPP
+#ifndef OSMIUM_AREA_MULTIPOLYGON_MANAGER_LEGACY_HPP
+#define OSMIUM_AREA_MULTIPOLYGON_MANAGER_LEGACY_HPP
/*
@@ -34,26 +34,29 @@ DEALINGS IN THE SOFTWARE.
*/
#include <algorithm>
+#include <cassert>
#include <cstddef>
+#include <cstdint>
#include <cstring>
#include <vector>
#include <osmium/area/stats.hpp>
+#include <osmium/handler.hpp>
+#include <osmium/handler/check_order.hpp>
#include <osmium/memory/buffer.hpp>
+#include <osmium/memory/callback_buffer.hpp>
#include <osmium/osm/item_type.hpp>
-#include <osmium/osm/location.hpp>
-#include <osmium/osm/node_ref.hpp>
#include <osmium/osm/relation.hpp>
#include <osmium/osm/tag.hpp>
#include <osmium/osm/way.hpp>
-#include <osmium/relations/collector.hpp>
+#include <osmium/relations/manager_util.hpp>
+#include <osmium/relations/members_database.hpp>
+#include <osmium/relations/relations_database.hpp>
+#include <osmium/relations/relations_manager.hpp>
+#include <osmium/storage/item_stash.hpp>
namespace osmium {
- namespace relations {
- class RelationMeta;
- } // namespace relations
-
/**
* @brief Code related to the building of areas (multipolygons) from relations.
*/
@@ -72,54 +75,38 @@ namespace osmium {
* @pre The Ids of all objects must be unique in the input data.
*/
template <typename TAssembler>
- class MultipolygonCollector : public osmium::relations::Collector<MultipolygonCollector<TAssembler>, false, true, false> {
-
- using collector_type = osmium::relations::Collector<MultipolygonCollector<TAssembler>, false, true, false>;
+ class MultipolygonManagerLegacy : public osmium::relations::RelationsManager<MultipolygonManagerLegacy<TAssembler>, false, true, false> {
using assembler_config_type = typename TAssembler::config_type;
const assembler_config_type m_assembler_config;
- osmium::memory::Buffer m_output_buffer;
-
- osmium::area::area_stats m_stats;
-
- static constexpr size_t initial_output_buffer_size = 1024 * 1024;
- static constexpr size_t max_buffer_size_for_flush = 100 * 1024;
-
- void flush_output_buffer() {
- if (this->callback()) {
- osmium::memory::Buffer buffer{initial_output_buffer_size};
- using std::swap;
- swap(buffer, m_output_buffer);
- this->callback()(std::move(buffer));
- }
- }
-
- void possibly_flush_output_buffer() {
- if (m_output_buffer.committed() > max_buffer_size_for_flush) {
- flush_output_buffer();
- }
- }
+ area_stats m_stats;
public:
- explicit MultipolygonCollector(const assembler_config_type& assembler_config) :
- collector_type(),
- m_assembler_config(assembler_config),
- m_output_buffer(initial_output_buffer_size, osmium::memory::Buffer::auto_grow::yes) {
+ /**
+ * Construct a MultipolygonManagerLegacy.
+ *
+ * @param assembler_config The configuration that will be given to
+ * any newly constructed area assembler.
+ */
+ explicit MultipolygonManagerLegacy(const assembler_config_type& assembler_config) :
+ m_assembler_config(assembler_config) {
}
- const osmium::area::area_stats& stats() const noexcept {
+ /**
+ * Access the aggregated statistics generated by the assemblers
+ * called from the manager.
+ */
+ const area_stats& stats() const noexcept {
return m_stats;
}
/**
* We are interested in all relations tagged with type=multipolygon
- * or type=boundary.
- *
- * Overwritten from the base class.
+ * or type=boundary with at least one way member.
*/
- bool keep_relation(const osmium::Relation& relation) const {
+ bool new_relation(const osmium::Relation& relation) const {
const char* type = relation.tags().get_value_by_key("type");
// ignore relations without "type" tag
@@ -128,25 +115,41 @@ namespace osmium {
}
if ((!std::strcmp(type, "multipolygon")) || (!std::strcmp(type, "boundary"))) {
- return true;
+ return std::any_of(relation.members().cbegin(), relation.members().cend(), [](const RelationMember& member) {
+ return member.type() == osmium::item_type::way;
+ });
}
return false;
}
/**
- * Overwritten from the base class.
+ * This is called when a relation is complete, ie. all members
+ * were found in the input. It will build the area using the
+ * assembler.
*/
- bool keep_member(const osmium::relations::RelationMeta& /*relation_meta*/, const osmium::RelationMember& member) const {
- // We are only interested in members of type way.
- return member.type() == osmium::item_type::way;
+ void complete_relation(const osmium::Relation& relation) {
+ std::vector<const osmium::Way*> ways;
+ ways.reserve(relation.members().size());
+ for (const auto& member : relation.members()) {
+ if (member.ref() != 0) {
+ ways.push_back(this->get_member_way(member.ref()));
+ assert(ways.back() != nullptr);
+ }
+ }
+
+ try {
+ TAssembler assembler{m_assembler_config};
+ assembler(relation, ways, this->buffer());
+ m_stats += assembler.stats();
+ } catch (const osmium::invalid_location&) {
+ // XXX ignore
+ }
}
/**
* This is called when a way is not in any multipolygon
* relation.
- *
- * Overwritten from the base class.
*/
void way_not_in_any_relation(const osmium::Way& way) {
// you need at least 4 nodes to make up a polygon
@@ -155,60 +158,23 @@ namespace osmium {
}
try {
if (!way.nodes().front().location() || !way.nodes().back().location()) {
- throw osmium::invalid_location("invalid location");
+ throw osmium::invalid_location{"invalid location"};
}
if (way.ends_have_same_location()) {
// way is closed and has enough nodes, build simple multipolygon
- TAssembler assembler(m_assembler_config);
- assembler(way, m_output_buffer);
+ TAssembler assembler{m_assembler_config};
+ assembler(way, this->buffer());
m_stats += assembler.stats();
- possibly_flush_output_buffer();
}
} catch (const osmium::invalid_location&) {
// XXX ignore
}
}
- void complete_relation(osmium::relations::RelationMeta& relation_meta) {
- const osmium::Relation& relation = this->get_relation(relation_meta);
- const osmium::memory::Buffer& buffer = this->members_buffer();
-
- std::vector<const osmium::Way*> ways;
- ways.reserve(relation.members().size());
- for (const auto& member : relation.members()) {
- if (member.ref() != 0) {
- const size_t offset = this->get_offset(member.type(), member.ref());
- ways.push_back(&buffer.get<const osmium::Way>(offset));
- }
- }
-
- try {
- TAssembler assembler(m_assembler_config);
- assembler(relation, ways, m_output_buffer);
- m_stats += assembler.stats();
- possibly_flush_output_buffer();
- } catch (const osmium::invalid_location&) {
- // XXX ignore
- }
- }
-
- void flush() {
- flush_output_buffer();
- }
-
- osmium::memory::Buffer read() {
- osmium::memory::Buffer buffer{initial_output_buffer_size, osmium::memory::Buffer::auto_grow::yes};
-
- using std::swap;
- swap(buffer, m_output_buffer);
-
- return buffer;
- }
-
- }; // class MultipolygonCollector
+ }; // class MultipolygonManagerLegacy
} // namespace area
} // namespace osmium
-#endif // OSMIUM_AREA_MULTIPOLYGON_COLLECTOR_HPP
+#endif // OSMIUM_AREA_MULTIPOLYGON_MANAGER_LEGACY_HPP
diff --git a/include/osmium/area/problem_reporter.hpp b/include/osmium/area/problem_reporter.hpp
index 797845b..181d2d1 100644
--- a/include/osmium/area/problem_reporter.hpp
+++ b/include/osmium/area/problem_reporter.hpp
@@ -144,6 +144,18 @@ namespace osmium {
}
/**
+ * Report a duplicate segments. Two or more segments are directly
+ * on top of each other. This can be a problem, if there is a
+ * spike for instance, or it could be okay, if there are touching
+ * inner rings.
+ *
+ * @param nr1 NodeRef of one end of the segment.
+ * @param nr2 NodeRef of the other end of the segment.
+ */
+ virtual void report_overlapping_segment(const osmium::NodeRef& nr1, const osmium::NodeRef& nr2) {
+ }
+
+ /**
* Report an open ring.
*
* @param nr NodeRef of one end of the ring.
diff --git a/include/osmium/area/problem_reporter_exception.hpp b/include/osmium/area/problem_reporter_exception.hpp
index f1d64d8..cfc2b54 100644
--- a/include/osmium/area/problem_reporter_exception.hpp
+++ b/include/osmium/area/problem_reporter_exception.hpp
@@ -84,6 +84,12 @@ namespace osmium {
throw std::runtime_error{m_sstream.str()};
}
+ void report_overlapping_segment(const osmium::NodeRef& nr1, const osmium::NodeRef& nr2) override {
+ m_sstream.str("");
+ ProblemReporterStream::report_overlapping_segment(nr1, nr2);
+ throw std::runtime_error{m_sstream.str()};
+ }
+
void report_ring_not_closed(const osmium::NodeRef& nr, const osmium::Way* way = nullptr) override {
m_sstream.str("");
ProblemReporterStream::report_ring_not_closed(nr, way);
diff --git a/include/osmium/area/problem_reporter_ogr.hpp b/include/osmium/area/problem_reporter_ogr.hpp
index 80cbbc2..5f531c8 100644
--- a/include/osmium/area/problem_reporter_ogr.hpp
+++ b/include/osmium/area/problem_reporter_ogr.hpp
@@ -158,6 +158,10 @@ namespace osmium {
write_line("duplicate_segment", nr1.ref(), nr2.ref(), nr1.location(), nr2.location());
}
+ void report_overlapping_segment(const osmium::NodeRef& nr1, const osmium::NodeRef& nr2) override {
+ write_line("overlapping_segment", nr1.ref(), nr2.ref(), nr1.location(), nr2.location());
+ }
+
void report_ring_not_closed(const osmium::NodeRef& nr, const osmium::Way* way = nullptr) override {
write_point("ring_not_closed", nr.ref(), way ? way->id() : 0, nr.location());
}
diff --git a/include/osmium/area/problem_reporter_stream.hpp b/include/osmium/area/problem_reporter_stream.hpp
index ee414a6..774e9c3 100644
--- a/include/osmium/area/problem_reporter_stream.hpp
+++ b/include/osmium/area/problem_reporter_stream.hpp
@@ -85,6 +85,12 @@ namespace osmium {
<< " node_id2=" << nr2.ref() << " location2=" << nr2.location() << "\n";
}
+ void report_overlapping_segment(const osmium::NodeRef& nr1, const osmium::NodeRef& nr2) override {
+ header("overlapping segment");
+ *m_out << "node_id1=" << nr1.ref() << " location1=" << nr1.location()
+ << " node_id2=" << nr2.ref() << " location2=" << nr2.location() << "\n";
+ }
+
void report_ring_not_closed(const osmium::NodeRef& nr, const osmium::Way* way = nullptr) override {
header("ring not closed");
*m_out << "node_id=" << nr.ref() << " location=" << nr.location();
diff --git a/include/osmium/area/stats.hpp b/include/osmium/area/stats.hpp
index 2fc18b7..6133da8 100644
--- a/include/osmium/area/stats.hpp
+++ b/include/osmium/area/stats.hpp
@@ -64,6 +64,7 @@ namespace osmium {
uint64_t nodes = 0; ///< Number of nodes in the area
uint64_t open_rings = 0; ///< Number of open rings in the area
uint64_t outer_rings = 0; ///< Number of outer rings in the area
+ uint64_t overlapping_segments = 0; ///< Three or more segments with same end points
uint64_t short_ways = 0; ///< Number of ways with less than two nodes
uint64_t single_way_in_mp_relation = 0; ///< Multipolygon relation containing a single way
uint64_t touching_rings = 0; ///< Rings touching in a node
diff --git a/include/osmium/builder/builder.hpp b/include/osmium/builder/builder.hpp
index d435884..4351588 100644
--- a/include/osmium/builder/builder.hpp
+++ b/include/osmium/builder/builder.hpp
@@ -35,16 +35,12 @@ DEALINGS IN THE SOFTWARE.
#include <algorithm>
#include <cassert>
+#include <cstddef>
#include <cstdint>
#include <cstring>
-#include <new>
-#include <string>
-#include <type_traits>
#include <osmium/memory/buffer.hpp>
#include <osmium/memory/item.hpp>
-#include <osmium/osm/types.hpp>
-#include <osmium/util/cast.hpp>
#include <osmium/util/compatibility.hpp>
namespace osmium {
@@ -62,7 +58,7 @@ namespace osmium {
osmium::memory::Buffer& m_buffer;
Builder* m_parent;
- size_t m_item_offset;
+ std::size_t m_item_offset;
Builder(const Builder&) = delete;
Builder(Builder&&) = delete;
@@ -101,7 +97,7 @@ namespace osmium {
return *reinterpret_cast<osmium::memory::Item*>(m_buffer.data() + m_item_offset);
}
- unsigned char* reserve_space(size_t size) {
+ unsigned char* reserve_space(std::size_t size) {
return m_buffer.reserve_space(size);
}
@@ -119,7 +115,9 @@ namespace osmium {
*
*/
void add_padding(bool self = false) {
- const auto padding = osmium::memory::align_bytes - (size() % osmium::memory::align_bytes);
+ // We know the padding is only a very small number, so it will
+ // always fit.
+ const auto padding = static_cast<osmium::memory::item_size_type>(osmium::memory::align_bytes - (size() % osmium::memory::align_bytes));
if (padding != osmium::memory::align_bytes) {
std::fill_n(reserve_space(padding), padding, 0);
if (self) {
@@ -131,7 +129,7 @@ namespace osmium {
}
}
- void add_size(uint32_t size) {
+ void add_size(osmium::memory::item_size_type size) {
item().add_size(size);
if (m_parent) {
m_parent->add_size(size);
diff --git a/include/osmium/builder/osm_object_builder.hpp b/include/osmium/builder/osm_object_builder.hpp
index d4483b1..4706314 100644
--- a/include/osmium/builder/osm_object_builder.hpp
+++ b/include/osmium/builder/osm_object_builder.hpp
@@ -33,7 +33,10 @@ DEALINGS IN THE SOFTWARE.
*/
+#include <algorithm>
#include <cassert>
+#include <cstdint>
+#include <cstddef>
#include <cstring>
#include <initializer_list>
#include <limits>
@@ -43,25 +46,25 @@ DEALINGS IN THE SOFTWARE.
#include <utility>
#include <osmium/builder/builder.hpp>
+#include <osmium/memory/item.hpp>
+#include <osmium/osm/area.hpp>
+#include <osmium/osm/box.hpp>
+#include <osmium/osm/changeset.hpp>
#include <osmium/osm/item_type.hpp>
#include <osmium/osm/location.hpp>
#include <osmium/osm/node.hpp>
#include <osmium/osm/node_ref.hpp>
#include <osmium/osm/object.hpp>
-#include <osmium/osm/tag.hpp>
-#include <osmium/osm/types.hpp>
-#include <osmium/memory/item.hpp>
-#include <osmium/osm/area.hpp>
-#include <osmium/osm/changeset.hpp>
#include <osmium/osm/relation.hpp>
+#include <osmium/osm/tag.hpp>
#include <osmium/osm/timestamp.hpp>
+#include <osmium/osm/types.hpp>
#include <osmium/osm/way.hpp>
+#include <osmium/util/cast.hpp>
#include <osmium/util/compatibility.hpp>
namespace osmium {
- class Node;
-
namespace memory {
class Buffer;
} // namespace memory
@@ -74,12 +77,12 @@ namespace osmium {
explicit TagListBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
Builder(buffer, parent, sizeof(TagList)) {
- new (&item()) TagList();
+ new (&item()) TagList{};
}
explicit TagListBuilder(Builder& parent) :
Builder(parent.buffer(), &parent, sizeof(TagList)) {
- new (&item()) TagList();
+ new (&item()) TagList{};
}
~TagListBuilder() {
@@ -94,10 +97,10 @@ namespace osmium {
*/
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");
+ 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");
+ throw std::length_error{"OSM tag value is too long"};
}
add_size(append(key));
add_size(append(value));
@@ -111,12 +114,12 @@ namespace osmium {
* @param value Pointer to tag value.
* @param value_length Length of value (not including the \0 byte).
*/
- void add_tag(const char* key, const size_t key_length, const char* value, const size_t value_length) {
+ void add_tag(const char* key, const std::size_t key_length, const char* value, const std::size_t value_length) {
if (key_length > osmium::max_osm_string_length) {
- throw std::length_error("OSM tag key is too long");
+ 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");
+ throw std::length_error{"OSM tag value is too long"};
}
add_size(append_with_zero(key, osmium::memory::item_size_type(key_length)));
add_size(append_with_zero(value, osmium::memory::item_size_type(value_length)));
@@ -130,10 +133,10 @@ namespace osmium {
*/
void add_tag(const std::string& key, const std::string& value) {
if (key.size() > osmium::max_osm_string_length) {
- throw std::length_error("OSM tag key is too long");
+ 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");
+ throw std::length_error{"OSM tag value is too long"};
}
add_size(append(key.data(), osmium::memory::item_size_type(key.size()) + 1));
add_size(append(value.data(), osmium::memory::item_size_type(value.size()) + 1));
@@ -185,12 +188,12 @@ namespace osmium {
explicit NodeRefListBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
Builder(buffer, parent, sizeof(T)) {
- new (&item()) T();
+ new (&item()) T{};
}
explicit NodeRefListBuilder(Builder& parent) :
Builder(parent.buffer(), &parent, sizeof(T)) {
- new (&item()) T();
+ new (&item()) T{};
}
~NodeRefListBuilder() {
@@ -198,12 +201,12 @@ namespace osmium {
}
void add_node_ref(const NodeRef& node_ref) {
- new (reserve_space_for<osmium::NodeRef>()) osmium::NodeRef(node_ref);
+ new (reserve_space_for<osmium::NodeRef>()) osmium::NodeRef{node_ref};
add_size(sizeof(osmium::NodeRef));
}
void add_node_ref(const object_id_type ref, const osmium::Location& location = Location{}) {
- add_node_ref(NodeRef(ref, location));
+ add_node_ref(NodeRef{ref, location});
}
}; // class NodeRefListBuilder
@@ -223,9 +226,9 @@ namespace osmium {
* @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 size_t length) {
+ void add_role(osmium::RelationMember& member, const char* role, const std::size_t length) {
if (length > osmium::max_osm_string_length) {
- throw std::length_error("OSM relation member role is too long");
+ throw std::length_error{"OSM relation member role is too long"};
}
member.set_role_size(osmium::string_size_type(length) + 1);
add_size(append_with_zero(role, osmium::memory::item_size_type(length)));
@@ -236,12 +239,12 @@ namespace osmium {
explicit RelationMemberListBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
Builder(buffer, parent, sizeof(RelationMemberList)) {
- new (&item()) RelationMemberList();
+ new (&item()) RelationMemberList{};
}
explicit RelationMemberListBuilder(Builder& parent) :
Builder(parent.buffer(), &parent, sizeof(RelationMemberList)) {
- new (&item()) RelationMemberList();
+ new (&item()) RelationMemberList{};
}
~RelationMemberListBuilder() {
@@ -261,9 +264,9 @@ namespace osmium {
* @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 size_t role_length, const osmium::OSMObject* full_member = nullptr) {
+ void add_member(osmium::item_type type, object_id_type ref, const char* role, const std::size_t role_length, const osmium::OSMObject* full_member = nullptr) {
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_role(*member, role, role_length);
if (full_member) {
@@ -307,23 +310,19 @@ namespace osmium {
osmium::ChangesetComment* m_comment = nullptr;
- void add_user(osmium::ChangesetComment& comment, const char* user, const size_t length) {
+ void add_user(osmium::ChangesetComment& comment, const char* user, const std::size_t length) {
if (length > osmium::max_osm_string_length) {
- throw std::length_error("OSM user name is too long");
+ throw std::length_error{"OSM user name is too long"};
}
comment.set_user_size(osmium::string_size_type(length) + 1);
add_size(append_with_zero(user, osmium::memory::item_size_type(length)));
}
- 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");
+ void add_text(osmium::ChangesetComment& comment, const char* text, const std::size_t length) {
+ if (length > std::numeric_limits<osmium::changeset_comment_size_type>::max() - 1) {
+ throw std::length_error{"OSM changeset comment is too long"};
}
- comment.set_text_size(osmium::string_size_type(length) + 1);
+ comment.set_text_size(osmium::changeset_comment_size_type(length) + 1);
add_size(append_with_zero(text, osmium::memory::item_size_type(length)));
add_padding(true);
}
@@ -332,12 +331,12 @@ namespace osmium {
explicit ChangesetDiscussionBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
Builder(buffer, parent, sizeof(ChangesetDiscussion)) {
- new (&item()) ChangesetDiscussion();
+ new (&item()) ChangesetDiscussion{};
}
explicit ChangesetDiscussionBuilder(Builder& parent) :
Builder(parent.buffer(), &parent, sizeof(ChangesetDiscussion)) {
- new (&item()) ChangesetDiscussion();
+ new (&item()) ChangesetDiscussion{};
}
~ChangesetDiscussionBuilder() {
@@ -348,21 +347,23 @@ namespace osmium {
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);
+ 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));
+ osmium::ChangesetComment& comment = *m_comment;
m_comment = nullptr;
+ add_text(comment, text, std::strlen(text));
}
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());
+ osmium::ChangesetComment& comment = *m_comment;
m_comment = nullptr;
+ add_text(comment, text.c_str(), text.size());
}
}; // class ChangesetDiscussionBuilder
@@ -379,13 +380,13 @@ namespace osmium {
using type = TDerived;
- constexpr static const size_t min_size_for_user = osmium::memory::padded_length(sizeof(string_size_type) + 1);
+ constexpr static const std::size_t min_size_for_user = osmium::memory::padded_length(sizeof(string_size_type) + 1);
public:
explicit OSMObjectBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
Builder(buffer, parent, sizeof(T) + min_size_for_user) {
- new (&item()) T();
+ new (&item()) T{};
add_size(min_size_for_user);
std::fill_n(object().data() + sizeof(T), min_size_for_user, 0);
object().set_user_size(1);
@@ -403,6 +404,17 @@ namespace osmium {
}
/**
+ * Get a const reference to the object buing built.
+ *
+ * Note that this reference will be invalidated by every action
+ * on the builder that might make the buffer grow. This includes
+ * calls to set_user() and any time a new sub-builder is created.
+ */
+ const T& cobject() const noexcept {
+ return static_cast<const T&>(item());
+ }
+
+ /**
* Set user name.
*
* @param user Pointer to user name.
@@ -410,7 +422,7 @@ namespace osmium {
*/
TDerived& set_user(const char* user, const string_size_type length) {
const auto size_of_object = sizeof(T) + sizeof(string_size_type);
- assert(object().user_size() == 1 && (size() <= size_of_object + osmium::memory::padded_length(1))
+ assert(cobject().user_size() == 1 && (size() <= size_of_object + osmium::memory::padded_length(1))
&& "set_user() must be called at most once and before any sub-builders");
const auto available_space = min_size_for_user - sizeof(string_size_type) - 1;
if (length > available_space) {
@@ -558,13 +570,13 @@ namespace osmium {
using type = ChangesetBuilder;
- constexpr static const size_t min_size_for_user = osmium::memory::padded_length(1);
+ constexpr static const std::size_t min_size_for_user = osmium::memory::padded_length(1);
public:
explicit ChangesetBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
Builder(buffer, parent, sizeof(Changeset) + min_size_for_user) {
- new (&item()) Changeset();
+ new (&item()) Changeset{};
add_size(min_size_for_user);
std::fill_n(object().data() + sizeof(Changeset), min_size_for_user, 0);
object().set_user_size(1);
@@ -581,6 +593,17 @@ namespace osmium {
return static_cast<Changeset&>(item());
}
+ /**
+ * Get a const reference to the changeset buing built.
+ *
+ * Note that this reference will be invalidated by every action
+ * on the builder that might make the buffer grow. This includes
+ * calls to set_user() and any time a new sub-builder is created.
+ */
+ const Changeset& cobject() const noexcept {
+ return static_cast<const Changeset&>(item());
+ }
+
OSMIUM_FORWARD(set_id)
OSMIUM_FORWARD(set_uid)
OSMIUM_FORWARD(set_uid_from_signed)
@@ -608,7 +631,7 @@ namespace osmium {
* @param length Length of user name (without \0 termination).
*/
ChangesetBuilder& set_user(const char* user, const string_size_type length) {
- assert(object().user_size() == 1 && (size() <= sizeof(Changeset) + osmium::memory::padded_length(1))
+ assert(cobject().user_size() == 1 && (size() <= sizeof(Changeset) + osmium::memory::padded_length(1))
&& "set_user() must be called at most once and before any sub-builders");
const auto available_space = min_size_for_user - 1;
if (length > available_space) {
diff --git a/include/osmium/diff_handler.hpp b/include/osmium/diff_handler.hpp
index 19c75b8..d042edd 100644
--- a/include/osmium/diff_handler.hpp
+++ b/include/osmium/diff_handler.hpp
@@ -48,13 +48,13 @@ namespace osmium {
DiffHandler() = default;
- void node(const osmium::DiffNode&) const {
+ void node(const osmium::DiffNode&) const noexcept {
}
- void way(const osmium::DiffWay&) const {
+ void way(const osmium::DiffWay&) const noexcept {
}
- void relation(const osmium::DiffRelation&) const {
+ void relation(const osmium::DiffRelation&) const noexcept {
}
}; // class DiffHandler
diff --git a/include/osmium/diff_iterator.hpp b/include/osmium/diff_iterator.hpp
index 9a70399..c650858 100644
--- a/include/osmium/diff_iterator.hpp
+++ b/include/osmium/diff_iterator.hpp
@@ -66,8 +66,8 @@ namespace osmium {
void set_diff() const noexcept {
assert(m_curr != m_end);
- bool use_curr_for_prev = m_prev->type() != m_curr->type() || m_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();
+ const bool use_curr_for_prev = m_prev->type() != m_curr->type() || m_prev->id() != m_curr->id();
+ const bool use_curr_for_next = m_next == m_end || m_next->type() != m_curr->type() || m_next->id() != m_curr->id();
m_diff = std::move(osmium::DiffObject{
*(use_curr_for_prev ? m_curr : m_prev),
@@ -104,7 +104,7 @@ namespace osmium {
}
DiffIterator operator++(int) {
- DiffIterator tmp(*this);
+ DiffIterator tmp{*this};
operator++();
return tmp;
}
diff --git a/include/osmium/diff_visitor.hpp b/include/osmium/diff_visitor.hpp
index f796ac6..7ede0ee 100644
--- a/include/osmium/diff_visitor.hpp
+++ b/include/osmium/diff_visitor.hpp
@@ -56,7 +56,7 @@ namespace osmium {
handler.relation(static_cast<const osmium::DiffRelation&>(diff));
break;
default:
- throw osmium::unknown_type();
+ throw osmium::unknown_type{};
}
}
@@ -72,8 +72,8 @@ namespace osmium {
inline void apply_diff(TIterator it, TIterator end, THandlers&... handlers) {
using diff_iterator = osmium::DiffIterator<TIterator>;
- diff_iterator dit(it, end);
- diff_iterator dend(end, end);
+ diff_iterator dit{it, end};
+ diff_iterator dend{end, end};
for (; dit != dend; ++dit) {
detail::apply_diff_iterator_recurse(*dit, handlers...);
diff --git a/include/osmium/dynamic_handler.hpp b/include/osmium/dynamic_handler.hpp
index 9219ade..8e51852 100644
--- a/include/osmium/dynamic_handler.hpp
+++ b/include/osmium/dynamic_handler.hpp
@@ -54,8 +54,7 @@ namespace osmium {
public:
- virtual ~HandlerWrapperBase() {
- }
+ virtual ~HandlerWrapperBase() = default;
virtual void node(const osmium::Node&) {
}
@@ -115,7 +114,7 @@ auto _name_##_dispatch(THandler& handler, const osmium::_type_& object, long) ->
public:
template <typename... TArgs>
- HandlerWrapper(TArgs&&... args) :
+ explicit HandlerWrapper(TArgs&&... args) :
m_handler(std::forward<TArgs>(args)...) {
}
@@ -155,12 +154,12 @@ auto _name_##_dispatch(THandler& handler, const osmium::_type_& object, long) ->
public:
DynamicHandler() :
- m_impl(impl_ptr(new osmium::handler::detail::HandlerWrapperBase)) {
+ m_impl(new osmium::handler::detail::HandlerWrapperBase) {
}
template <typename THandler, typename... TArgs>
void set(TArgs&&... args) {
- m_impl = impl_ptr(new osmium::handler::detail::HandlerWrapper<THandler>(std::forward<TArgs>(args)...));
+ m_impl.reset(new osmium::handler::detail::HandlerWrapper<THandler>{std::forward<TArgs>(args)...});
}
void node(const osmium::Node& node) {
diff --git a/include/osmium/experimental/flex_reader.hpp b/include/osmium/experimental/flex_reader.hpp
index 08f426c..2f66ba4 100644
--- a/include/osmium/experimental/flex_reader.hpp
+++ b/include/osmium/experimental/flex_reader.hpp
@@ -78,7 +78,7 @@ namespace osmium {
{
m_location_handler.ignore_errors();
if (m_with_areas) {
- osmium::io::Reader reader(file, osmium::osm_entity_bits::relation);
+ osmium::io::Reader reader{file, osmium::osm_entity_bits::relation};
m_collector.read_relations(reader);
reader.close();
}
diff --git a/include/osmium/geom/factory.hpp b/include/osmium/geom/factory.hpp
index 39d1eac..85d0abd 100644
--- a/include/osmium/geom/factory.hpp
+++ b/include/osmium/geom/factory.hpp
@@ -165,6 +165,11 @@ namespace osmium {
public:
+ GeometryFactory<TGeomImpl, TProjection>() :
+ m_projection(),
+ m_impl(m_projection.epsg()) {
+ }
+
/**
* Constructor for default initialized projection.
*/
@@ -380,9 +385,9 @@ namespace osmium {
size_t num_rings = 0;
m_impl.multipolygon_start();
- for (auto it = area.cbegin(); it != area.cend(); ++it) {
- if (it->type() == osmium::item_type::outer_ring) {
- auto& ring = static_cast<const osmium::OuterRing&>(*it);
+ for (const auto& item : area) {
+ if (item.type() == osmium::item_type::outer_ring) {
+ auto& ring = static_cast<const osmium::OuterRing&>(item);
if (num_polygons > 0) {
m_impl.multipolygon_polygon_finish();
}
@@ -392,8 +397,8 @@ namespace osmium {
m_impl.multipolygon_outer_ring_finish();
++num_rings;
++num_polygons;
- } else if (it->type() == osmium::item_type::inner_ring) {
- auto& ring = static_cast<const osmium::InnerRing&>(*it);
+ } else if (item.type() == osmium::item_type::inner_ring) {
+ auto& ring = static_cast<const osmium::InnerRing&>(item);
m_impl.multipolygon_inner_ring_start();
add_points(ring);
m_impl.multipolygon_inner_ring_finish();
diff --git a/include/osmium/geom/geos.hpp b/include/osmium/geom/geos.hpp
index b472a38..2367b97 100644
--- a/include/osmium/geom/geos.hpp
+++ b/include/osmium/geom/geos.hpp
@@ -129,13 +129,13 @@ namespace osmium {
*/
OSMIUM_DEPRECATED explicit GEOSFactoryImpl(int /* srid */, int srid) :
m_precision_model(new geos::geom::PrecisionModel),
- m_our_geos_factory(new geos::geom::GeometryFactory(m_precision_model.get(), srid)),
+ m_our_geos_factory(new geos::geom::GeometryFactory{m_precision_model.get(), srid}),
m_geos_factory(m_our_geos_factory.get()) {
}
explicit GEOSFactoryImpl(int srid) :
m_precision_model(new geos::geom::PrecisionModel),
- m_our_geos_factory(new geos::geom::GeometryFactory(m_precision_model.get(), srid)),
+ m_our_geos_factory(new geos::geom::GeometryFactory{m_precision_model.get(), srid}),
m_geos_factory(m_our_geos_factory.get()) {
}
@@ -143,7 +143,7 @@ namespace osmium {
point_type make_point(const osmium::geom::Coordinates& xy) const {
try {
- return point_type(m_geos_factory->createPoint(geos::geom::Coordinate(xy.x, xy.y)));
+ return point_type{m_geos_factory->createPoint(geos::geom::Coordinate{xy.x, xy.y})};
} catch (const geos::util::GEOSException& e) {
THROW(osmium::geos_geometry_error(e.what()));
}
@@ -153,7 +153,7 @@ namespace osmium {
void linestring_start() {
try {
- m_coordinate_sequence.reset(m_geos_factory->getCoordinateSequenceFactory()->create(static_cast<size_t>(0), 2));
+ m_coordinate_sequence.reset(m_geos_factory->getCoordinateSequenceFactory()->create(static_cast<std::size_t>(0), 2));
} catch (const geos::util::GEOSException& e) {
THROW(osmium::geos_geometry_error(e.what()));
}
@@ -161,15 +161,15 @@ namespace osmium {
void linestring_add_location(const osmium::geom::Coordinates& xy) {
try {
- m_coordinate_sequence->add(geos::geom::Coordinate(xy.x, xy.y));
+ m_coordinate_sequence->add(geos::geom::Coordinate{xy.x, xy.y});
} catch (const geos::util::GEOSException& e) {
THROW(osmium::geos_geometry_error(e.what()));
}
}
- linestring_type linestring_finish(size_t /* num_points */) {
+ linestring_type linestring_finish(std::size_t /* num_points */) {
try {
- return linestring_type(m_geos_factory->createLineString(m_coordinate_sequence.release()));
+ return linestring_type{m_geos_factory->createLineString(m_coordinate_sequence.release())};
} catch (const geos::util::GEOSException& e) {
THROW(osmium::geos_geometry_error(e.what()));
}
@@ -201,7 +201,7 @@ namespace osmium {
void multipolygon_outer_ring_start() {
try {
- m_coordinate_sequence.reset(m_geos_factory->getCoordinateSequenceFactory()->create(static_cast<size_t>(0), 2));
+ m_coordinate_sequence.reset(m_geos_factory->getCoordinateSequenceFactory()->create(static_cast<std::size_t>(0), 2));
} catch (const geos::util::GEOSException& e) {
THROW(osmium::geos_geometry_error(e.what()));
}
@@ -217,7 +217,7 @@ namespace osmium {
void multipolygon_inner_ring_start() {
try {
- m_coordinate_sequence.reset(m_geos_factory->getCoordinateSequenceFactory()->create(static_cast<size_t>(0), 2));
+ m_coordinate_sequence.reset(m_geos_factory->getCoordinateSequenceFactory()->create(static_cast<std::size_t>(0), 2));
} catch (const geos::util::GEOSException& e) {
THROW(osmium::geos_geometry_error(e.what()));
}
@@ -233,7 +233,7 @@ namespace osmium {
void multipolygon_add_location(const osmium::geom::Coordinates& xy) {
try {
- m_coordinate_sequence->add(geos::geom::Coordinate(xy.x, xy.y));
+ m_coordinate_sequence->add(geos::geom::Coordinate{xy.x, xy.y});
} catch (const geos::util::GEOSException& e) {
THROW(osmium::geos_geometry_error(e.what()));
}
@@ -246,7 +246,7 @@ namespace osmium {
return p.release();
});
m_polygons.clear();
- return multipolygon_type(m_geos_factory->createMultiPolygon(polygons));
+ return multipolygon_type{m_geos_factory->createMultiPolygon(polygons)};
} catch (const geos::util::GEOSException& e) {
THROW(osmium::geos_geometry_error(e.what()));
}
diff --git a/include/osmium/geom/mercator_projection.hpp b/include/osmium/geom/mercator_projection.hpp
index a6b798a..5be84a4 100644
--- a/include/osmium/geom/mercator_projection.hpp
+++ b/include/osmium/geom/mercator_projection.hpp
@@ -138,6 +138,9 @@ namespace osmium {
public:
+ MercatorProjection() {
+ }
+
Coordinates operator()(osmium::Location location) const {
return Coordinates{detail::lon_to_x(location.lon()), detail::lat_to_y(location.lat())};
}
diff --git a/include/osmium/geom/projection.hpp b/include/osmium/geom/projection.hpp
index 132b068..de3bf90 100644
--- a/include/osmium/geom/projection.hpp
+++ b/include/osmium/geom/projection.hpp
@@ -111,10 +111,11 @@ namespace osmium {
*
* @throws osmium::projection_error if the projection fails
*/
+ // cppcheck-suppress passedByValue (because c is small and we want to change it)
inline Coordinates transform(const CRS& src, const CRS& dest, Coordinates c) {
const int result = pj_transform(src.get(), dest.get(), 1, 1, &c.x, &c.y, nullptr);
if (result != 0) {
- throw osmium::projection_error{std::string("projection failed: ") + pj_strerrno(result)};
+ throw osmium::projection_error{std::string{"projection failed: "} + pj_strerrno(result)};
}
return c;
}
diff --git a/include/osmium/geom/relations.hpp b/include/osmium/geom/relations.hpp
index f11ba51..c8d5caf 100644
--- a/include/osmium/geom/relations.hpp
+++ b/include/osmium/geom/relations.hpp
@@ -43,13 +43,23 @@ namespace osmium {
/**
* Check whether one geometry contains another.
*/
- inline bool contains(const osmium::Box& lhs, const osmium::Box& rhs) {
+ inline bool contains(const osmium::Box& lhs, const osmium::Box& rhs) noexcept {
return ((lhs.bottom_left().x() >= rhs.bottom_left().x()) &&
(lhs.top_right().x() <= rhs.top_right().x()) &&
(lhs.bottom_left().y() >= rhs.bottom_left().y()) &&
(lhs.top_right().y() <= rhs.top_right().y()));
}
+ /**
+ * Check whether one geometry overlaps another.
+ */
+ inline bool overlaps(const osmium::Box& lhs, const osmium::Box& rhs) noexcept {
+ return ((lhs.bottom_left().x() <= rhs.top_right().x()) &&
+ (lhs.bottom_left().y() <= rhs.top_right().y()) &&
+ (rhs.bottom_left().x() <= lhs.top_right().x()) &&
+ (rhs.bottom_left().y() <= lhs.top_right().y()));
+ }
+
} // namespace geom
} // namespace osmium
diff --git a/include/osmium/geom/tile.hpp b/include/osmium/geom/tile.hpp
index 55ea87b..6f07d8c 100644
--- a/include/osmium/geom/tile.hpp
+++ b/include/osmium/geom/tile.hpp
@@ -62,7 +62,7 @@ namespace osmium {
}
/**
- * Returns the width or hight of a tile in web mercator coordinates for
+ * Returns the width or height of a tile in web mercator coordinates for
* the given zoom level.
*/
inline constexpr double tile_extent_in_zoom(uint32_t zoom) noexcept {
@@ -108,7 +108,7 @@ namespace osmium {
uint32_t z;
/**
- * Create a tile with the given zoom level and x any y tile
+ * Create a tile with the given zoom level and x and y tile
* coordinates.
*
* The values are not checked for validity.
@@ -172,22 +172,30 @@ namespace osmium {
}; // struct Tile
/// Tiles are equal if all their attributes are equal.
- inline bool operator==(const Tile& lhs, const Tile& rhs) {
+ inline bool operator==(const Tile& lhs, const Tile& rhs) noexcept {
return lhs.z == rhs.z && lhs.x == rhs.x && lhs.y == rhs.y;
}
- inline bool operator!=(const Tile& lhs, const Tile& rhs) {
+ inline bool operator!=(const Tile& lhs, const Tile& rhs) noexcept {
return ! (lhs == rhs);
}
/**
* This defines an arbitrary order on tiles for use in std::map etc.
*/
- inline bool operator<(const Tile& lhs, const Tile& rhs) {
- if (lhs.z < rhs.z) return true;
- if (lhs.z > rhs.z) return false;
- if (lhs.x < rhs.x) return true;
- if (lhs.x > rhs.x) return false;
+ inline bool operator<(const Tile& lhs, const Tile& rhs) noexcept {
+ if (lhs.z < rhs.z) {
+ return true;
+ }
+ if (lhs.z > rhs.z) {
+ return false;
+ }
+ if (lhs.x < rhs.x) {
+ return true;
+ }
+ if (lhs.x > rhs.x) {
+ return false;
+ }
return lhs.y < rhs.y;
}
diff --git a/include/osmium/geom/wkb.hpp b/include/osmium/geom/wkb.hpp
index 39105fc..5299d45 100644
--- a/include/osmium/geom/wkb.hpp
+++ b/include/osmium/geom/wkb.hpp
@@ -108,19 +108,19 @@ namespace osmium {
}; // enum class wkb_byte_order_type
std::string m_data;
- uint32_t m_points {0};
+ uint32_t m_points = 0;
int m_srid;
wkb_type m_wkb_type;
out_type m_out_type;
- size_t m_linestring_size_offset = 0;
- size_t m_polygons = 0;
- size_t m_rings = 0;
- size_t m_multipolygon_size_offset = 0;
- size_t m_polygon_size_offset = 0;
- size_t m_ring_size_offset = 0;
+ std::size_t m_linestring_size_offset = 0;
+ std::size_t m_polygons = 0;
+ std::size_t m_rings = 0;
+ std::size_t m_multipolygon_size_offset = 0;
+ std::size_t m_polygon_size_offset = 0;
+ std::size_t m_ring_size_offset = 0;
- size_t header(std::string& str, wkbGeometryType type, bool add_length) const {
+ std::size_t header(std::string& str, wkbGeometryType type, bool add_length) const {
#if __BYTE_ORDER == __LITTLE_ENDIAN
str_push(str, wkb_byte_order_type::NDR);
#else
@@ -132,14 +132,14 @@ namespace osmium {
} else {
str_push(str, type);
}
- const size_t offset = str.size();
+ const std::size_t offset = str.size();
if (add_length) {
str_push(str, static_cast<uint32_t>(0));
}
return offset;
}
- void set_size(const size_t offset, const size_t size) {
+ void set_size(const std::size_t offset, const std::size_t size) {
uint32_t s = static_cast_with_assert<uint32_t>(size);
std::copy_n(reinterpret_cast<char*>(&s), sizeof(uint32_t), &m_data[offset]);
}
@@ -185,7 +185,7 @@ namespace osmium {
str_push(m_data, xy.y);
}
- linestring_type linestring_finish(size_t num_points) {
+ linestring_type linestring_finish(std::size_t num_points) {
set_size(m_linestring_size_offset, num_points);
std::string data;
diff --git a/include/osmium/handler/check_order.hpp b/include/osmium/handler/check_order.hpp
index 46411da..48a673b 100644
--- a/include/osmium/handler/check_order.hpp
+++ b/include/osmium/handler/check_order.hpp
@@ -39,6 +39,7 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/handler.hpp>
#include <osmium/osm/node.hpp>
+#include <osmium/osm/object_comparisons.hpp>
#include <osmium/osm/relation.hpp>
#include <osmium/osm/types.hpp>
#include <osmium/osm/way.hpp>
@@ -71,7 +72,9 @@ namespace osmium {
* Handler that can be used to check that an OSM file is ordered
* correctly. Ordered in this case refers to the usual order in OSM
* files: First nodes in the order of their IDs, then ways in the order
- * of their IDs, then relations in the order or their IDs.
+ * of their IDs, then relations in the order or their IDs. Negative
+ * IDs are ordered first then positive IDs, both ordered by absolute
+ * value.
*
* IDs have to be unique for each type. This check will fail for
* history files.
@@ -90,31 +93,31 @@ namespace osmium {
public:
void node(const osmium::Node& node) {
- if (m_max_way_id > 0) {
+ if (m_max_way_id > std::numeric_limits<osmium::object_id_type>::min()) {
throw out_of_order_error{"Found a node after a way.", node.id()};
}
- if (m_max_relation_id > 0) {
+ if (m_max_relation_id > std::numeric_limits<osmium::object_id_type>::min()) {
throw out_of_order_error{"Found a node after a relation.", node.id()};
}
if (m_max_node_id == node.id()) {
- throw out_of_order_error{"Node ID twice in input. Maybe you are using a history or changes file?", node.id()};
+ throw out_of_order_error{"Node ID twice in input. Maybe you are using a history or change file?", node.id()};
}
- if (m_max_node_id > node.id()) {
+ if (id_order{}(node.id(), m_max_node_id)) {
throw out_of_order_error{"Node IDs out of order.", node.id()};
}
m_max_node_id = node.id();
}
void way(const osmium::Way& way) {
- if (m_max_relation_id > 0) {
+ if (m_max_relation_id > std::numeric_limits<osmium::object_id_type>::min()) {
throw out_of_order_error{"Found a way after a relation.", way.id()};
}
if (m_max_way_id == way.id()) {
- throw out_of_order_error{"Way ID twice in input. Maybe you are using a history or changes file?", way.id()};
+ throw out_of_order_error{"Way ID twice in input. Maybe you are using a history or change file?", way.id()};
}
- if (m_max_way_id > way.id()) {
+ if (id_order{}(way.id(), m_max_way_id)) {
throw out_of_order_error{"Way IDs out of order.", way.id()};
}
m_max_way_id = way.id();
@@ -122,9 +125,9 @@ namespace osmium {
void relation(const osmium::Relation& relation) {
if (m_max_relation_id == relation.id()) {
- throw out_of_order_error{"Relation ID twice in input. Maybe you are using a history or changes file?", relation.id()};
+ throw out_of_order_error{"Relation ID twice in input. Maybe you are using a history or change file?", relation.id()};
}
- if (m_max_relation_id > relation.id()) {
+ if (id_order{}(relation.id(), m_max_relation_id)) {
throw out_of_order_error{"Relation IDs out of order.", relation.id()};
}
m_max_relation_id = relation.id();
diff --git a/include/osmium/handler/disk_store.hpp b/include/osmium/handler/disk_store.hpp
index 882d7a1..da1119d 100644
--- a/include/osmium/handler/disk_store.hpp
+++ b/include/osmium/handler/disk_store.hpp
@@ -60,9 +60,9 @@ namespace osmium {
*/
class DiskStore : public osmium::handler::Handler {
- using offset_index_type = osmium::index::map::Map<unsigned_object_id_type, size_t>;
+ using offset_index_type = osmium::index::map::Map<unsigned_object_id_type, std::size_t>;
- size_t m_offset = 0;
+ std::size_t m_offset = 0;
int m_data_fd;
offset_index_type& m_node_index;
diff --git a/include/osmium/handler/dump.hpp b/include/osmium/handler/dump.hpp
index b3f2ed7..9c2c5c6 100644
--- a/include/osmium/handler/dump.hpp
+++ b/include/osmium/handler/dump.hpp
@@ -108,7 +108,7 @@ namespace osmium {
<< (object.visible() ? "yes" : "no")
<< "\n";
- Dump dump(*m_out, m_with_size, m_prefix + " ");
+ Dump dump{*m_out, m_with_size, m_prefix + " "};
osmium::apply(object.cbegin(), object.cend(), dump);
}
@@ -281,7 +281,7 @@ namespace osmium {
*m_out << "\n";
- Dump dump(*m_out, m_with_size, m_prefix + " ");
+ Dump dump{*m_out, m_with_size, m_prefix + " "};
osmium::apply(changeset.cbegin(), changeset.cend(), dump);
}
diff --git a/include/osmium/handler/node_locations_for_ways.hpp b/include/osmium/handler/node_locations_for_ways.hpp
index 84f77d1..ff3fbe9 100644
--- a/include/osmium/handler/node_locations_for_ways.hpp
+++ b/include/osmium/handler/node_locations_for_ways.hpp
@@ -64,9 +64,11 @@ namespace osmium {
template <typename TStoragePosIDs, typename TStorageNegIDs = dummy_type>
class NodeLocationsForWays : public osmium::handler::Handler {
- static_assert(std::is_base_of<osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>, TStoragePosIDs>::value, "Index class must be derived from osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>");
+ template <typename T>
+ using based_on_map = std::is_base_of<osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>, T>;
- static_assert(std::is_base_of<osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>, TStorageNegIDs>::value, "Index class must be derived from osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>");
+ static_assert(based_on_map<TStoragePosIDs>::value, "Index class must be derived from osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>");
+ static_assert(based_on_map<TStorageNegIDs>::value, "Index class must be derived from osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>");
public:
@@ -81,11 +83,11 @@ namespace osmium {
/// Object that handles the actual storage of the node locations (with negative IDs).
TStorageNegIDs& m_storage_neg;
- osmium::unsigned_object_id_type m_last_id{0};
+ osmium::unsigned_object_id_type m_last_id = 0;
- bool m_ignore_errors{false};
+ bool m_ignore_errors = false;
- bool m_must_sort{false};
+ bool m_must_sort = false;
// It is okay to have this static dummy instance, even when using several threads,
// because it is read-only.
@@ -123,7 +125,7 @@ namespace osmium {
}
m_last_id = node.positive_id();
- const osmium::object_id_type id = node.id();
+ const auto id = node.id();
if (id >= 0) {
m_storage_pos.set(static_cast<osmium::unsigned_object_id_type>( id), node.location());
} else {
diff --git a/include/osmium/index/detail/create_map_with_fd.hpp b/include/osmium/index/detail/create_map_with_fd.hpp
index e724f18..745a358 100644
--- a/include/osmium/index/detail/create_map_with_fd.hpp
+++ b/include/osmium/index/detail/create_map_with_fd.hpp
@@ -50,15 +50,15 @@ namespace osmium {
template <typename T>
inline T* create_map_with_fd(const std::vector<std::string>& config) {
if (config.size() == 1) {
- return new T();
+ return new T{};
}
assert(config.size() > 1);
const std::string& filename = config[1];
const 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 + "': " + std::strerror(errno));
+ throw std::runtime_error{std::string{"can't open file '"} + filename + "': " + std::strerror(errno)};
}
- return new T(fd);
+ return new T{fd};
}
} // namespace detail
diff --git a/include/osmium/index/detail/mmap_vector_file.hpp b/include/osmium/index/detail/mmap_vector_file.hpp
index 6ba7e2e..ff0ca54 100644
--- a/include/osmium/index/detail/mmap_vector_file.hpp
+++ b/include/osmium/index/detail/mmap_vector_file.hpp
@@ -53,11 +53,11 @@ namespace osmium {
template <typename T>
class mmap_vector_file : public mmap_vector_base<T> {
- size_t filesize(int fd) const {
- const size_t size = osmium::util::file_size(fd);
+ std::size_t filesize(int fd) const {
+ const auto size = osmium::util::file_size(fd);
if (size % sizeof(T) != 0) {
- throw std::runtime_error("Index file has wrong size (must be multiple of " + std::to_string(sizeof(T)) + ").");
+ throw std::runtime_error{"Index file has wrong size (must be multiple of " + std::to_string(sizeof(T)) + ")."};
}
return size / sizeof(T);
diff --git a/include/osmium/index/detail/tmpfile.hpp b/include/osmium/index/detail/tmpfile.hpp
index 9da7b70..ce9b194 100644
--- a/include/osmium/index/detail/tmpfile.hpp
+++ b/include/osmium/index/detail/tmpfile.hpp
@@ -50,7 +50,7 @@ namespace osmium {
inline int create_tmp_file() {
FILE* file = ::tmpfile();
if (!file) {
- throw std::system_error(errno, std::system_category(), "tempfile failed");
+ throw std::system_error{errno, std::system_category(), "tempfile failed"};
}
return fileno(file);
}
diff --git a/include/osmium/index/detail/vector_map.hpp b/include/osmium/index/detail/vector_map.hpp
index ed0f760..0eb49d5 100644
--- a/include/osmium/index/detail/vector_map.hpp
+++ b/include/osmium/index/detail/vector_map.hpp
@@ -35,7 +35,6 @@ DEALINGS IN THE SOFTWARE.
#include <algorithm>
#include <cstddef>
-#include <stdexcept>
#include <utility>
#include <osmium/index/index.hpp>
@@ -70,7 +69,7 @@ namespace osmium {
~VectorBasedDenseMap() noexcept final = default;
- void reserve(const size_t size) final {
+ void reserve(const std::size_t size) final {
m_vector.reserve(size);
}
@@ -99,15 +98,15 @@ namespace osmium {
return m_vector[id];
}
- size_t size() const final {
+ std::size_t size() const final {
return m_vector.size();
}
- size_t byte_size() const {
+ std::size_t byte_size() const {
return m_vector.size() * sizeof(element_type);
}
- size_t used_memory() const final {
+ std::size_t used_memory() const final {
return sizeof(TValue) * size();
}
@@ -205,15 +204,15 @@ namespace osmium {
return result->second;
}
- size_t size() const final {
+ std::size_t size() const final {
return m_vector.size();
}
- size_t byte_size() const {
+ std::size_t byte_size() const {
return m_vector.size() * sizeof(element_type);
}
- size_t used_memory() const final {
+ std::size_t used_memory() const final {
return sizeof(element_type) * size();
}
diff --git a/include/osmium/index/id_set.hpp b/include/osmium/index/id_set.hpp
index 9f36314..d86973d 100644
--- a/include/osmium/index/id_set.hpp
+++ b/include/osmium/index/id_set.hpp
@@ -35,10 +35,11 @@ DEALINGS IN THE SOFTWARE.
#include <algorithm>
#include <cassert>
+#include <cstddef>
#include <cstring>
+#include <iterator>
#include <memory>
#include <type_traits>
-#include <unordered_set>
#include <vector>
#include <osmium/osm/item_type.hpp>
@@ -57,8 +58,7 @@ namespace osmium {
public:
- virtual ~IdSet() {
- }
+ virtual ~IdSet() = default;
/**
* Add the given Id to the set.
@@ -80,6 +80,11 @@ namespace osmium {
*/
virtual void clear() = 0;
+ /**
+ * Get an estimate of the amount of memory used for the set.
+ */
+ virtual std::size_t used_memory() const noexcept = 0;
+
}; // class IdSet
template <typename T>
@@ -139,7 +144,7 @@ namespace osmium {
}
IdSetDenseIterator<T> operator++(int) noexcept {
- IdSetDenseIterator<T> tmp(*this);
+ IdSetDenseIterator<T> tmp{*this};
operator++();
return tmp;
}
@@ -178,17 +183,17 @@ namespace osmium {
// which would mean less (but larger) memory allocations. For
// relations Ids it could be smaller, because they would all fit
// into a smaller allocation.
- constexpr static const size_t chunk_bits = 22;
- constexpr static const size_t chunk_size = 1 << chunk_bits;
+ constexpr static const std::size_t chunk_bits = 22;
+ constexpr static const std::size_t chunk_size = 1 << chunk_bits;
std::vector<std::unique_ptr<unsigned char[]>> m_data;
T m_size = 0;
- static size_t chunk_id(T id) noexcept {
+ static std::size_t chunk_id(T id) noexcept {
return id >> (chunk_bits + 3);
}
- static size_t offset(T id) noexcept {
+ static std::size_t offset(T id) noexcept {
return (id >> 3) & ((1 << chunk_bits) - 1);
}
@@ -244,7 +249,7 @@ namespace osmium {
*
* @param id The Id to set.
*/
- void set(T id) override final {
+ void set(T id) final {
(void)check_and_set(id);
}
@@ -267,7 +272,7 @@ namespace osmium {
*
* @param id The Id to check.
*/
- bool get(T id) const noexcept override final {
+ bool get(T id) const noexcept final {
if (chunk_id(id) >= m_data.size()) {
return false;
}
@@ -281,7 +286,7 @@ namespace osmium {
/**
* Is the set empty?
*/
- bool empty() const noexcept override final {
+ bool empty() const noexcept final {
return m_size == 0;
}
@@ -295,17 +300,21 @@ namespace osmium {
/**
* Clear the set.
*/
- void clear() override final {
+ void clear() final {
m_data.clear();
m_size = 0;
}
+ std::size_t used_memory() const noexcept final {
+ return m_data.size() * chunk_size;
+ }
+
IdSetDenseIterator<T> begin() const {
- return IdSetDenseIterator<T>{this, 0, last()};
+ return {this, 0, last()};
}
IdSetDenseIterator<T> end() const {
- return IdSetDenseIterator<T>{this, last(), last()};
+ return {this, last(), last()};
}
}; // class IdSetDense
@@ -324,7 +333,7 @@ namespace osmium {
/**
* Add the given Id to the set.
*/
- void set(T id) override final {
+ void set(T id) final {
m_data.push_back(id);
}
@@ -333,7 +342,7 @@ namespace osmium {
*
* @param id The Id to check.
*/
- bool get(T id) const noexcept override final {
+ bool get(T id) const noexcept final {
const auto it = std::find(m_data.cbegin(), m_data.cend(), id);
return it != m_data.cend();
}
@@ -355,14 +364,14 @@ namespace osmium {
/**
* Is the set empty?
*/
- bool empty() const noexcept override final {
+ bool empty() const noexcept final {
return m_data.empty();
}
/**
* Clear the set.
*/
- void clear() override final {
+ void clear() final {
m_data.clear();
}
@@ -383,10 +392,14 @@ namespace osmium {
* @pre You must have called sort_unique() before calling this
* or be sure there are no duplicates.
*/
- size_t size() const noexcept {
+ std::size_t size() const noexcept {
return m_data.size();
}
+ std::size_t used_memory() const noexcept final {
+ return m_data.capacity() * sizeof(T);
+ }
+
/// Iterator type. There is no non-const iterator.
using const_iterator = typename std::vector<T>::const_iterator;
@@ -408,7 +421,7 @@ namespace osmium {
}; // class IdSetSmall
- /// @deprecated Use nrw_array helper class instead.
+ /// @deprecated Use nwr_array helper class instead.
template <template<typename> class IdSetType>
class NWRIdSet {
diff --git a/include/osmium/index/index.hpp b/include/osmium/index/index.hpp
index 565009c..325b42f 100644
--- a/include/osmium/index/index.hpp
+++ b/include/osmium/index/index.hpp
@@ -34,12 +34,11 @@ DEALINGS IN THE SOFTWARE.
*/
#include <cstddef>
+#include <cstdint>
#include <limits>
#include <stdexcept>
#include <string>
-#include <osmium/util/compatibility.hpp>
-
namespace osmium {
/**
diff --git a/include/osmium/index/map.hpp b/include/osmium/index/map.hpp
index bcda589..e0f9aec 100644
--- a/include/osmium/index/map.hpp
+++ b/include/osmium/index/map.hpp
@@ -43,7 +43,6 @@ DEALINGS IN THE SOFTWARE.
#include <type_traits>
#include <vector>
-#include <osmium/util/compatibility.hpp>
#include <osmium/util/string.hpp>
namespace osmium {
@@ -181,14 +180,14 @@ namespace osmium {
// 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*/) {
- throw std::runtime_error("can't dump as list");
+ throw std::runtime_error{"can't dump as list"};
}
// This function can 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*/) {
- throw std::runtime_error("can't dump as array");
+ throw std::runtime_error{"can't dump as array"};
}
}; // class Map
@@ -245,13 +244,13 @@ namespace osmium {
}
std::unique_ptr<map_type> create_map(const std::string& config_string) const {
- std::vector<std::string> config = osmium::split_string(config_string, ',');
+ std::vector<std::string> config{osmium::split_string(config_string, ',')};
if (config.empty()) {
throw map_factory_error{"Need non-empty map type name"};
}
- auto it = m_callbacks.find(config[0]);
+ const auto it = m_callbacks.find(config[0]);
if (it != m_callbacks.end()) {
return std::unique_ptr<map_type>((it->second)(config));
}
diff --git a/include/osmium/index/map/all.hpp b/include/osmium/index/map/all.hpp
index 1e4827f..f196ffe 100644
--- a/include/osmium/index/map/all.hpp
+++ b/include/osmium/index/map/all.hpp
@@ -37,6 +37,7 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/index/map/dense_mem_array.hpp> // IWYU pragma: keep
#include <osmium/index/map/dense_mmap_array.hpp> // IWYU pragma: keep
#include <osmium/index/map/dummy.hpp> // IWYU pragma: keep
+#include <osmium/index/map/flex_mem.hpp> // IWYU pragma: keep
#include <osmium/index/map/sparse_file_array.hpp> // IWYU pragma: keep
#include <osmium/index/map/sparse_mem_array.hpp> // IWYU pragma: keep
#include <osmium/index/map/sparse_mem_map.hpp> // IWYU pragma: keep
diff --git a/include/osmium/index/map/flex_mem.hpp b/include/osmium/index/map/flex_mem.hpp
new file mode 100644
index 0000000..db474e7
--- /dev/null
+++ b/include/osmium/index/map/flex_mem.hpp
@@ -0,0 +1,285 @@
+#ifndef OSMIUM_INDEX_MAP_FLEX_MEM_HPP
+#define OSMIUM_INDEX_MAP_FLEX_MEM_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2017 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <utility>
+#include <vector>
+
+#include <osmium/index/map.hpp>
+#include <osmium/index/index.hpp>
+
+#define OSMIUM_HAS_INDEX_MAP_FLEX_MEM
+
+namespace osmium {
+
+ namespace index {
+
+ namespace map {
+
+ /**
+ * This is an autoscaling index that works well with small and
+ * large input data. All data will be held in memory. For small
+ * input data a sparse array will be used, if this becomes
+ * inefficient, the class will switch automatically to a dense
+ * index.
+ */
+ template <typename TId, typename TValue>
+ class FlexMem : public osmium::index::map::Map<TId, TValue> {
+
+ // This value is based on benchmarks with a planet file and
+ // some smaller files.
+ enum constant_bits {
+ bits = 16
+ };
+
+ enum constant_block_size : uint64_t {
+ block_size = 1ll << bits
+ };
+
+ // Minimum number of entries in the sparse index before we
+ // are considering switching to a dense index.
+ enum constant_min_dense_entries : int64_t {
+ min_dense_entries = 0xffffff
+ };
+
+ // When more than a third of all Ids are in the index, we
+ // switch to the dense index. This is a compromise between
+ // the best memory efficiency (which we would get at a factor
+ // of 2) and the performance (dense index is much faster then
+ // the sparse index).
+ enum constant_density_factor {
+ density_factor = 3
+ };
+
+ // An entry in the sparse index
+ struct entry {
+ uint64_t id;
+ TValue value;
+
+ entry(uint64_t i, TValue v) :
+ id(i),
+ value(v) {
+ }
+
+ bool operator<(const entry other) const noexcept {
+ return id < other.id;
+ }
+ };
+
+ std::vector<entry> m_sparse_entries;
+
+ std::vector<std::vector<TValue>> m_dense_blocks;
+
+ // The maximum Id that was seen yet. Only set in sparse mode.
+ uint64_t m_max_id = 0;
+
+ // Set to false in sparse mode and to true in dense mode.
+ bool m_dense;
+
+ static uint64_t block(const uint64_t id) noexcept {
+ return id >> bits;
+ }
+
+ static uint64_t offset(const uint64_t id) noexcept {
+ return id & (block_size - 1);
+ }
+
+ // Assure that the block with the given number exists. Create
+ // it if needed.
+ void assure_block(const uint64_t num) {
+ if (num >= m_dense_blocks.size()) {
+ m_dense_blocks.resize(num + 1);
+ }
+ if (m_dense_blocks[num].empty()) {
+ m_dense_blocks[num].assign(block_size, osmium::index::empty_value<TValue>());
+ }
+ }
+
+ void set_sparse(const uint64_t id, const TValue value) {
+ m_sparse_entries.emplace_back(id, value);
+ if (id > m_max_id) {
+ m_max_id = id;
+
+ if (m_sparse_entries.size() >= min_dense_entries) {
+ if (m_max_id < m_sparse_entries.size() * density_factor) {
+ switch_to_dense();
+ }
+ }
+ }
+ }
+
+ TValue get_sparse(const uint64_t id) const noexcept {
+ const auto it = std::lower_bound(m_sparse_entries.begin(),
+ m_sparse_entries.end(),
+ entry{id, osmium::index::empty_value<TValue>()});
+ if (it == m_sparse_entries.end() || it->id != id) {
+ return osmium::index::empty_value<TValue>();
+ }
+ return it->value;
+ }
+
+ void set_dense(const uint64_t id, const TValue value) {
+ assure_block(block(id));
+ m_dense_blocks[block(id)][offset(id)] = value;
+ }
+
+ TValue get_dense(const uint64_t id) const noexcept {
+ if (m_dense_blocks.size() <= block(id) || m_dense_blocks[block(id)].empty()) {
+ return osmium::index::empty_value<TValue>();
+ }
+ return m_dense_blocks[block(id)][offset(id)];
+ }
+
+ public:
+
+ /**
+ * Create FlexMem index.
+ *
+ * @param use_dense Usually FlexMem indexes start out as sparse
+ * indexes and will switch to dense when they
+ * think it is better. Set this to force dense
+ * indexing from the start. This is usually
+ * only useful for testing.
+ */
+ explicit FlexMem(bool use_dense = false) :
+ m_dense(use_dense) {
+ }
+
+ ~FlexMem() noexcept final = default;
+
+ bool is_dense() const noexcept {
+ return m_dense;
+ }
+
+ std::size_t size() const noexcept final {
+ if (m_dense) {
+ return m_dense_blocks.size() * block_size;
+ }
+ return m_sparse_entries.size();
+ }
+
+ std::size_t used_memory() const noexcept final {
+ return sizeof(FlexMem) +
+ m_sparse_entries.size() * sizeof(entry) +
+ m_dense_blocks.size() * (block_size * sizeof(TValue) + sizeof(std::vector<TValue>));
+ }
+
+ void set(const TId id, const TValue value) final {
+ if (m_dense) {
+ set_dense(id, value);
+ } else {
+ set_sparse(id, value);
+ }
+ }
+
+ TValue get_noexcept(const TId id) const noexcept final {
+ if (m_dense) {
+ return get_dense(id);
+ }
+ return get_sparse(id);
+ }
+
+ TValue get(const TId id) const final {
+ const auto value = get_noexcept(id);
+ if (value == osmium::index::empty_value<TValue>()) {
+ throw osmium::not_found{id};
+ }
+ return value;
+ }
+
+ void clear() final {
+ m_sparse_entries.clear();
+ m_sparse_entries.shrink_to_fit();
+ m_dense_blocks.clear();
+ m_dense_blocks.shrink_to_fit();
+ m_max_id = 0;
+ m_dense = false;
+ }
+
+ void sort() final {
+ std::sort(m_sparse_entries.begin(), m_sparse_entries.end());
+ }
+
+ /**
+ * Switch from using a sparse to a dense index. Usually you
+ * do not need to call this, because the FlexMem class will
+ * do this automatically if it thinks the dense index is more
+ * efficient.
+ *
+ * Does nothing if the index is already in dense mode.
+ */
+ void switch_to_dense() {
+ if (m_dense) {
+ return;
+ }
+ for (const auto entry : m_sparse_entries) {
+ set_dense(entry.id, entry.value);
+ }
+ m_sparse_entries.clear();
+ m_sparse_entries.shrink_to_fit();
+ m_max_id = 0;
+ m_dense = true;
+ }
+
+ std::pair<std::size_t, std::size_t> stats() const noexcept {
+ std::size_t used_blocks = 0;
+ std::size_t empty_blocks = 0;
+
+ for (const auto& block : m_dense_blocks) {
+ if (block.empty()) {
+ ++empty_blocks;
+ } else {
+ ++used_blocks;
+ }
+ }
+
+ return std::make_pair(used_blocks, empty_blocks);
+ }
+
+ }; // class FlexMem
+
+ } // namespace map
+
+ } // namespace index
+
+} // namespace osmium
+
+#ifdef OSMIUM_WANT_NODE_LOCATION_MAPS
+ REGISTER_MAP(osmium::unsigned_object_id_type, osmium::Location, osmium::index::map::FlexMem, flex_mem)
+#endif
+
+#endif // OSMIUM_INDEX_MAP_FLEX_MEM_HPP
diff --git a/include/osmium/index/node_locations_map.hpp b/include/osmium/index/node_locations_map.hpp
index 4b096c4..0e78de1 100644
--- a/include/osmium/index/node_locations_map.hpp
+++ b/include/osmium/index/node_locations_map.hpp
@@ -69,4 +69,8 @@ DEALINGS IN THE SOFTWARE.
REGISTER_MAP(osmium::unsigned_object_id_type, osmium::Location, osmium::index::map::SparseMmapArray, sparse_mmap_array)
#endif
+#ifdef OSMIUM_HAS_INDEX_MAP_FLEX_MEM
+ REGISTER_MAP(osmium::unsigned_object_id_type, osmium::Location, osmium::index::map::FlexMem, flex_mem)
+#endif
+
#endif // OSMIUM_INDEX_NODE_LOCATIONS_MAP_HPP
diff --git a/include/osmium/index/relations_map.hpp b/include/osmium/index/relations_map.hpp
index bb9f5a7..bc26719 100644
--- a/include/osmium/index/relations_map.hpp
+++ b/include/osmium/index/relations_map.hpp
@@ -35,10 +35,14 @@ DEALINGS IN THE SOFTWARE.
#include <algorithm>
#include <cassert>
+#include <cstddef>
#include <cstdint>
#include <tuple>
+#include <type_traits>
+#include <utility>
#include <vector>
+#include <osmium/osm/item_type.hpp>
#include <osmium/osm/relation.hpp>
#include <osmium/osm/types.hpp>
@@ -125,11 +129,11 @@ namespace osmium {
return m_map.empty();
}
- size_t size() const noexcept {
+ std::size_t size() const noexcept {
return m_map.size();
}
- void reserve(size_t size) {
+ void reserve(std::size_t size) {
m_map.reserve(size);
}
@@ -172,7 +176,7 @@ namespace osmium {
map_type m_map;
- RelationsMapIndex(map_type&& map) :
+ explicit RelationsMapIndex(map_type&& map) :
m_map(std::move(map)) {
}
@@ -246,7 +250,7 @@ namespace osmium {
*
* Complexity: Constant.
*/
- size_t size() const noexcept {
+ std::size_t size() const noexcept {
return m_map.size();
}
@@ -288,7 +292,7 @@ namespace osmium {
*
* Complexity: Constant.
*/
- size_t size() const noexcept {
+ std::size_t size() const noexcept {
return m_member_to_parent.size();
}
@@ -355,7 +359,7 @@ namespace osmium {
*
* Complexity: Constant.
*/
- size_t size() const noexcept {
+ std::size_t size() const noexcept {
assert(m_valid && "You can't use the RelationsMap any more after calling build_index()");
return m_map.size();
}
diff --git a/include/osmium/io/bzip2_compression.hpp b/include/osmium/io/bzip2_compression.hpp
index 84b2825..094062c 100644
--- a/include/osmium/io/bzip2_compression.hpp
+++ b/include/osmium/io/bzip2_compression.hpp
@@ -85,7 +85,7 @@ namespace osmium {
namespace detail {
OSMIUM_NORETURN inline void throw_bzip2_error(BZFILE* bzfile, const char* msg, int bzlib_error = 0) {
- std::string error("bzip2 error: ");
+ std::string error{"bzip2 error: "};
error += msg;
error += ": ";
int errnum = bzlib_error;
@@ -94,7 +94,7 @@ namespace osmium {
} else {
error += ::BZ2_bzerror(bzfile, &errnum);
}
- throw osmium::bzip2_error(error, errnum);
+ throw osmium::bzip2_error{error, errnum};
}
} // namespace detail
@@ -143,7 +143,7 @@ namespace osmium {
osmium::io::detail::reliable_fsync(::fileno(m_file));
}
if (fclose(m_file) != 0) {
- throw std::system_error(errno, std::system_category(), "Close failed");
+ throw std::system_error{errno, std::system_category(), "Close failed"};
}
}
if (error != BZ_OK) {
@@ -187,7 +187,7 @@ namespace osmium {
if (!m_stream_end) {
buffer.resize(osmium::io::Decompressor::input_buffer_size);
int error;
- int nread = ::BZ2_bzRead(&error, m_bzfile, const_cast<char*>(buffer.data()), static_cast_with_assert<int>(buffer.size()));
+ const int nread = ::BZ2_bzRead(&error, m_bzfile, const_cast<char*>(buffer.data()), static_cast_with_assert<int>(buffer.size()));
if (error != BZ_OK && error != BZ_STREAM_END) {
detail::throw_bzip2_error(m_bzfile, "read failed", error);
}
@@ -227,7 +227,7 @@ namespace osmium {
m_bzfile = nullptr;
if (m_file) {
if (fclose(m_file) != 0) {
- throw std::system_error(errno, std::system_category(), "Close failed");
+ throw std::system_error{errno, std::system_category(), "Close failed"};
}
}
if (error != BZ_OK) {
@@ -252,10 +252,10 @@ namespace osmium {
m_bzstream() {
m_bzstream.next_in = const_cast<char*>(buffer);
m_bzstream.avail_in = static_cast_with_assert<unsigned int>(size);
- int result = BZ2_bzDecompressInit(&m_bzstream, 0, 0);
+ const int result = BZ2_bzDecompressInit(&m_bzstream, 0, 0);
if (result != BZ_OK) {
- std::string message("bzip2 error: decompression init failed: ");
- throw bzip2_error(message, result);
+ std::string message{"bzip2 error: decompression init failed: "};
+ throw bzip2_error{message, result};
}
}
@@ -275,7 +275,7 @@ namespace osmium {
output.resize(buffer_size);
m_bzstream.next_out = const_cast<char*>(output.data());
m_bzstream.avail_out = buffer_size;
- int result = BZ2_bzDecompress(&m_bzstream);
+ const int result = BZ2_bzDecompress(&m_bzstream);
if (result != BZ_OK) {
m_buffer = nullptr;
@@ -283,8 +283,8 @@ namespace osmium {
}
if (result != BZ_OK && result != BZ_STREAM_END) {
- std::string message("bzip2 error: decompress failed: ");
- throw bzip2_error(message, result);
+ std::string message{"bzip2 error: decompress failed: "};
+ throw bzip2_error{message, result};
}
output.resize(static_cast<unsigned long>(m_bzstream.next_out - output.data()));
@@ -304,9 +304,9 @@ namespace osmium {
// we want the register_compression() function to run, setting
// the variable is only a side-effect, it will never be used
const bool registered_bzip2_compression = osmium::io::CompressionFactory::instance().register_compression(osmium::io::file_compression::bzip2,
- [](int fd, fsync sync) { return new osmium::io::Bzip2Compressor(fd, sync); },
- [](int fd) { return new osmium::io::Bzip2Decompressor(fd); },
- [](const char* buffer, size_t size) { return new osmium::io::Bzip2BufferDecompressor(buffer, size); }
+ [](int fd, fsync sync) { return new osmium::io::Bzip2Compressor{fd, sync}; },
+ [](int fd) { return new osmium::io::Bzip2Decompressor{fd}; },
+ [](const char* buffer, size_t size) { return new osmium::io::Bzip2BufferDecompressor{buffer, size}; }
);
// dummy function to silence the unused variable warning from above
diff --git a/include/osmium/io/compression.hpp b/include/osmium/io/compression.hpp
index 68011e8..c3b8706 100644
--- a/include/osmium/io/compression.hpp
+++ b/include/osmium/io/compression.hpp
@@ -54,7 +54,6 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/io/error.hpp>
#include <osmium/io/file_compression.hpp>
#include <osmium/io/writer_options.hpp>
-#include <osmium/util/compatibility.hpp>
#include <osmium/util/file.hpp>
namespace osmium {
@@ -77,8 +76,7 @@ namespace osmium {
m_fsync(sync) {
}
- virtual ~Compressor() noexcept {
- }
+ virtual ~Compressor() noexcept = default;
virtual void write(const std::string& data) = 0;
@@ -88,8 +86,8 @@ namespace osmium {
class Decompressor {
- std::atomic<size_t> m_file_size {0};
- std::atomic<size_t> m_offset {0};
+ std::atomic<std::size_t> m_file_size{0};
+ std::atomic<std::size_t> m_offset{0};
public:
@@ -103,26 +101,25 @@ namespace osmium {
Decompressor(Decompressor&&) = delete;
Decompressor& operator=(Decompressor&&) = delete;
- virtual ~Decompressor() noexcept {
- }
+ virtual ~Decompressor() noexcept = default;
virtual std::string read() = 0;
virtual void close() = 0;
- size_t file_size() const noexcept {
+ std::size_t file_size() const noexcept {
return m_file_size;
}
- void set_file_size(size_t size) noexcept {
+ void set_file_size(std::size_t size) noexcept {
m_file_size = size;
}
- size_t offset() const noexcept {
+ std::size_t offset() const noexcept {
return m_offset;
}
- void set_offset(size_t offset) noexcept {
+ void set_offset(std::size_t offset) noexcept {
m_offset = offset;
}
@@ -141,7 +138,7 @@ namespace osmium {
using create_compressor_type = std::function<osmium::io::Compressor*(int, fsync)>;
using create_decompressor_type_fd = std::function<osmium::io::Decompressor*(int)>;
- using create_decompressor_type_buffer = std::function<osmium::io::Decompressor*(const char*, size_t)>;
+ using create_decompressor_type_buffer = std::function<osmium::io::Decompressor*(const char*, std::size_t)>;
private:
@@ -187,10 +184,10 @@ namespace osmium {
create_decompressor_type_fd create_decompressor_fd,
create_decompressor_type_buffer create_decompressor_buffer) {
- compression_map_type::value_type cc(compression,
+ compression_map_type::value_type cc{compression,
std::make_tuple(create_compressor,
create_decompressor_fd,
- create_decompressor_buffer));
+ create_decompressor_buffer)};
return m_callbacks.insert(cc).second;
}
@@ -208,7 +205,7 @@ namespace osmium {
return p;
}
- std::unique_ptr<osmium::io::Decompressor> create_decompressor(osmium::io::file_compression compression, const char* buffer, size_t size) const {
+ std::unique_ptr<osmium::io::Decompressor> create_decompressor(osmium::io::file_compression compression, const char* buffer, std::size_t size) const {
const auto callbacks = find_callbacks(compression);
return std::unique_ptr<osmium::io::Decompressor>(std::get<2>(callbacks)(buffer, size));
}
@@ -240,7 +237,7 @@ namespace osmium {
void close() final {
if (m_fd >= 0) {
- int fd = m_fd;
+ const int fd = m_fd;
m_fd = -1;
if (do_fsync()) {
osmium::io::detail::reliable_fsync(fd);
@@ -255,8 +252,8 @@ namespace osmium {
int m_fd;
const char *m_buffer;
- size_t m_buffer_size;
- size_t m_offset = 0;
+ std::size_t m_buffer_size;
+ std::size_t m_offset = 0;
public:
@@ -267,7 +264,7 @@ namespace osmium {
m_buffer_size(0) {
}
- NoDecompressor(const char* buffer, size_t size) :
+ NoDecompressor(const char* buffer, std::size_t size) :
Decompressor(),
m_fd(-1),
m_buffer(buffer),
@@ -287,15 +284,15 @@ namespace osmium {
if (m_buffer) {
if (m_buffer_size != 0) {
- size_t size = m_buffer_size;
+ const std::size_t size = m_buffer_size;
m_buffer_size = 0;
buffer.append(m_buffer, size);
}
} else {
buffer.resize(osmium::io::Decompressor::input_buffer_size);
- auto nread = ::read(m_fd, const_cast<char*>(buffer.data()), osmium::io::Decompressor::input_buffer_size);
+ const auto nread = ::read(m_fd, const_cast<char*>(buffer.data()), osmium::io::Decompressor::input_buffer_size);
if (nread < 0) {
- throw std::system_error(errno, std::system_category(), "Read failed");
+ throw std::system_error{errno, std::system_category(), "Read failed"};
}
buffer.resize(std::string::size_type(nread));
}
@@ -308,7 +305,7 @@ namespace osmium {
void close() final {
if (m_fd >= 0) {
- int fd = m_fd;
+ const int fd = m_fd;
m_fd = -1;
osmium::io::detail::reliable_close(fd);
}
@@ -321,9 +318,9 @@ namespace osmium {
// we want the register_compression() function to run, setting
// the variable is only a side-effect, it will never be used
const bool registered_no_compression = osmium::io::CompressionFactory::instance().register_compression(osmium::io::file_compression::none,
- [](int fd, fsync sync) { return new osmium::io::NoCompressor(fd, sync); },
- [](int fd) { return new osmium::io::NoDecompressor(fd); },
- [](const char* buffer, size_t size) { return new osmium::io::NoDecompressor(buffer, size); }
+ [](int fd, fsync sync) { return new osmium::io::NoCompressor{fd, sync}; },
+ [](int fd) { return new osmium::io::NoDecompressor{fd}; },
+ [](const char* buffer, std::size_t size) { return new osmium::io::NoDecompressor{buffer, size}; }
);
// dummy function to silence the unused variable warning from above
diff --git a/include/osmium/io/detail/debug_output_format.hpp b/include/osmium/io/detail/debug_output_format.hpp
index 7e2f07e..f7ce7c8 100644
--- a/include/osmium/io/detail/debug_output_format.hpp
+++ b/include/osmium/io/detail/debug_output_format.hpp
@@ -282,15 +282,16 @@ namespace osmium {
void write_box(const osmium::Box& box) {
write_fieldname("box l/b/r/t");
- if (!box) {
+ if (box.bottom_left().is_undefined() &&
+ box.top_right().is_undefined()) {
write_error("BOX NOT SET!\n");
return;
}
const auto& bl = box.bottom_left();
const auto& tr = box.top_right();
- bl.as_string(std::back_inserter(*m_out));
+ bl.as_string_without_check(std::back_inserter(*m_out));
*m_out += ' ';
- tr.as_string(std::back_inserter(*m_out));
+ tr.as_string_without_check(std::back_inserter(*m_out));
if (!box.valid()) {
write_error(" INVALID BOX!");
}
@@ -520,8 +521,8 @@ namespace osmium {
public:
- DebugOutputFormat(const osmium::io::File& file, future_string_queue_type& output_queue) :
- OutputFormat(output_queue),
+ DebugOutputFormat(osmium::thread::Pool& pool, const osmium::io::File& file, future_string_queue_type& output_queue) :
+ OutputFormat(pool, output_queue),
m_options() {
m_options.add_metadata = file.is_not_false("add_metadata");
m_options.use_color = file.is_true("color");
@@ -576,7 +577,7 @@ namespace osmium {
}
void write_buffer(osmium::memory::Buffer&& buffer) final {
- m_output_queue.push(osmium::thread::Pool::instance().submit(DebugOutputBlock{std::move(buffer), m_options}));
+ m_output_queue.push(m_pool.submit(DebugOutputBlock{std::move(buffer), m_options}));
}
}; // class DebugOutputFormat
@@ -584,8 +585,8 @@ namespace osmium {
// 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);
+ [](osmium::thread::Pool& pool, const osmium::io::File& file, future_string_queue_type& output_queue) {
+ return new osmium::io::detail::DebugOutputFormat(pool, file, output_queue);
});
// dummy function to silence the unused variable warning from above
diff --git a/include/osmium/io/detail/input_format.hpp b/include/osmium/io/detail/input_format.hpp
index 8651a35..442c717 100644
--- a/include/osmium/io/detail/input_format.hpp
+++ b/include/osmium/io/detail/input_format.hpp
@@ -48,6 +48,7 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/io/header.hpp>
#include <osmium/memory/buffer.hpp>
#include <osmium/osm/entity_bits.hpp>
+#include <osmium/thread/pool.hpp>
namespace osmium {
@@ -56,6 +57,7 @@ namespace osmium {
namespace detail {
struct parser_arguments {
+ osmium::thread::Pool& pool;
future_string_queue_type& input_queue;
future_buffer_queue_type& output_queue;
std::promise<osmium::io::Header>& header_promise;
@@ -65,6 +67,7 @@ namespace osmium {
class Parser {
+ osmium::thread::Pool& m_pool;
future_buffer_queue_type& m_output_queue;
std::promise<osmium::io::Header>& m_header_promise;
queue_wrapper<std::string> m_input_queue;
@@ -74,6 +77,10 @@ namespace osmium {
protected:
+ osmium::thread::Pool& get_pool() {
+ return m_pool;
+ }
+
std::string get_input() {
return m_input_queue.pop();
}
@@ -121,7 +128,8 @@ namespace osmium {
public:
- Parser(parser_arguments& args) :
+ explicit Parser(parser_arguments& args) :
+ m_pool(args.pool),
m_output_queue(args.output_queue),
m_header_promise(args.header_promise),
m_input_queue(args.input_queue),
diff --git a/include/osmium/io/detail/o5m_input_format.hpp b/include/osmium/io/detail/o5m_input_format.hpp
index fa47ed0..e0b3fa8 100644
--- a/include/osmium/io/detail/o5m_input_format.hpp
+++ b/include/osmium/io/detail/o5m_input_format.hpp
@@ -121,7 +121,7 @@ namespace osmium {
current_entry = 0;
}
- void add(const char* string, size_t size) {
+ void add(const char* string, std::size_t size) {
if (m_table.empty()) {
m_table.resize(entry_size * number_of_entries);
}
@@ -162,7 +162,7 @@ namespace osmium {
return protozero::decode_zigzag64(protozero::decode_varint(data, end));
}
- bool ensure_bytes_available(size_t need_bytes) {
+ bool ensure_bytes_available(std::size_t need_bytes) {
if ((m_end - m_data) >= long(need_bytes)) {
return true;
}
@@ -174,7 +174,7 @@ namespace osmium {
m_input.erase(0, m_data - m_input.data());
while (m_input.size() < need_bytes) {
- std::string data = get_input();
+ const std::string data{get_input()};
if (input_done()) {
return false;
}
@@ -589,7 +589,7 @@ namespace osmium {
public:
- O5mParser(parser_arguments& args) :
+ explicit O5mParser(parser_arguments& args) :
Parser(args),
m_header(),
m_buffer(buffer_size),
diff --git a/include/osmium/io/detail/opl_input_format.hpp b/include/osmium/io/detail/opl_input_format.hpp
index fd556e6..0d7a62d 100644
--- a/include/osmium/io/detail/opl_input_format.hpp
+++ b/include/osmium/io/detail/opl_input_format.hpp
@@ -33,19 +33,16 @@ DEALINGS IN THE SOFTWARE.
*/
-#include <cstdlib>
-#include <future>
+#include <cstdint>
#include <memory>
#include <string>
#include <utility>
#include <osmium/io/detail/input_format.hpp>
#include <osmium/io/detail/opl_parser_functions.hpp>
-#include <osmium/io/detail/queue_util.hpp>
#include <osmium/io/file_format.hpp>
#include <osmium/io/header.hpp>
#include <osmium/memory/buffer.hpp>
-#include <osmium/osm/entity_bits.hpp>
#include <osmium/thread/util.hpp>
namespace osmium {
@@ -79,7 +76,7 @@ namespace osmium {
public:
- OPLParser(parser_arguments& args) :
+ explicit OPLParser(parser_arguments& args) :
Parser(args) {
set_header_value(osmium::io::Header{});
}
@@ -91,7 +88,7 @@ namespace osmium {
std::string rest;
while (!input_done()) {
- std::string input = get_input();
+ std::string input{get_input()};
std::string::size_type ppos = 0;
if (!rest.empty()) {
diff --git a/include/osmium/io/detail/opl_output_format.hpp b/include/osmium/io/detail/opl_output_format.hpp
index bfcbcb1..d1fb2e5 100644
--- a/include/osmium/io/detail/opl_output_format.hpp
+++ b/include/osmium/io/detail/opl_output_format.hpp
@@ -141,14 +141,15 @@ namespace osmium {
}
void write_location(const osmium::Location& location, const char x, const char y) {
+ const bool not_undefined = !location.is_undefined();
*m_out += ' ';
*m_out += x;
- if (location) {
+ if (not_undefined) {
osmium::detail::append_location_coordinate_to_string(std::back_inserter(*m_out), location.x());
}
*m_out += ' ';
*m_out += y;
- if (location) {
+ if (not_undefined) {
osmium::detail::append_location_coordinate_to_string(std::back_inserter(*m_out), location.y());
}
}
@@ -283,8 +284,8 @@ namespace osmium {
public:
- OPLOutputFormat(const osmium::io::File& file, future_string_queue_type& output_queue) :
- OutputFormat(output_queue),
+ OPLOutputFormat(osmium::thread::Pool& pool, const osmium::io::File& file, future_string_queue_type& output_queue) :
+ OutputFormat(pool, output_queue),
m_options() {
m_options.add_metadata = file.is_not_false("add_metadata");
m_options.locations_on_ways = file.is_true("locations_on_ways");
@@ -297,7 +298,7 @@ namespace osmium {
~OPLOutputFormat() noexcept final = default;
void write_buffer(osmium::memory::Buffer&& buffer) final {
- m_output_queue.push(osmium::thread::Pool::instance().submit(OPLOutputBlock{std::move(buffer), m_options}));
+ m_output_queue.push(m_pool.submit(OPLOutputBlock{std::move(buffer), m_options}));
}
}; // class OPLOutputFormat
@@ -305,8 +306,8 @@ namespace osmium {
// 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);
+ [](osmium::thread::Pool& pool, const osmium::io::File& file, future_string_queue_type& output_queue) {
+ return new osmium::io::detail::OPLOutputFormat(pool, file, output_queue);
});
// dummy function to silence the unused variable warning from above
diff --git a/include/osmium/io/detail/opl_parser_functions.hpp b/include/osmium/io/detail/opl_parser_functions.hpp
index 622a7ca..f21145b 100644
--- a/include/osmium/io/detail/opl_parser_functions.hpp
+++ b/include/osmium/io/detail/opl_parser_functions.hpp
@@ -81,7 +81,7 @@ namespace osmium {
}
explicit opl_error(const char* what, const char* d = nullptr) :
- io_error(std::string("OPL error: ") + what),
+ io_error(std::string{"OPL error: "} + what),
data(d),
msg("OPL error: ") {
msg.append(what);
@@ -291,7 +291,7 @@ namespace osmium {
++*data;
return;
}
- std::string msg = "expected '";
+ std::string msg{"expected '"};
msg += c;
msg += "'";
throw opl_error{msg, *data};
@@ -599,8 +599,7 @@ namespace osmium {
const char* tags_begin = nullptr;
- osmium::Location location1;
- osmium::Location location2;
+ osmium::Box box;
std::string user;
while (**data) {
opl_parse_space(data);
@@ -630,22 +629,22 @@ namespace osmium {
break;
case 'x':
if (opl_non_empty(*data)) {
- location1.set_lon_partial(data);
+ box.bottom_left().set_lon_partial(data);
}
break;
case 'y':
if (opl_non_empty(*data)) {
- location1.set_lat_partial(data);
+ box.bottom_left().set_lat_partial(data);
}
break;
case 'X':
if (opl_non_empty(*data)) {
- location2.set_lon_partial(data);
+ box.top_right().set_lon_partial(data);
}
break;
case 'Y':
if (opl_non_empty(*data)) {
- location2.set_lat_partial(data);
+ box.top_right().set_lat_partial(data);
}
break;
case 'T':
@@ -661,13 +660,7 @@ namespace osmium {
}
- if (location1.valid() && location2.valid()) {
- osmium::Box box;
- box.extend(location1);
- box.extend(location2);
- builder.set_bounds(box);
- }
-
+ builder.set_bounds(box);
builder.set_user(user);
if (tags_begin) {
diff --git a/include/osmium/io/detail/output_format.hpp b/include/osmium/io/detail/output_format.hpp
index ccb0efd..5fe8bd9 100644
--- a/include/osmium/io/detail/output_format.hpp
+++ b/include/osmium/io/detail/output_format.hpp
@@ -46,6 +46,7 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/io/file.hpp>
#include <osmium/io/file_format.hpp>
#include <osmium/memory/buffer.hpp>
+#include <osmium/thread/pool.hpp>
namespace osmium {
@@ -107,6 +108,7 @@ namespace osmium {
protected:
+ osmium::thread::Pool& m_pool;
future_string_queue_type& m_output_queue;
/**
@@ -119,7 +121,8 @@ namespace osmium {
public:
- explicit OutputFormat(future_string_queue_type& output_queue) :
+ OutputFormat(osmium::thread::Pool& pool, future_string_queue_type& output_queue) :
+ m_pool(pool),
m_output_queue(output_queue) {
}
@@ -152,7 +155,7 @@ namespace osmium {
public:
- using create_output_type = std::function<osmium::io::detail::OutputFormat*(const osmium::io::File&, future_string_queue_type&)>;
+ using create_output_type = std::function<osmium::io::detail::OutputFormat*(osmium::thread::Pool&, const osmium::io::File&, future_string_queue_type&)>;
private:
@@ -178,18 +181,18 @@ namespace osmium {
return true;
}
- std::unique_ptr<osmium::io::detail::OutputFormat> create_output(const osmium::io::File& file, future_string_queue_type& output_queue) {
- auto it = m_callbacks.find(file.format());
+ std::unique_ptr<osmium::io::detail::OutputFormat> create_output(osmium::thread::Pool& pool, const osmium::io::File& file, future_string_queue_type& output_queue) {
+ const auto it = m_callbacks.find(file.format());
if (it != m_callbacks.end()) {
- return std::unique_ptr<osmium::io::detail::OutputFormat>((it->second)(file, output_queue));
+ return std::unique_ptr<osmium::io::detail::OutputFormat>((it->second)(pool, file, output_queue));
}
- throw unsupported_file_format_error(
- std::string("Can not open file '") +
+ 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.");
+ "'. No support for writing this format in this program."};
}
}; // class OutputFormatFactory
diff --git a/include/osmium/io/detail/pbf_decoder.hpp b/include/osmium/io/detail/pbf_decoder.hpp
index e47cff6..6b05301 100644
--- a/include/osmium/io/detail/pbf_decoder.hpp
+++ b/include/osmium/io/detail/pbf_decoder.hpp
@@ -99,21 +99,21 @@ namespace osmium {
void decode_stringtable(const data_view& data) {
if (!m_stringtable.empty()) {
- throw osmium::pbf_error("more than one stringtable in pbf file");
+ throw osmium::pbf_error{"more than one stringtable in pbf file"};
}
- 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)) {
const auto str_view = pbf_string_table.get_view();
if (str_view.size() > osmium::max_osm_string_length) {
- throw osmium::pbf_error("overlong string in string table");
+ throw osmium::pbf_error{"overlong string in string table"};
}
m_stringtable.emplace_back(str_view.data(), osmium::string_size_type(str_view.size()));
}
}
void decode_primitive_block_metadata() {
- protozero::pbf_message<OSMFormat::PrimitiveBlock> pbf_primitive_block(m_data);
+ protozero::pbf_message<OSMFormat::PrimitiveBlock> pbf_primitive_block{m_data};
while (pbf_primitive_block.next()) {
switch (pbf_primitive_block.tag()) {
case OSMFormat::PrimitiveBlock::required_StringTable_stringtable:
@@ -138,7 +138,7 @@ namespace osmium {
}
void decode_primitive_block_data() {
- protozero::pbf_message<OSMFormat::PrimitiveBlock> pbf_primitive_block(m_data);
+ protozero::pbf_message<OSMFormat::PrimitiveBlock> pbf_primitive_block{m_data};
while (pbf_primitive_block.next(OSMFormat::PrimitiveBlock::repeated_PrimitiveGroup_primitivegroup)) {
protozero::pbf_message<OSMFormat::PrimitiveGroup> pbf_primitive_group = pbf_primitive_block.get_message();
while (pbf_primitive_group.next()) {
@@ -187,16 +187,16 @@ namespace osmium {
}
osm_string_len_type decode_info(const data_view& data, osmium::OSMObject& object) {
- osm_string_len_type user = std::make_pair("", 0);
+ osm_string_len_type user{"", 0};
- protozero::pbf_message<OSMFormat::Info> pbf_info(data);
+ protozero::pbf_message<OSMFormat::Info> pbf_info{data};
while (pbf_info.next()) {
switch (pbf_info.tag()) {
case OSMFormat::Info::optional_int32_version:
{
const auto version = pbf_info.get_int32();
if (version < 0) {
- throw osmium::pbf_error("object version must not be negative");
+ throw osmium::pbf_error{"object version must not be negative"};
}
object.set_version(static_cast_with_assert<object_version_type>(version));
}
@@ -208,7 +208,7 @@ namespace osmium {
{
const auto changeset_id = pbf_info.get_int64();
if (changeset_id < 0) {
- throw osmium::pbf_error("object changeset_id must not be negative");
+ throw osmium::pbf_error{"object changeset_id must not be negative"};
}
object.set_changeset(static_cast_with_assert<changeset_id_type>(changeset_id));
}
@@ -240,7 +240,7 @@ namespace osmium {
while (kit != keys.end()) {
if (vit == vals.end()) {
// 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"};
}
const auto& k = m_stringtable.at(*kit++);
const auto& v = m_stringtable.at(*vit++);
@@ -262,9 +262,9 @@ namespace osmium {
int64_t lon = std::numeric_limits<int64_t>::max();
int64_t lat = std::numeric_limits<int64_t>::max();
- osm_string_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()) {
switch (pbf_node.tag()) {
case OSMFormat::Node::required_sint64_id:
@@ -297,12 +297,12 @@ namespace osmium {
if (node.visible()) {
if (lon == std::numeric_limits<int64_t>::max() ||
lat == std::numeric_limits<int64_t>::max()) {
- throw osmium::pbf_error("illegal coordinate format");
+ throw osmium::pbf_error{"illegal coordinate format"};
}
- node.set_location(osmium::Location(
+ node.set_location(osmium::Location{
convert_pbf_coordinate(lon),
convert_pbf_coordinate(lat)
- ));
+ });
}
builder.set_user(user.first, user.second);
@@ -319,9 +319,9 @@ namespace osmium {
protozero::iterator_range<protozero::pbf_reader::const_sint64_iterator> lats;
protozero::iterator_range<protozero::pbf_reader::const_sint64_iterator> lons;
- osm_string_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()) {
switch (pbf_way.tag()) {
case OSMFormat::Way::required_int64_id:
@@ -391,9 +391,9 @@ namespace osmium {
protozero::iterator_range<protozero::pbf_reader::const_sint64_iterator> refs;
protozero::iterator_range<protozero::pbf_reader::const_int32_iterator> types;
- osm_string_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()) {
switch (pbf_relation.tag()) {
case OSMFormat::Relation::required_int64_id:
@@ -435,7 +435,7 @@ namespace osmium {
const auto& r = m_stringtable.at(roles.front());
const int type = types.front();
if (type < 0 || type > 2) {
- throw osmium::pbf_error("unknown relation member type");
+ throw osmium::pbf_error{"unknown relation member type"};
}
rml_builder.add_member(
osmium::item_type(type + 1),
@@ -457,7 +457,7 @@ namespace osmium {
while (it != last && *it != 0) {
const auto& k = m_stringtable.at(*it++);
if (it == last) {
- throw osmium::pbf_error("PBF format error"); // this is against the spec, keys/vals must come in pairs
+ throw osmium::pbf_error{"PBF format error"}; // this is against the spec, keys/vals must come in pairs
}
const auto& v = m_stringtable.at(*it++);
tl_builder.add_tag(k.first, k.second, v.first, v.second);
@@ -475,7 +475,7 @@ namespace osmium {
protozero::iterator_range<protozero::pbf_reader::const_int32_iterator> tags;
- protozero::pbf_message<OSMFormat::DenseNodes> pbf_dense_nodes(data);
+ protozero::pbf_message<OSMFormat::DenseNodes> pbf_dense_nodes{data};
while (pbf_dense_nodes.next()) {
switch (pbf_dense_nodes.tag()) {
case OSMFormat::DenseNodes::packed_sint64_id:
@@ -505,7 +505,7 @@ namespace osmium {
if (lons.empty() ||
lats.empty()) {
// 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"};
}
osmium::builder::NodeBuilder builder{m_buffer};
@@ -547,7 +547,7 @@ namespace osmium {
protozero::iterator_range<protozero::pbf_reader::const_sint32_iterator> user_sids;
protozero::iterator_range<protozero::pbf_reader::const_int32_iterator> visibles;
- protozero::pbf_message<OSMFormat::DenseNodes> pbf_dense_nodes(data);
+ protozero::pbf_message<OSMFormat::DenseNodes> pbf_dense_nodes{data};
while (pbf_dense_nodes.next()) {
switch (pbf_dense_nodes.tag()) {
case OSMFormat::DenseNodes::packed_sint64_id:
@@ -556,7 +556,7 @@ namespace osmium {
case OSMFormat::DenseNodes::optional_DenseInfo_denseinfo:
{
has_info = true;
- protozero::pbf_message<OSMFormat::DenseInfo> pbf_dense_info = pbf_dense_nodes.get_message();
+ protozero::pbf_message<OSMFormat::DenseInfo> pbf_dense_info{pbf_dense_nodes.get_message()};
while (pbf_dense_info.next()) {
switch (pbf_dense_info.tag()) {
case OSMFormat::DenseInfo::packed_int32_version:
@@ -612,7 +612,7 @@ namespace osmium {
if (lons.empty() ||
lats.empty()) {
// 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"};
}
bool visible = true;
@@ -630,20 +630,20 @@ namespace osmium {
uids.empty() ||
user_sids.empty()) {
// 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"};
}
const auto version = versions.front();
versions.drop_front();
if (version < 0) {
- throw osmium::pbf_error("object version must not be negative");
+ throw osmium::pbf_error{"object version must not be negative"};
}
node.set_version(static_cast<osmium::object_version_type>(version));
const auto changeset_id = dense_changeset.update(changesets.front());
changesets.drop_front();
if (changeset_id < 0) {
- throw osmium::pbf_error("object changeset_id must not be negative");
+ throw osmium::pbf_error{"object changeset_id must not be negative"};
}
node.set_changeset(static_cast<osmium::changeset_id_type>(changeset_id));
@@ -655,7 +655,7 @@ namespace osmium {
if (has_visibles) {
if (visibles.empty()) {
// 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.front() != 0);
visibles.drop_front();
@@ -674,10 +674,10 @@ namespace osmium {
const auto lat = dense_latitude.update(lats.front());
lats.drop_front();
if (visible) {
- builder.object().set_location(osmium::Location(
+ builder.object().set_location(osmium::Location{
convert_pbf_coordinate(lon),
convert_pbf_coordinate(lat)
- ));
+ });
}
if (tag_it != tags.end()) {
@@ -708,7 +708,7 @@ namespace osmium {
decode_primitive_block_metadata();
decode_primitive_block_data();
} catch (const std::out_of_range&) {
- throw osmium::pbf_error("string id out of range");
+ throw osmium::pbf_error{"string id out of range"};
}
return std::move(m_buffer);
@@ -720,30 +720,30 @@ namespace osmium {
int32_t raw_size = 0;
protozero::data_view zlib_data;
- protozero::pbf_message<FileFormat::Blob> pbf_blob(blob_data);
+ protozero::pbf_message<FileFormat::Blob> pbf_blob{blob_data};
while (pbf_blob.next()) {
switch (pbf_blob.tag()) {
case FileFormat::Blob::optional_bytes_raw:
{
- auto data_len = pbf_blob.get_view();
+ const auto data_len = pbf_blob.get_view();
if (data_len.size() > max_uncompressed_blob_size) {
- throw osmium::pbf_error("illegal blob size");
+ throw osmium::pbf_error{"illegal blob size"};
}
return data_len;
}
case FileFormat::Blob::optional_int32_raw_size:
raw_size = pbf_blob.get_int32();
if (raw_size <= 0 || uint32_t(raw_size) > max_uncompressed_blob_size) {
- throw osmium::pbf_error("illegal blob size");
+ throw osmium::pbf_error{"illegal blob size"};
}
break;
case FileFormat::Blob::optional_bytes_zlib_data:
zlib_data = pbf_blob.get_view();
break;
case FileFormat::Blob::optional_bytes_lzma_data:
- throw osmium::pbf_error("lzma blobs not implemented");
+ throw osmium::pbf_error{"lzma blobs not implemented"};
default:
- throw osmium::pbf_error("unknown compression");
+ throw osmium::pbf_error{"unknown compression"};
}
}
@@ -756,7 +756,7 @@ namespace osmium {
);
}
- throw osmium::pbf_error("blob contains no data");
+ throw osmium::pbf_error{"blob contains no data"};
}
inline osmium::Box decode_header_bbox(const data_view& data) {
@@ -765,7 +765,7 @@ namespace osmium {
int64_t top = std::numeric_limits<int64_t>::max();
int64_t bottom = std::numeric_limits<int64_t>::max();
- protozero::pbf_message<OSMFormat::HeaderBBox> pbf_header_bbox(data);
+ protozero::pbf_message<OSMFormat::HeaderBBox> pbf_header_bbox{data};
while (pbf_header_bbox.next()) {
switch (pbf_header_bbox.tag()) {
case OSMFormat::HeaderBBox::required_sint64_left:
@@ -789,7 +789,7 @@ namespace osmium {
right == std::numeric_limits<int64_t>::max() ||
top == std::numeric_limits<int64_t>::max() ||
bottom == std::numeric_limits<int64_t>::max()) {
- throw osmium::pbf_error("invalid bbox");
+ throw osmium::pbf_error{"invalid bbox"};
}
osmium::Box box;
@@ -803,7 +803,7 @@ namespace osmium {
osmium::io::Header header;
int i = 0;
- protozero::pbf_message<OSMFormat::HeaderBlock> pbf_header_block(data);
+ protozero::pbf_message<OSMFormat::HeaderBlock> pbf_header_block{data};
while (pbf_header_block.next()) {
switch (pbf_header_block.tag()) {
case OSMFormat::HeaderBlock::optional_HeaderBBox_bbox:
@@ -819,9 +819,9 @@ namespace osmium {
} else if (!std::strncmp("HistoricalInformation", feature.data(), feature.size())) {
header.set_has_multiple_object_versions(true);
} else {
- std::string msg("required feature not supported: ");
+ std::string msg{"required feature not supported: "};
msg.append(feature.data(), feature.size());
- throw osmium::pbf_error(msg);
+ throw osmium::pbf_error{msg};
}
}
break;
@@ -833,7 +833,7 @@ namespace osmium {
break;
case OSMFormat::HeaderBlock::optional_int64_osmosis_replication_timestamp:
{
- const auto timestamp = osmium::Timestamp(pbf_header_block.get_int64()).to_iso();
+ const auto timestamp = osmium::Timestamp{pbf_header_block.get_int64()}.to_iso();
header.set("osmosis_replication_timestamp", timestamp);
header.set("timestamp", timestamp);
}
@@ -889,7 +889,7 @@ namespace osmium {
osmium::memory::Buffer operator()() {
std::string output;
- PBFPrimitiveBlockDecoder decoder(decode_blob(*m_input_buffer, output), m_read_types, m_read_metadata);
+ PBFPrimitiveBlockDecoder decoder{decode_blob(*m_input_buffer, output), m_read_types, m_read_metadata};
return decoder();
}
diff --git a/include/osmium/io/detail/pbf_input_format.hpp b/include/osmium/io/detail/pbf_input_format.hpp
index b5cd058..1ab4595 100644
--- a/include/osmium/io/detail/pbf_input_format.hpp
+++ b/include/osmium/io/detail/pbf_input_format.hpp
@@ -37,7 +37,6 @@ DEALINGS IN THE SOFTWARE.
#include <cstddef>
#include <cstdint>
#include <cstring>
-#include <future>
#include <memory>
#include <string>
#include <type_traits>
@@ -50,7 +49,6 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/io/detail/pbf.hpp> // IWYU pragma: export
#include <osmium/io/detail/pbf_decoder.hpp>
#include <osmium/io/detail/protobuf_tags.hpp>
-#include <osmium/io/detail/queue_util.hpp>
#include <osmium/io/file_format.hpp>
#include <osmium/io/header.hpp>
#include <osmium/osm/entity_bits.hpp>
@@ -77,14 +75,14 @@ namespace osmium {
*/
std::string read_from_input_queue(size_t size) {
while (m_input_buffer.size() < size) {
- const std::string new_data = get_input();
+ const std::string new_data{get_input()};
if (input_done()) {
- throw osmium::pbf_error("truncated data (EOF encountered)");
+ throw osmium::pbf_error{"truncated data (EOF encountered)"};
}
m_input_buffer += new_data;
}
- std::string output { m_input_buffer.substr(size) };
+ std::string output{m_input_buffer.substr(size)};
m_input_buffer.resize(size);
using std::swap;
@@ -101,7 +99,7 @@ namespace osmium {
uint32_t size_in_network_byte_order;
try {
- const 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());
} catch (const osmium::pbf_error&) {
return 0; // EOF
@@ -109,7 +107,7 @@ namespace osmium {
const uint32_t size = ntohl(size_in_network_byte_order);
if (size > static_cast<uint32_t>(max_blob_header_size)) {
- throw osmium::pbf_error("invalid BlobHeader size (> max_blob_header_size)");
+ throw osmium::pbf_error{"invalid BlobHeader size (> max_blob_header_size)"};
}
return size;
@@ -137,11 +135,11 @@ namespace osmium {
}
if (blob_header_datasize == 0) {
- throw osmium::pbf_error("PBF format error: BlobHeader.datasize missing or zero.");
+ throw osmium::pbf_error{"PBF format error: BlobHeader.datasize missing or zero."};
}
if (std::strncmp(expected_type, blob_header_type.data(), blob_header_type.size())) {
- throw osmium::pbf_error("blob does not have expected type (OSMHeader in first blob, OSMData in following blobs)");
+ throw osmium::pbf_error{"blob does not have expected type (OSMHeader in first blob, OSMData in following blobs)"};
}
return blob_header_datasize;
@@ -155,35 +153,34 @@ namespace osmium {
return 0;
}
- const 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);
}
std::string read_from_input_queue_with_check(size_t size) {
if (size > max_uncompressed_blob_size) {
- throw osmium::pbf_error(std::string("invalid blob size: " +
- std::to_string(size)));
+ throw osmium::pbf_error{std::string{"invalid blob size: "} +
+ std::to_string(size)};
}
return read_from_input_queue(size);
}
// Parse the header in the PBF OSMHeader blob.
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));
+ osmium::io::Header 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);
+ std::string input_buffer{read_from_input_queue_with_check(size)};
PBFDataBlobDecoder data_blob_parser{std::move(input_buffer), read_types(), read_metadata()};
if (osmium::config::use_pool_threads_for_pbf_parsing()) {
- send_to_output_queue(osmium::thread::Pool::instance().submit(std::move(data_blob_parser)));
+ send_to_output_queue(get_pool().submit(std::move(data_blob_parser)));
} else {
send_to_output_queue(data_blob_parser());
}
@@ -192,7 +189,7 @@ namespace osmium {
public:
- PBFParser(parser_arguments& args) :
+ explicit PBFParser(parser_arguments& args) :
Parser(args),
m_input_buffer() {
}
diff --git a/include/osmium/io/detail/pbf_output_format.hpp b/include/osmium/io/detail/pbf_output_format.hpp
index 00b364f..55cd0ea 100644
--- a/include/osmium/io/detail/pbf_output_format.hpp
+++ b/include/osmium/io/detail/pbf_output_format.hpp
@@ -37,10 +37,10 @@ DEALINGS IN THE SOFTWARE.
#include <cmath>
#include <cstdint>
#include <cstdlib>
-#include <iterator>
#include <memory>
#include <string>
#include <utility>
+#include <vector>
#include <protozero/pbf_builder.hpp>
#include <protozero/pbf_writer.hpp>
@@ -170,7 +170,7 @@ namespace osmium {
assert(m_msg.size() <= max_uncompressed_blob_size);
std::string blob_data;
- protozero::pbf_builder<FileFormat::Blob> pbf_blob(blob_data);
+ protozero::pbf_builder<FileFormat::Blob> pbf_blob{blob_data};
if (m_use_compression) {
pbf_blob.add_int32(FileFormat::Blob::optional_int32_raw_size, int32_t(m_msg.size()));
@@ -180,12 +180,12 @@ namespace osmium {
}
std::string blob_header_data;
- protozero::pbf_builder<FileFormat::BlobHeader> pbf_blob_header(blob_header_data);
+ protozero::pbf_builder<FileFormat::BlobHeader> pbf_blob_header{blob_header_data};
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()));
+ const 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;
@@ -269,7 +269,7 @@ namespace osmium {
m_delta_lon.clear();
}
- size_t size() const {
+ std::size_t size() const {
return m_ids.size() * 3 * sizeof(int64_t);
}
@@ -299,12 +299,12 @@ namespace osmium {
std::string serialize() const {
std::string data;
- protozero::pbf_builder<OSMFormat::DenseNodes> pbf_dense_nodes(data);
+ protozero::pbf_builder<OSMFormat::DenseNodes> pbf_dense_nodes{data};
pbf_dense_nodes.add_packed_sint64(OSMFormat::DenseNodes::packed_sint64_id, m_ids.cbegin(), m_ids.cend());
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_sint64(OSMFormat::DenseInfo::packed_sint64_timestamp, m_timestamps.cbegin(), m_timestamps.cend());
pbf_dense_info.add_packed_sint64(OSMFormat::DenseInfo::packed_sint64_changeset, m_changesets.cbegin(), m_changesets.cend());
@@ -389,7 +389,7 @@ namespace osmium {
return m_type;
}
- size_t size() const {
+ std::size_t size() const {
return m_pbf_primitive_group_data.size() + m_stringtable.size() + m_dense_nodes.size();
}
@@ -399,7 +399,7 @@ namespace osmium {
* enough space for the string table (which typically
* needs about 0.1 to 0.3% of the block size).
*/
- constexpr static size_t max_used_blob_size = max_uncompressed_blob_size * 95 / 100;
+ constexpr static std::size_t max_used_blob_size = max_uncompressed_blob_size * 95 / 100;
bool can_add(OSMFormat::PrimitiveGroup type) const {
if (type != m_type) {
@@ -425,16 +425,16 @@ namespace osmium {
}
std::string primitive_block_data;
- protozero::pbf_builder<OSMFormat::PrimitiveBlock> primitive_block(primitive_block_data);
+ protozero::pbf_builder<OSMFormat::PrimitiveBlock> primitive_block{primitive_block_data};
{
- protozero::pbf_builder<OSMFormat::StringTable> pbf_string_table(primitive_block, OSMFormat::PrimitiveBlock::required_StringTable_stringtable);
+ protozero::pbf_builder<OSMFormat::StringTable> pbf_string_table{primitive_block, OSMFormat::PrimitiveBlock::required_StringTable_stringtable};
m_primitive_block.write_stringtable(pbf_string_table);
}
primitive_block.add_message(OSMFormat::PrimitiveBlock::repeated_PrimitiveGroup_primitivegroup, m_primitive_block.group_data());
- m_output_queue.push(osmium::thread::Pool::instance().submit(
+ m_output_queue.push(m_pool.submit(
SerializeBlob{std::move(primitive_block_data),
pbf_blob_type::data,
m_options.use_compression}
@@ -458,7 +458,7 @@ namespace osmium {
}
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, static_cast_with_assert<int32_t>(object.version()));
pbf_info.add_int64(OSMFormat::Info::optional_int64_timestamp, uint32_t(object.timestamp()));
@@ -480,8 +480,8 @@ namespace osmium {
public:
- PBFOutputFormat(const osmium::io::File& file, future_string_queue_type& output_queue) :
- OutputFormat(output_queue),
+ PBFOutputFormat(osmium::thread::Pool& pool, const osmium::io::File& file, future_string_queue_type& output_queue) :
+ OutputFormat(pool, output_queue),
m_options(),
m_primitive_block(m_options) {
m_options.use_dense_nodes = file.is_not_false("pbf_dense_nodes");
@@ -499,10 +499,10 @@ namespace osmium {
void write_header(const osmium::io::Header& header) final {
std::string data;
- protozero::pbf_builder<OSMFormat::HeaderBlock> pbf_header_block(data);
+ protozero::pbf_builder<OSMFormat::HeaderBlock> pbf_header_block{data};
if (!header.boxes().empty()) {
- 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();
pbf_header_bbox.add_sint64(OSMFormat::HeaderBBox::required_sint64_left, int64_t(box.bottom_left().lon() * lonlat_resolution));
@@ -527,23 +527,23 @@ namespace osmium {
pbf_header_block.add_string(OSMFormat::HeaderBlock::optional_string_writingprogram, header.get("generator"));
- const std::string osmosis_replication_timestamp = header.get("osmosis_replication_timestamp");
+ const std::string osmosis_replication_timestamp{header.get("osmosis_replication_timestamp")};
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, uint32_t(ts));
}
- const std::string osmosis_replication_sequence_number = header.get("osmosis_replication_sequence_number");
+ const std::string osmosis_replication_sequence_number{header.get("osmosis_replication_sequence_number")};
if (!osmosis_replication_sequence_number.empty()) {
pbf_header_block.add_int64(OSMFormat::HeaderBlock::optional_int64_osmosis_replication_sequence_number, std::atoll(osmosis_replication_sequence_number.c_str()));
}
- const std::string osmosis_replication_base_url = header.get("osmosis_replication_base_url");
+ const std::string osmosis_replication_base_url{header.get("osmosis_replication_base_url")};
if (!osmosis_replication_base_url.empty()) {
pbf_header_block.add_string(OSMFormat::HeaderBlock::optional_string_osmosis_replication_base_url, osmosis_replication_base_url);
}
- m_output_queue.push(osmium::thread::Pool::instance().submit(
+ m_output_queue.push(m_pool.submit(
SerializeBlob{std::move(data),
pbf_blob_type::header,
m_options.use_compression}
@@ -566,7 +566,7 @@ namespace osmium {
}
switch_primitive_block_type(OSMFormat::PrimitiveGroup::repeated_Node_nodes);
- protozero::pbf_builder<OSMFormat::Node> pbf_node{ m_primitive_block.group(), OSMFormat::PrimitiveGroup::repeated_Node_nodes };
+ protozero::pbf_builder<OSMFormat::Node> pbf_node{m_primitive_block.group(), OSMFormat::PrimitiveGroup::repeated_Node_nodes};
pbf_node.add_sint64(OSMFormat::Node::required_sint64_id, node.id());
add_meta(node, pbf_node);
@@ -577,7 +577,7 @@ namespace osmium {
void way(const osmium::Way& way) {
switch_primitive_block_type(OSMFormat::PrimitiveGroup::repeated_Way_ways);
- protozero::pbf_builder<OSMFormat::Way> pbf_way{ m_primitive_block.group(), OSMFormat::PrimitiveGroup::repeated_Way_ways };
+ protozero::pbf_builder<OSMFormat::Way> pbf_way{m_primitive_block.group(), OSMFormat::PrimitiveGroup::repeated_Way_ways};
pbf_way.add_int64(OSMFormat::Way::required_int64_id, way.id());
add_meta(way, pbf_way);
@@ -610,7 +610,7 @@ namespace osmium {
void relation(const osmium::Relation& relation) {
switch_primitive_block_type(OSMFormat::PrimitiveGroup::repeated_Relation_relations);
- protozero::pbf_builder<OSMFormat::Relation> pbf_relation { m_primitive_block.group(), OSMFormat::PrimitiveGroup::repeated_Relation_relations };
+ protozero::pbf_builder<OSMFormat::Relation> pbf_relation{m_primitive_block.group(), OSMFormat::PrimitiveGroup::repeated_Relation_relations};
pbf_relation.add_int64(OSMFormat::Relation::required_int64_id, relation.id());
add_meta(relation, pbf_relation);
@@ -643,8 +643,8 @@ namespace osmium {
// 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);
+ [](osmium::thread::Pool& pool, const osmium::io::File& file, future_string_queue_type& output_queue) {
+ return new osmium::io::detail::PBFOutputFormat{pool, file, output_queue};
});
// dummy function to silence the unused variable warning from above
diff --git a/include/osmium/io/detail/read_write.hpp b/include/osmium/io/detail/read_write.hpp
index d6aa8bc..388d971 100644
--- a/include/osmium/io/detail/read_write.hpp
+++ b/include/osmium/io/detail/read_write.hpp
@@ -85,7 +85,7 @@ namespace osmium {
#endif
const 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 + "'");
+ throw std::system_error{errno, std::system_category(), std::string("Open failed for '") + filename + "'"};
}
return fd;
}
@@ -109,7 +109,7 @@ namespace osmium {
#endif
const int fd = ::open(filename.c_str(), flags);
if (fd < 0) {
- throw std::system_error(errno, std::system_category(), std::string("Open failed for '") + filename + "'");
+ throw std::system_error{errno, std::system_category(), std::string("Open failed for '") + filename + "'"};
}
return fd;
}
@@ -134,7 +134,7 @@ namespace osmium {
}
const auto length = ::write(fd, output_buffer + offset, static_cast<unsigned int>(write_count));
if (length < 0) {
- throw std::system_error(errno, std::system_category(), "Write failed");
+ throw std::system_error{errno, std::system_category(), "Write failed"};
}
offset += static_cast<size_t>(length);
} while (offset < size);
@@ -160,13 +160,13 @@ namespace osmium {
#else
if (::fsync(fd) != 0) {
#endif
- throw std::system_error(errno, std::system_category(), "Fsync failed");
+ 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");
+ throw std::system_error{errno, std::system_category(), "Close failed"};
}
}
diff --git a/include/osmium/io/detail/string_table.hpp b/include/osmium/io/detail/string_table.hpp
index ba725e5..16172c5 100644
--- a/include/osmium/io/detail/string_table.hpp
+++ b/include/osmium/io/detail/string_table.hpp
@@ -136,8 +136,12 @@ namespace osmium {
const_iterator& operator++() {
assert(m_it != m_last);
const auto last_pos = m_it->c_str() + m_it->size();
- while (m_pos != last_pos && *m_pos) ++m_pos;
- if (m_pos != last_pos) ++m_pos;
+ while (m_pos != last_pos && *m_pos) {
+ ++m_pos;
+ }
+ if (m_pos != last_pos) {
+ ++m_pos;
+ }
if (m_pos == last_pos) {
++m_it;
if (m_it != m_last) {
@@ -150,7 +154,7 @@ namespace osmium {
}
const_iterator operator++(int) {
- const_iterator tmp(*this);
+ const_iterator tmp{*this};
operator++();
return tmp;
}
@@ -175,11 +179,11 @@ namespace osmium {
if (m_chunks.front().empty()) {
return end();
}
- return const_iterator(m_chunks.begin(), m_chunks.end());
+ return {m_chunks.begin(), m_chunks.end()};
}
const_iterator end() const {
- return const_iterator(m_chunks.end(), m_chunks.end());
+ return {m_chunks.end(), m_chunks.end()};
}
// These functions get you some idea how much memory was
@@ -273,7 +277,7 @@ namespace osmium {
m_index[cs] = ++m_size;
if (m_size > max_entries) {
- throw osmium::pbf_error("string table has too many entries");
+ throw osmium::pbf_error{"string table has too many entries"};
}
return m_size;
diff --git a/include/osmium/io/detail/string_util.hpp b/include/osmium/io/detail/string_util.hpp
index 6414785..b450b7b 100644
--- a/include/osmium/io/detail/string_util.hpp
+++ b/include/osmium/io/detail/string_util.hpp
@@ -134,10 +134,10 @@ namespace osmium {
// Write out the value with four or more hex digits.
inline void append_min_4_hex_digits(std::string& out, uint32_t value, const char* const hex_digits) {
auto
- v = value & 0xf0000000; if (v) out += hex_digits[v >> 28];
- v = value & 0x0f000000; if (v) out += hex_digits[v >> 24];
- v = value & 0x00f00000; if (v) out += hex_digits[v >> 20];
- v = value & 0x000f0000; if (v) out += hex_digits[v >> 16];
+ v = value & 0xf0000000; if (v) { out += hex_digits[v >> 28]; }
+ v = value & 0x0f000000; if (v) { out += hex_digits[v >> 24]; }
+ v = value & 0x00f00000; if (v) { out += hex_digits[v >> 20]; }
+ v = value & 0x000f0000; if (v) { out += hex_digits[v >> 16]; }
out += hex_digits[(value >> 12) & 0xf];
out += hex_digits[(value >> 8) & 0xf];
diff --git a/include/osmium/io/detail/write_thread.hpp b/include/osmium/io/detail/write_thread.hpp
index 1b07451..575bc6b 100644
--- a/include/osmium/io/detail/write_thread.hpp
+++ b/include/osmium/io/detail/write_thread.hpp
@@ -83,7 +83,7 @@ namespace osmium {
try {
while (true) {
- std::string data = m_queue.pop();
+ const std::string data{m_queue.pop()};
if (at_end_of_data(data)) {
break;
}
diff --git a/include/osmium/io/detail/xml_input_format.hpp b/include/osmium/io/detail/xml_input_format.hpp
index a14c7f9..82c74eb 100644
--- a/include/osmium/io/detail/xml_input_format.hpp
+++ b/include/osmium/io/detail/xml_input_format.hpp
@@ -627,7 +627,7 @@ namespace osmium {
public:
- XMLParser(parser_arguments& args) :
+ explicit XMLParser(parser_arguments& args) :
Parser(args),
m_context(context::root),
m_last_context(context::root),
diff --git a/include/osmium/io/detail/xml_output_format.hpp b/include/osmium/io/detail/xml_output_format.hpp
index 130a3c7..a889874 100644
--- a/include/osmium/io/detail/xml_output_format.hpp
+++ b/include/osmium/io/detail/xml_output_format.hpp
@@ -396,7 +396,8 @@ namespace osmium {
write_attribute("uid", changeset.uid());
}
- if (changeset.bounds()) {
+ if (!changeset.bounds().bottom_left().is_undefined() ||
+ !changeset.bounds().top_right().is_undefined()) {
detail::append_lat_lon_attributes(*m_out, "min_lat", "min_lon", changeset.bounds().bottom_left());
detail::append_lat_lon_attributes(*m_out, "max_lat", "max_lon", changeset.bounds().top_right());
}
@@ -430,8 +431,8 @@ namespace osmium {
public:
- XMLOutputFormat(const osmium::io::File& file, future_string_queue_type& output_queue) :
- OutputFormat(output_queue),
+ XMLOutputFormat(osmium::thread::Pool& pool, const osmium::io::File& file, future_string_queue_type& output_queue) :
+ OutputFormat(pool, output_queue),
m_options() {
m_options.add_metadata = file.is_not_false("add_metadata");
m_options.use_change_ops = file.is_true("xml_change_format");
@@ -445,14 +446,14 @@ namespace osmium {
~XMLOutputFormat() noexcept final = default;
void write_header(const osmium::io::Header& header) 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_options.use_change_ops) {
out += "<osmChange version=\"0.6\" generator=\"";
} else {
out += "<osm version=\"0.6\"";
- std::string xml_josm_upload = header.get("xml_josm_upload");
+ const std::string xml_josm_upload{header.get("xml_josm_upload")};
if (xml_josm_upload == "true" || xml_josm_upload == "false") {
out += " upload=\"";
out += xml_josm_upload;
@@ -474,7 +475,7 @@ namespace osmium {
}
void write_buffer(osmium::memory::Buffer&& buffer) final {
- m_output_queue.push(osmium::thread::Pool::instance().submit(XMLOutputBlock{std::move(buffer), m_options}));
+ m_output_queue.push(m_pool.submit(XMLOutputBlock{std::move(buffer), m_options}));
}
void write_end() final {
@@ -494,8 +495,8 @@ namespace osmium {
// 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);
+ [](osmium::thread::Pool& pool, const osmium::io::File& file, future_string_queue_type& output_queue) {
+ return new osmium::io::detail::XMLOutputFormat(pool, file, output_queue);
});
// dummy function to silence the unused variable warning from above
diff --git a/include/osmium/io/detail/zlib.hpp b/include/osmium/io/detail/zlib.hpp
index f26fb48..b61bf1d 100644
--- a/include/osmium/io/detail/zlib.hpp
+++ b/include/osmium/io/detail/zlib.hpp
@@ -70,7 +70,7 @@ namespace osmium {
);
if (result != Z_OK) {
- throw io_error(std::string("failed to compress data: ") + zError(result));
+ throw io_error{std::string{"failed to compress data: "} + zError(result)};
}
output.resize(output_size);
@@ -100,7 +100,7 @@ namespace osmium {
);
if (result != Z_OK) {
- throw io_error(std::string("failed to uncompress data: ") + zError(result));
+ throw io_error{std::string{"failed to uncompress data: "} + zError(result)};
}
return protozero::data_view{output.data(), output.size()};
diff --git a/include/osmium/io/file.hpp b/include/osmium/io/file.hpp
index d537044..bf7c874 100644
--- a/include/osmium/io/file.hpp
+++ b/include/osmium/io/file.hpp
@@ -113,7 +113,7 @@ namespace osmium {
}
// if filename is a URL, default to XML format
- const std::string protocol = m_filename.substr(0, m_filename.find_first_of(':'));
+ const std::string protocol{m_filename.substr(0, m_filename.find_first_of(':'))};
if (protocol == "http" || protocol == "https") {
m_file_format = file_format::xml;
}
@@ -176,7 +176,7 @@ namespace osmium {
if (pos == std::string::npos) {
set(option, true);
} else {
- std::string value = option.substr(pos+1);
+ std::string value{option.substr(pos+1)};
option.erase(pos);
set(option, value);
}
@@ -192,7 +192,9 @@ namespace osmium {
void detect_format_from_suffix(const std::string& name) {
std::vector<std::string> suffixes = detail::split(name, '.');
- if (suffixes.empty()) return;
+ if (suffixes.empty()) {
+ return;
+ }
// if the last suffix is one of a known set of compressions,
// set that compression
@@ -204,7 +206,9 @@ namespace osmium {
suffixes.pop_back();
}
- if (suffixes.empty()) return;
+ if (suffixes.empty()) {
+ return;
+ }
// if the last suffix is one of a known set of formats,
// set that format
@@ -233,17 +237,25 @@ namespace osmium {
suffixes.pop_back();
}
- if (suffixes.empty()) return;
+ if (suffixes.empty()) {
+ return;
+ }
if (suffixes.back() == "osm") {
- if (m_file_format == file_format::unknown) m_file_format = file_format::xml;
+ if (m_file_format == file_format::unknown) {
+ m_file_format = file_format::xml;
+ }
suffixes.pop_back();
} else if (suffixes.back() == "osh") {
- if (m_file_format == file_format::unknown) m_file_format = file_format::xml;
+ if (m_file_format == file_format::unknown) {
+ m_file_format = file_format::xml;
+ }
m_has_multiple_object_versions = true;
suffixes.pop_back();
} else if (suffixes.back() == "osc") {
- if (m_file_format == file_format::unknown) m_file_format = file_format::xml;
+ if (m_file_format == file_format::unknown) {
+ m_file_format = file_format::xml;
+ }
m_has_multiple_object_versions = true;
set("xml_change_format", true);
suffixes.pop_back();
@@ -258,7 +270,7 @@ namespace osmium {
*/
const File& check() const {
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()) {
msg += " from format string '";
msg += m_format_string;
@@ -272,7 +284,7 @@ namespace osmium {
msg += "'";
}
msg += ".";
- throw io_error(msg);
+ throw io_error{msg};
}
return *this;
}
diff --git a/include/osmium/io/gzip_compression.hpp b/include/osmium/io/gzip_compression.hpp
index 27e18ee..49300d3 100644
--- a/include/osmium/io/gzip_compression.hpp
+++ b/include/osmium/io/gzip_compression.hpp
@@ -84,7 +84,7 @@ namespace osmium {
namespace detail {
OSMIUM_NORETURN inline void throw_gzip_error(gzFile gzfile, const char* msg, int zlib_error = 0) {
- std::string error("gzip error: ");
+ std::string error{"gzip error: "};
error += msg;
error += ": ";
int errnum = zlib_error;
@@ -93,7 +93,7 @@ namespace osmium {
} else {
error += ::gzerror(gzfile, &errnum);
}
- throw osmium::gzip_error(error, errnum);
+ throw osmium::gzip_error{error, errnum};
}
} // namespace detail
@@ -124,7 +124,7 @@ namespace osmium {
void write(const std::string& data) final {
if (!data.empty()) {
- int nwrite = ::gzwrite(m_gzfile, data.data(), static_cast_with_assert<unsigned int>(data.size()));
+ const int nwrite = ::gzwrite(m_gzfile, data.data(), static_cast_with_assert<unsigned int>(data.size()));
if (nwrite == 0) {
detail::throw_gzip_error(m_gzfile, "write failed");
}
@@ -133,7 +133,7 @@ namespace osmium {
void close() final {
if (m_gzfile) {
- int result = ::gzclose(m_gzfile);
+ const int result = ::gzclose(m_gzfile);
m_gzfile = nullptr;
if (result != Z_OK) {
detail::throw_gzip_error(m_gzfile, "write close failed", result);
@@ -184,7 +184,7 @@ namespace osmium {
void close() final {
if (m_gzfile) {
- int result = ::gzclose(m_gzfile);
+ const int result = ::gzclose(m_gzfile);
m_gzfile = nullptr;
if (result != Z_OK) {
detail::throw_gzip_error(m_gzfile, "read close failed", result);
@@ -208,13 +208,13 @@ namespace osmium {
m_zstream() {
m_zstream.next_in = reinterpret_cast<unsigned char*>(const_cast<char*>(buffer));
m_zstream.avail_in = static_cast_with_assert<unsigned int>(size);
- int result = inflateInit2(&m_zstream, MAX_WBITS | 32);
+ const int result = inflateInit2(&m_zstream, MAX_WBITS | 32);
if (result != Z_OK) {
- std::string message("gzip error: decompression init failed: ");
+ std::string message{"gzip error: decompression init failed: "};
if (m_zstream.msg) {
message.append(m_zstream.msg);
}
- throw osmium::gzip_error(message, result);
+ throw osmium::gzip_error{message, result};
}
}
@@ -234,7 +234,7 @@ namespace osmium {
output.append(buffer_size, '\0');
m_zstream.next_out = reinterpret_cast<unsigned char*>(const_cast<char*>(output.data()));
m_zstream.avail_out = buffer_size;
- int result = inflate(&m_zstream, Z_SYNC_FLUSH);
+ const int result = inflate(&m_zstream, Z_SYNC_FLUSH);
if (result != Z_OK) {
m_buffer = nullptr;
@@ -246,7 +246,7 @@ namespace osmium {
if (m_zstream.msg) {
message.append(m_zstream.msg);
}
- throw osmium::gzip_error(message, result);
+ throw osmium::gzip_error{message, result};
}
output.resize(static_cast<unsigned long>(m_zstream.next_out - reinterpret_cast<const unsigned char*>(output.data())));
@@ -266,9 +266,9 @@ namespace osmium {
// we want the register_compression() function to run, setting
// the variable is only a side-effect, it will never be used
const bool registered_gzip_compression = osmium::io::CompressionFactory::instance().register_compression(osmium::io::file_compression::gzip,
- [](int fd, fsync sync) { return new osmium::io::GzipCompressor(fd, sync); },
- [](int fd) { return new osmium::io::GzipDecompressor(fd); },
- [](const char* buffer, size_t size) { return new osmium::io::GzipBufferDecompressor(buffer, size); }
+ [](int fd, fsync sync) { return new osmium::io::GzipCompressor{fd, sync}; },
+ [](int fd) { return new osmium::io::GzipDecompressor{fd}; },
+ [](const char* buffer, size_t size) { return new osmium::io::GzipBufferDecompressor{buffer, size}; }
);
// dummy function to silence the unused variable warning from above
diff --git a/include/osmium/io/header.hpp b/include/osmium/io/header.hpp
index c0a2043..f529294 100644
--- a/include/osmium/io/header.hpp
+++ b/include/osmium/io/header.hpp
@@ -75,14 +75,20 @@ namespace osmium {
* this stream of objects? This should be true for history files
* and for change files, but not for normal OSM data files.
*/
- bool m_has_multiple_object_versions = false;
+ bool m_has_multiple_object_versions;
public:
- Header() = default;
+ Header() :
+ Options(),
+ m_boxes(),
+ m_has_multiple_object_versions(false) {
+ }
explicit Header(const std::initializer_list<osmium::util::Options::value_type>& values) :
- Options(values) {
+ Options(values),
+ m_boxes(),
+ m_has_multiple_object_versions(false) {
}
/**
diff --git a/include/osmium/io/reader.hpp b/include/osmium/io/reader.hpp
index 55b13be..7286933 100644
--- a/include/osmium/io/reader.hpp
+++ b/include/osmium/io/reader.hpp
@@ -61,6 +61,7 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/io/header.hpp>
#include <osmium/memory/buffer.hpp>
#include <osmium/osm/entity_bits.hpp>
+#include <osmium/thread/pool.hpp>
#include <osmium/thread/util.hpp>
#include <osmium/util/config.hpp>
@@ -70,13 +71,13 @@ namespace osmium {
namespace detail {
- inline size_t get_input_queue_size() noexcept {
- const size_t n = osmium::config::get_max_queue_size("INPUT", 20);
+ inline std::size_t get_input_queue_size() noexcept {
+ const std::size_t n = osmium::config::get_max_queue_size("INPUT", 20);
return n > 2 ? n : 2;
}
- inline size_t get_osmdata_queue_size() noexcept {
- const size_t n = osmium::config::get_max_queue_size("OSMDATA", 20);
+ inline std::size_t get_osmdata_queue_size() noexcept {
+ const std::size_t n = osmium::config::get_max_queue_size("OSMDATA", 20);
return n > 2 ? n : 2;
}
@@ -92,6 +93,8 @@ namespace osmium {
osmium::io::File m_file;
+ osmium::thread::Pool* m_pool = nullptr;
+
detail::ParserFactory::create_parser_type m_creator;
enum class status {
@@ -117,11 +120,15 @@ namespace osmium {
osmium::thread::thread_handler m_thread;
- size_t m_file_size;
+ std::size_t m_file_size;
osmium::osm_entity_bits::type m_read_which_entities = osmium::osm_entity_bits::all;
osmium::io::read_meta m_read_metadata = osmium::io::read_meta::yes;
+ void set_option(osmium::thread::Pool& pool) noexcept {
+ m_pool = &pool;
+ }
+
void set_option(osmium::osm_entity_bits::type value) noexcept {
m_read_which_entities = value;
}
@@ -131,14 +138,16 @@ namespace osmium {
}
// This function will run in a separate thread.
- static void parser_thread(const detail::ParserFactory::create_parser_type& creator,
+ static void parser_thread(osmium::thread::Pool& pool,
+ const detail::ParserFactory::create_parser_type& creator,
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,
osmium::io::read_meta read_metadata) {
- std::promise<osmium::io::Header> promise = std::move(header_promise);
+ std::promise<osmium::io::Header> promise{std::move(header_promise)};
osmium::io::detail::parser_arguments args = {
+ pool,
input_queue,
osmdata_queue,
promise,
@@ -206,16 +215,15 @@ namespace osmium {
* @throws std::system_error if a system call fails.
*/
static int open_input_file_or_url(const std::string& filename, int* childpid) {
- std::string protocol = filename.substr(0, filename.find_first_of(':'));
+ const std::string protocol{filename.substr(0, filename.find_first_of(':'))};
if (protocol == "http" || protocol == "https" || protocol == "ftp" || protocol == "file") {
#ifndef _WIN32
return execute("curl", filename, childpid);
#else
throw io_error{"Reading OSM files from the network currently not supported on Windows."};
#endif
- } else {
- return osmium::io::detail::open_for_reading(filename);
}
+ return osmium::io::detail::open_for_reading(filename);
}
public:
@@ -264,9 +272,13 @@ namespace osmium {
(set_option(args), 0)...
};
+ if (!m_pool) {
+ m_pool = &thread::Pool::default_instance();
+ }
+
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_creator), std::ref(m_input_queue), std::ref(m_osmdata_queue), std::move(header_promise), m_read_which_entities, m_read_metadata};
+ m_thread = osmium::thread::thread_handler{parser_thread, std::ref(*m_pool), std::ref(m_creator), std::ref(m_input_queue), std::ref(m_osmdata_queue), std::move(header_promise), m_read_which_entities, m_read_metadata};
}
template <typename... TArgs>
@@ -408,7 +420,7 @@ namespace osmium {
* Get the size of the input file. Returns 0 if the file size
* is not available (for instance when reading from stdin).
*/
- size_t file_size() const noexcept {
+ std::size_t file_size() const noexcept {
return m_file_size;
}
@@ -426,7 +438,7 @@ namespace osmium {
* object you are reading. Depending on the file type it might
* do an expensive system call.
*/
- size_t offset() const noexcept {
+ std::size_t offset() const noexcept {
return m_decompressor->offset();
}
@@ -442,10 +454,10 @@ namespace osmium {
*/
template <typename... TArgs>
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};
- Reader reader(std::forward<TArgs>(args)...);
- while (osmium::memory::Buffer read_buffer = reader.read()) {
+ Reader reader{std::forward<TArgs>(args)...};
+ while (auto read_buffer = reader.read()) {
buffer.add_buffer(read_buffer);
buffer.commit();
}
diff --git a/include/osmium/io/writer.hpp b/include/osmium/io/writer.hpp
index 1397a22..dd90a2e 100644
--- a/include/osmium/io/writer.hpp
+++ b/include/osmium/io/writer.hpp
@@ -53,6 +53,7 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/io/header.hpp>
#include <osmium/io/writer_options.hpp>
#include <osmium/memory/buffer.hpp>
+#include <osmium/thread/pool.hpp>
#include <osmium/thread/util.hpp>
#include <osmium/util/config.hpp>
#include <osmium/version.hpp>
@@ -169,8 +170,13 @@ namespace osmium {
osmium::io::Header header;
overwrite allow_overwrite = overwrite::no;
fsync sync = fsync::no;
+ osmium::thread::Pool* pool = nullptr;
};
+ static void set_option(options_type& options, osmium::thread::Pool& pool) {
+ options.pool = &pool;
+ }
+
static void set_option(options_type& options, const osmium::io::Header& header) {
options.header = header;
}
@@ -223,7 +229,7 @@ namespace osmium {
explicit Writer(const osmium::io::File& file, TArgs&&... args) :
m_file(file.check()),
m_output_queue(detail::get_output_queue_size(), "raw_output"),
- m_output(osmium::io::detail::OutputFormatFactory::instance().create_output(m_file, m_output_queue)),
+ m_output(nullptr),
m_buffer(),
m_buffer_size(default_buffer_size),
m_write_future(),
@@ -236,6 +242,12 @@ namespace osmium {
(set_option(options, args), 0)...
};
+ if (!options.pool) {
+ options.pool = &thread::Pool::default_instance();
+ }
+
+ m_output = osmium::io::detail::OutputFormatFactory::instance().create_output(*options.pool, m_file, m_output_queue);
+
if (options.header.get("generator") == "") {
options.header.set("generator", "libosmium/" LIBOSMIUM_VERSION_STRING);
}
diff --git a/include/osmium/memory/buffer.hpp b/include/osmium/memory/buffer.hpp
index 48d8409..deaee42 100644
--- a/include/osmium/memory/buffer.hpp
+++ b/include/osmium/memory/buffer.hpp
@@ -1,6 +1,7 @@
#ifndef OSMIUM_MEMORY_BUFFER_HPP
#define OSMIUM_MEMORY_BUFFER_HPP
+#include <iostream>
/*
This file is part of Osmium (http://osmcode.org/libosmium).
@@ -58,7 +59,7 @@ namespace osmium {
struct buffer_is_full : public std::runtime_error {
buffer_is_full() :
- std::runtime_error("Osmium buffer is full") {
+ std::runtime_error{"Osmium buffer is full"} {
}
}; // struct buffer_is_full
@@ -110,18 +111,18 @@ namespace osmium {
std::unique_ptr<unsigned char[]> m_memory;
unsigned char* m_data;
- size_t m_capacity;
- size_t m_written;
- size_t m_committed;
+ std::size_t m_capacity;
+ std::size_t m_written;
+ std::size_t m_committed;
#ifndef NDEBUG
- uint8_t m_builder_count{0};
+ uint8_t m_builder_count = 0;
#endif
auto_grow m_auto_grow{auto_grow::no};
std::function<void(Buffer&)> m_full;
- static size_t calculate_capacity(size_t capacity) noexcept {
+ static std::size_t calculate_capacity(std::size_t capacity) noexcept {
// The majority of all Nodes will fit into this size.
- constexpr static const size_t min_capacity = 64;
+ constexpr static const std::size_t min_capacity = 64;
if (capacity < min_capacity) {
return min_capacity;
}
@@ -156,14 +157,14 @@ namespace osmium {
* @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, std::size_t size) :
m_memory(),
m_data(data),
m_capacity(size),
m_written(size),
m_committed(size) {
if (size % align_bytes != 0) {
- throw std::invalid_argument("buffer size needs to be multiple of alignment");
+ throw std::invalid_argument{"buffer size needs to be multiple of alignment"};
}
}
@@ -176,19 +177,23 @@ namespace osmium {
* @param committed The size of the initialized data. If this is 0, the buffer startes out empty.
*
* @throws std::invalid_argument if the capacity or committed isn't
- * a multiple of the alignment.
+ * a multiple of the alignment or if committed is larger
+ * than capacity.
*/
- explicit Buffer(unsigned char* data, size_t capacity, size_t committed) :
+ explicit Buffer(unsigned char* data, std::size_t capacity, std::size_t committed) :
m_memory(),
m_data(data),
m_capacity(capacity),
m_written(committed),
m_committed(committed) {
if (capacity % align_bytes != 0) {
- throw std::invalid_argument("buffer capacity needs to be multiple of alignment");
+ throw std::invalid_argument{"buffer capacity needs to be multiple of alignment"};
}
if (committed % align_bytes != 0) {
- throw std::invalid_argument("buffer parameter 'committed' needs to be multiple of alignment");
+ throw std::invalid_argument{"buffer parameter 'committed' needs to be multiple of alignment"};
+ }
+ if (committed > capacity) {
+ throw std::invalid_argument{"buffer parameter 'committed' can not be larger than capacity"};
}
}
@@ -204,7 +209,7 @@ namespace osmium {
* @param auto_grow Should this buffer automatically grow when it
* becomes to small?
*/
- explicit Buffer(size_t capacity, auto_grow auto_grow = auto_grow::yes) :
+ explicit Buffer(std::size_t capacity, auto_grow auto_grow = auto_grow::yes) :
m_memory(new unsigned char[calculate_capacity(capacity)]),
m_data(m_memory.get()),
m_capacity(calculate_capacity(capacity)),
@@ -252,7 +257,7 @@ namespace osmium {
* Returns the capacity of the buffer, ie how many bytes it can
* contain. Always returns 0 on invalid buffers.
*/
- size_t capacity() const noexcept {
+ std::size_t capacity() const noexcept {
return m_capacity;
}
@@ -260,7 +265,7 @@ namespace osmium {
* Returns the number of bytes already filled in this buffer.
* Always returns 0 on invalid buffers.
*/
- size_t committed() const noexcept {
+ std::size_t committed() const noexcept {
return m_committed;
}
@@ -269,7 +274,7 @@ namespace osmium {
* are not yet committed.
* Always returns 0 on invalid buffers.
*/
- size_t written() const noexcept {
+ std::size_t written() const noexcept {
return m_written;
}
@@ -297,20 +302,16 @@ namespace osmium {
* 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().
+ * the CallbackBuffer class.
*/
- OSMIUM_DEPRECATED void set_full_callback(std::function<void(Buffer&)> full) {
+ OSMIUM_DEPRECATED void set_full_callback(const std::function<void(Buffer&)>& full) {
assert(m_data && "This must be a valid buffer");
m_full = full;
}
/**
- * Grow capacity of this buffer to the given size.
+ * Grow capacity of this buffer to the given size (which will be
+ * rounded up to the alignment needed).
* This works only with internally memory-managed buffers.
* If the given size is not larger than the current capacity,
* nothing is done.
@@ -321,19 +322,15 @@ namespace osmium {
*
* @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.
* @throws std::bad_alloc if there isn't enough memory available.
*/
- void grow(size_t size) {
+ void grow(std::size_t size) {
assert(m_data && "This must be a valid buffer");
if (!m_memory) {
- 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."};
}
+ size = calculate_capacity(size);
if (m_capacity < size) {
- if (size % align_bytes != 0) {
- throw std::invalid_argument("buffer capacity needs to be multiple of alignment");
- }
std::unique_ptr<unsigned char[]> memory(new unsigned char[size]);
std::copy_n(m_memory.get(), m_capacity, memory.get());
using std::swap;
@@ -355,12 +352,12 @@ namespace osmium {
* used as an offset into the buffer to get to the
* object being committed by this call.
*/
- size_t commit() {
+ std::size_t commit() {
assert(m_data && "This must be a valid buffer");
assert(m_builder_count == 0 && "Make sure there are no Builder objects still in scope");
assert(is_aligned());
- const size_t offset = m_committed;
+ const std::size_t offset = m_committed;
m_committed = m_written;
return offset;
}
@@ -386,9 +383,9 @@ namespace osmium {
*
* @returns Number of bytes in the buffer before it was cleared.
*/
- size_t clear() {
+ std::size_t clear() {
assert(m_builder_count == 0 && "Make sure there are no Builder objects still in scope");
- const size_t committed = m_committed;
+ const std::size_t committed = m_committed;
m_written = 0;
m_committed = 0;
return committed;
@@ -405,7 +402,7 @@ namespace osmium {
* buffer.
*/
template <typename T>
- T& get(const size_t offset) const {
+ T& get(const std::size_t offset) const {
assert(m_data && "This must be a valid buffer");
return *reinterpret_cast<T*>(&m_data[offset]);
}
@@ -443,7 +440,7 @@ namespace osmium {
* @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 std::size_t size) {
assert(m_data && "This must be a valid buffer");
// try to flush the buffer empty first.
if (m_written + size > m_capacity && m_full) {
@@ -453,13 +450,13 @@ namespace osmium {
if (m_written + size > m_capacity) {
if (m_memory && (m_auto_grow == auto_grow::yes)) {
// double buffer size until there is enough space
- size_t new_capacity = m_capacity * 2;
+ std::size_t new_capacity = m_capacity * 2;
while (m_written + size > new_capacity) {
new_capacity *= 2;
}
grow(new_capacity);
} else {
- throw osmium::buffer_is_full();
+ throw osmium::buffer_is_full{};
}
}
unsigned char* data = &m_data[m_written];
@@ -598,7 +595,7 @@ namespace osmium {
* in the buffer.
*/
template <typename T>
- t_iterator<T> get_iterator(size_t offset) {
+ t_iterator<T> get_iterator(std::size_t offset) {
assert(m_data && "This must be a valid buffer");
return t_iterator<T>(m_data + offset, m_data + m_committed);
}
@@ -612,7 +609,7 @@ namespace osmium {
* @returns Iterator to first OSMEntity after given offset in the
* buffer.
*/
- iterator get_iterator(size_t offset) {
+ iterator get_iterator(std::size_t offset) {
assert(m_data && "This must be a valid buffer");
return iterator(m_data + offset, m_data + m_committed);
}
@@ -656,12 +653,12 @@ namespace osmium {
}
template <typename T>
- t_const_iterator<T> get_iterator(size_t offset) const {
+ t_const_iterator<T> get_iterator(std::size_t offset) const {
assert(m_data && "This must be a valid buffer");
return t_const_iterator<T>(m_data + offset, m_data + m_committed);
}
- const_iterator get_iterator(size_t offset) const {
+ const_iterator get_iterator(std::size_t offset) const {
assert(m_data && "This must be a valid buffer");
return const_iterator(m_data + offset, m_data + m_committed);
}
@@ -746,8 +743,8 @@ namespace osmium {
if (it_read != it_write) {
assert(it_read.data() >= data());
assert(it_write.data() >= data());
- size_t old_offset = static_cast<size_t>(it_read.data() - data());
- size_t new_offset = static_cast<size_t>(it_write.data() - data());
+ const auto old_offset = static_cast<std::size_t>(it_read.data() - data());
+ const auto new_offset = static_cast<std::size_t>(it_write.data() - data());
callback->moving_in_buffer(old_offset, new_offset);
std::memmove(it_write.data(), it_read.data(), it_read->padded_size());
}
@@ -756,7 +753,7 @@ namespace osmium {
}
assert(it_write.data() >= data());
- m_written = static_cast<size_t>(it_write.data() - data());
+ m_written = static_cast<std::size_t>(it_write.data() - data());
m_committed = m_written;
}
diff --git a/include/osmium/memory/callback_buffer.hpp b/include/osmium/memory/callback_buffer.hpp
new file mode 100644
index 0000000..7e9be73
--- /dev/null
+++ b/include/osmium/memory/callback_buffer.hpp
@@ -0,0 +1,189 @@
+#ifndef OSMIUM_MEMORY_CALLBACK_BUFFER_HPP
+#define OSMIUM_MEMORY_CALLBACK_BUFFER_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2017 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstddef>
+#include <functional>
+#include <utility>
+
+#include <osmium/memory/buffer.hpp>
+
+namespace osmium {
+
+ namespace memory {
+
+ /**
+ * This is basically a wrapper around osmium::memory::Buffer with an
+ * additional callback function that is called whenever the buffer is
+ * full.
+ *
+ * The internal buffer is created with the `initial_buffer_size` set
+ * in the constructor. When it grows beyond the `max_buffer_size` set
+ * in the constructor, the callback function is called with the buffer
+ * and a new, empty buffer is created internally.
+ *
+ * Note that the buffer can grow beyond the initial buffer size if
+ * needed. This can happen if a new object doesn't fit into the rest
+ * of the buffer available or if no callback function is set (yet).
+ *
+ * Example:
+ * @code
+ * CallbackBuffer cb;
+ * cb.set_callback([&](osmium::memory::Buffer&& buffer) {
+ * ...handle buffer...
+ * }
+ * osmium::builder::add_node(cb.buffer(), _id(9), ...);
+ * osmium::builder::add_way(cb.buffer(), _id(27), ...);
+ * @endcode
+ */
+ class CallbackBuffer {
+
+ public:
+
+ /// The type for the callback function
+ using callback_func_type = std::function<void(osmium::memory::Buffer&&)>;
+
+ private:
+
+ static constexpr const std::size_t default_initial_buffer_size = 1024 * 1024;
+ static constexpr const std::size_t default_max_buffer_size = 800 * 1024;
+
+ osmium::memory::Buffer m_buffer;
+ std::size_t m_initial_buffer_size;
+ std::size_t m_max_buffer_size;
+ callback_func_type m_callback;
+
+ public:
+
+ /**
+ * Construct a CallbackBuffer without a callback function. You
+ * can later call set the callback with set_callback().
+ *
+ * @param initial_buffer_size The initial size of newly created
+ * internal buffers.
+ * @param max_buffer_size If the buffer grows beyond this size the
+ * callback will be called.
+ */
+ explicit CallbackBuffer(std::size_t initial_buffer_size = default_initial_buffer_size, std::size_t max_buffer_size = default_max_buffer_size) :
+ m_buffer(initial_buffer_size, osmium::memory::Buffer::auto_grow::yes),
+ m_initial_buffer_size(initial_buffer_size),
+ m_max_buffer_size(max_buffer_size),
+ m_callback(nullptr) {
+ }
+
+ /**
+ * Construct a CallbackBuffer with a callback function.
+ *
+ * @param callback The callback function. Must be of type
+ * @code void(osmium::memory::Buffer&&) @endcode
+ * @param initial_buffer_size The initial size of newly created
+ * internal buffers.
+ * @param max_buffer_size If the buffer grows beyond this size the
+ * callback will be called.
+ */
+ explicit CallbackBuffer(const callback_func_type& callback, std::size_t initial_buffer_size = default_initial_buffer_size, std::size_t max_buffer_size = default_max_buffer_size) :
+ m_buffer(initial_buffer_size, osmium::memory::Buffer::auto_grow::yes),
+ m_initial_buffer_size(initial_buffer_size),
+ m_max_buffer_size(max_buffer_size),
+ m_callback(callback) {
+ }
+
+ /**
+ * Access the internal buffer. This is used to fill the buffer,
+ * the CallbackBuffer still owns the buffer.
+ *
+ * Use read() or the callback if you need to own the buffer.
+ */
+ osmium::memory::Buffer& buffer() noexcept {
+ return m_buffer;
+ }
+
+ /**
+ * Set the callback. The function must take a rvalue reference to
+ * a buffer and return void.
+ *
+ * @param callback The callback function. Must be of type
+ * @code void(osmium::memory::Buffer&&) @endcode
+ */
+ void set_callback(const callback_func_type& callback = nullptr) noexcept {
+ m_callback = callback;
+ }
+
+ /**
+ * Flush the internal buffer regardless of how full it is. Calls
+ * the callback with the buffer and creates an new empty internal
+ * one.
+ *
+ * This will do nothing if no callback is set or if the buffer
+ * is empty.
+ */
+ void flush() {
+ if (m_callback && m_buffer.committed() > 0) {
+ m_callback(read());
+ }
+ }
+
+ /**
+ * Flush the internal buffer if and only if it contains more than
+ * the max_buffer_size set in the constructor. Calls the callback
+ * with the buffer and creates an new empty internal one.
+ *
+ * This will do nothing if no callback is set or if the buffer
+ * is empty.
+ */
+ void possibly_flush() {
+ if (m_buffer.committed() > m_max_buffer_size) {
+ flush();
+ }
+ }
+
+ /**
+ * Return the internal buffer and create a new empty internal one.
+ * You can use this as an alternative access instead of using the
+ * callback.
+ */
+ osmium::memory::Buffer read() {
+ osmium::memory::Buffer buffer{m_initial_buffer_size, osmium::memory::Buffer::auto_grow::yes};
+ using std::swap;
+ swap(buffer, m_buffer);
+ return buffer;
+ }
+
+ }; // class CallbackBuffer
+
+ } // namespace memory
+
+} // namespace osmium
+
+#endif // OSMIUM_MEMORY_CALLBACK_BUFFER_HPP
diff --git a/include/osmium/memory/item.hpp b/include/osmium/memory/item.hpp
index 6714ce2..0f02df9 100644
--- a/include/osmium/memory/item.hpp
+++ b/include/osmium/memory/item.hpp
@@ -59,7 +59,7 @@ namespace osmium {
using item_size_type = uint32_t;
// align datastructures to this many bytes
- constexpr const item_size_type align_bytes = 8;
+ constexpr const std::size_t align_bytes = 8;
inline constexpr std::size_t padded_length(std::size_t length) noexcept {
return (length + align_bytes - 1) & ~(align_bytes - 1);
diff --git a/include/osmium/object_pointer_collection.hpp b/include/osmium/object_pointer_collection.hpp
index bc94ec6..685211d 100644
--- a/include/osmium/object_pointer_collection.hpp
+++ b/include/osmium/object_pointer_collection.hpp
@@ -116,7 +116,7 @@ namespace osmium {
*
* Complexity: Constant.
*/
- size_t size() const noexcept {
+ std::size_t size() const noexcept {
return m_objects.size();
}
@@ -126,19 +126,19 @@ namespace osmium {
}
iterator begin() {
- return iterator{m_objects.begin()};
+ return {m_objects.begin()};
}
iterator end() {
- return iterator{m_objects.end()};
+ return {m_objects.end()};
}
const_iterator cbegin() const {
- return const_iterator{m_objects.cbegin()};
+ return {m_objects.cbegin()};
}
const_iterator cend() const {
- return const_iterator{m_objects.cend()};
+ return {m_objects.cend()};
}
}; // class ObjectPointerCollection
diff --git a/include/osmium/opl.hpp b/include/osmium/opl.hpp
index c77a6c0..9969914 100644
--- a/include/osmium/opl.hpp
+++ b/include/osmium/opl.hpp
@@ -33,8 +33,8 @@ DEALINGS IN THE SOFTWARE.
*/
-#include <osmium/memory/buffer.hpp>
#include <osmium/io/detail/opl_parser_functions.hpp>
+#include <osmium/memory/buffer.hpp>
namespace osmium {
diff --git a/include/osmium/osm/area.hpp b/include/osmium/osm/area.hpp
index a980552..12a73be 100644
--- a/include/osmium/osm/area.hpp
+++ b/include/osmium/osm/area.hpp
@@ -171,8 +171,8 @@ namespace osmium {
std::pair<size_t, size_t> num_rings() const {
std::pair<size_t, size_t> counter{0, 0};
- for (auto it = cbegin(); it != cend(); ++it) {
- switch (it->type()) {
+ for (const auto& item : *this) {
+ switch (item.type()) {
case osmium::item_type::outer_ring:
++counter.first;
break;
diff --git a/include/osmium/osm/changeset.hpp b/include/osmium/osm/changeset.hpp
index 7fbd466..d79ec31 100644
--- a/include/osmium/osm/changeset.hpp
+++ b/include/osmium/osm/changeset.hpp
@@ -61,9 +61,9 @@ namespace osmium {
friend class osmium::builder::ChangesetDiscussionBuilder;
osmium::Timestamp m_date;
- osmium::user_id_type m_uid {0};
+ osmium::user_id_type m_uid = 0;
+ changeset_comment_size_type m_text_size;
string_size_type m_user_size;
- string_size_type m_text_size;
ChangesetComment(const ChangesetComment&) = delete;
ChangesetComment(ChangesetComment&&) = delete;
@@ -94,7 +94,7 @@ namespace osmium {
m_user_size = size;
}
- void set_text_size(string_size_type size) noexcept {
+ void set_text_size(changeset_comment_size_type size) noexcept {
m_text_size = size;
}
@@ -105,8 +105,8 @@ namespace osmium {
ChangesetComment(osmium::Timestamp date, osmium::user_id_type uid) noexcept :
m_date(date),
m_uid(uid),
- m_user_size(0),
- m_text_size(0) {
+ m_text_size(0),
+ m_user_size(0) {
}
osmium::Timestamp date() const noexcept {
@@ -153,13 +153,13 @@ namespace osmium {
osmium::Box m_bounds;
osmium::Timestamp m_created_at;
osmium::Timestamp m_closed_at;
- changeset_id_type m_id {0};
- num_changes_type m_num_changes {0};
- num_comments_type m_num_comments {0};
- user_id_type m_uid {0};
- string_size_type m_user_size;
- int16_t m_padding1 {0};
- int32_t m_padding2 {0};
+ changeset_id_type m_id = 0;
+ num_changes_type m_num_changes = 0;
+ num_comments_type m_num_comments = 0;
+ user_id_type m_uid = 0;
+ string_size_type m_user_size = 0;
+ int16_t m_padding1 = 0;
+ int32_t m_padding2 = 0;
Changeset() :
OSMEntity(sizeof(Changeset), osmium::item_type::changeset) {
diff --git a/include/osmium/osm/location.hpp b/include/osmium/osm/location.hpp
index b2fdc1b..f5ae9e5 100644
--- a/include/osmium/osm/location.hpp
+++ b/include/osmium/osm/location.hpp
@@ -33,6 +33,7 @@ DEALINGS IN THE SOFTWARE.
*/
+#include <algorithm>
#include <cmath>
#include <cstdint>
#include <cstring>
@@ -198,6 +199,12 @@ namespace osmium {
// Convert integer as used by location for coordinates into a string.
template <typename T>
inline T append_location_coordinate_to_string(T iterator, int32_t value) {
+ // need to special-case this, because later `value = -value` would overflow.
+ if (value == std::numeric_limits<int32_t>::min()) {
+ static const char minresult[] = "-214.7483648";
+ return std::copy_n(minresult, sizeof(minresult) - 1, iterator);
+ }
+
// handle negative values
if (value < 0) {
*iterator++ = '-';
@@ -329,6 +336,9 @@ namespace osmium {
/**
* Check whether the coordinates of this location
* are defined.
+ *
+ * @deprecated Use is_defined() or is_undefined() or is_valid() which
+ * have all slightly different meanings.
*/
explicit constexpr operator bool() const noexcept {
return m_x != undefined_coordinate && m_y != undefined_coordinate;
@@ -337,6 +347,8 @@ namespace osmium {
/**
* Check whether the coordinates are inside the
* usual bounds (-180<=lon<=180, -90<=lat<=90).
+ *
+ * See also is_defined() and is_undefined().
*/
constexpr bool valid() const noexcept {
return m_x >= -180 * detail::coordinate_precision
@@ -345,6 +357,24 @@ namespace osmium {
&& m_y <= 90 * detail::coordinate_precision;
}
+ /**
+ * Returns true if at least one of the coordinates is defined.
+ *
+ * See also is_undefined() and is_valid().
+ */
+ constexpr bool is_defined() const noexcept {
+ return m_x != undefined_coordinate || m_y != undefined_coordinate;
+ }
+
+ /**
+ * Returns true if both coordinates are undefined.
+ *
+ * See also is_defined() and is_valid().
+ */
+ constexpr bool is_undefined() const noexcept {
+ return m_x == undefined_coordinate && m_y == undefined_coordinate;
+ }
+
constexpr int32_t x() const noexcept {
return m_x;
}
@@ -370,7 +400,7 @@ namespace osmium {
*/
double lon() const {
if (!valid()) {
- throw osmium::invalid_location("invalid location");
+ throw osmium::invalid_location{"invalid location"};
}
return fix_to_double(m_x);
}
@@ -389,7 +419,7 @@ namespace osmium {
*/
double lat() const {
if (!valid()) {
- throw osmium::invalid_location("invalid location");
+ throw osmium::invalid_location{"invalid location"};
}
return fix_to_double(m_y);
}
@@ -449,7 +479,7 @@ namespace osmium {
template <typename T>
T as_string(T iterator, const char separator = ',') const {
if (!valid()) {
- throw osmium::invalid_location("invalid location");
+ throw osmium::invalid_location{"invalid location"};
}
return as_string_without_check(iterator, separator);
}
diff --git a/include/osmium/osm/object.hpp b/include/osmium/osm/object.hpp
index 66f891a..1e477db 100644
--- a/include/osmium/osm/object.hpp
+++ b/include/osmium/osm/object.hpp
@@ -193,7 +193,7 @@ namespace osmium {
} else if (!std::strcmp("false", visible)) {
set_visible(false);
} else {
- throw std::invalid_argument("Unknown value for visible attribute (allowed is 'true' or 'false')");
+ throw std::invalid_argument{"Unknown value for visible attribute (allowed is 'true' or 'false')"};
}
return *this;
}
@@ -468,18 +468,19 @@ namespace osmium {
* ordering by timestamp is not necessary as there shouldn't be two
* objects with the same type, id, and version. But this can happen when
* creating diff files from extracts, so we take the timestamp into
- * account here.
+ * account here.
*
* Note that we use the absolute value of the id for a better ordering
- * of objects with negative id. If the IDs have the same absolute value,
- * the positive ID comes first.
+ * of objects with negative id. All the negative IDs come first, then the
+ * positive IDs. IDs are ordered by their absolute values. (This is the
+ * same ordering JOSM uses.)
*
* See object_order_type_id_reverse_version if you need a different
* ordering.
*/
inline bool operator<(const OSMObject& lhs, const OSMObject& rhs) noexcept {
- return const_tie(lhs.type(), lhs.positive_id(), lhs.id() < 0, lhs.version(), lhs.timestamp()) <
- const_tie(rhs.type(), rhs.positive_id(), rhs.id() < 0, rhs.version(), rhs.timestamp());
+ return const_tie(lhs.type(), lhs.id() > 0, lhs.positive_id(), lhs.version(), lhs.timestamp()) <
+ const_tie(rhs.type(), rhs.id() > 0, rhs.positive_id(), rhs.version(), rhs.timestamp());
}
inline bool operator>(const OSMObject& lhs, const OSMObject& rhs) noexcept {
diff --git a/include/osmium/osm/object_comparisons.hpp b/include/osmium/osm/object_comparisons.hpp
index 69dbf79..a762f19 100644
--- a/include/osmium/osm/object_comparisons.hpp
+++ b/include/osmium/osm/object_comparisons.hpp
@@ -34,6 +34,7 @@ DEALINGS IN THE SOFTWARE.
*/
#include <cassert>
+#include <cstdlib>
#include <tuple>
#include <osmium/osm/object.hpp>
@@ -44,7 +45,7 @@ namespace osmium {
/**
* Function object class for comparing OSM objects for equality by type,
- * id, and version.
+ * ID, and version.
*/
struct object_equal_type_id_version {
@@ -62,7 +63,7 @@ namespace osmium {
/**
* Function object class for comparing OSM objects for equality by type
- * and id, ignoring the version.
+ * and ID, ignoring the version.
*/
struct object_equal_type_id {
@@ -80,6 +81,19 @@ namespace osmium {
}; // struct object_equal_type_id
/**
+ * Compare two objects IDs. Order is as follows: 0 first, then negative
+ * IDs, then positive IDs, both ordered by their absolute values.
+ */
+ struct id_order {
+
+ bool operator()(const object_id_type lhs, const object_id_type rhs) const noexcept {
+ return const_tie(lhs > 0, std::abs(lhs)) <
+ const_tie(rhs > 0, std::abs(rhs));
+ }
+
+ }; // struct id_order
+
+ /**
* Function object class for ordering OSM objects by type, id, version,
* and timestamp.
*/
@@ -98,17 +112,18 @@ namespace osmium {
}; // struct object_order_type_id_version
/**
- * Function object class for ordering OSM objects by type, id, and
- * reverse version, timestamp. So objects are ordered by type and id, but
- * later versions of an object are ordered before earlier versions of the
- * same object. This is useful when the last version of an object needs
- * to be used.
+ * Function object class for ordering OSM objects by type, ID, and
+ * reverse version, timestamp. So objects are ordered by type and ID
+ * (negative IDs first, then positive IDs, both in the order of their
+ * absolute values), but later versions of an object are ordered before
+ * earlier versions of the same object. This is useful when the last
+ * version of an object needs to be used.
*/
struct object_order_type_id_reverse_version {
bool operator()(const osmium::OSMObject& lhs, const osmium::OSMObject& rhs) const noexcept {
- return const_tie(lhs.type(), lhs.id() < 0, lhs.positive_id(), rhs.version(), rhs.timestamp()) <
- const_tie(rhs.type(), rhs.id() < 0, rhs.positive_id(), lhs.version(), lhs.timestamp());
+ return const_tie(lhs.type(), lhs.id() > 0, lhs.positive_id(), rhs.version(), rhs.timestamp()) <
+ const_tie(rhs.type(), rhs.id() > 0, rhs.positive_id(), lhs.version(), lhs.timestamp());
}
/// @pre lhs and rhs must not be nullptr
diff --git a/include/osmium/osm/relation.hpp b/include/osmium/osm/relation.hpp
index deac43a..8122a1f 100644
--- a/include/osmium/osm/relation.hpp
+++ b/include/osmium/osm/relation.hpp
@@ -61,7 +61,7 @@ namespace osmium {
object_id_type m_ref;
item_type m_type;
uint16_t m_flags;
- string_size_type m_role_size {0};
+ string_size_type m_role_size = 0;
RelationMember(const RelationMember&) = delete;
RelationMember(RelationMember&&) = delete;
@@ -183,14 +183,21 @@ namespace osmium {
return t == itemtype;
}
+ /// Get a reference to the member list.
RelationMemberList& members() {
return osmium::detail::subitem_of_type<RelationMemberList>(begin(), end());
}
+ /// Get a const reference to the member list.
const RelationMemberList& members() const {
return osmium::detail::subitem_of_type<const RelationMemberList>(cbegin(), cend());
}
+ /// Get a const reference to the member list.
+ const RelationMemberList& cmembers() const {
+ return osmium::detail::subitem_of_type<const RelationMemberList>(cbegin(), cend());
+ }
+
}; // class Relation
static_assert(sizeof(Relation) % osmium::memory::align_bytes == 0, "Class osmium::Relation has wrong size to be aligned properly!");
diff --git a/include/osmium/osm/types.hpp b/include/osmium/osm/types.hpp
index 6a801c1..8c7e48a 100644
--- a/include/osmium/osm/types.hpp
+++ b/include/osmium/osm/types.hpp
@@ -58,6 +58,13 @@ namespace osmium {
*/
using string_size_type = uint16_t;
+ /**
+ * This is the size type for the text in a changeset discussion comment.
+ * There is no official limit for this. 16 bit is not enough for existing
+ * OSM changesets, hopefully 32 bit is.
+ */
+ using changeset_comment_size_type = uint32_t;
+
// maximum of 256 characters of max 4 bytes each (in UTF-8 encoding)
constexpr const int max_osm_string_length = 256 * 4;
diff --git a/include/osmium/osm/types_from_string.hpp b/include/osmium/osm/types_from_string.hpp
index d2a1421..43f6203 100644
--- a/include/osmium/osm/types_from_string.hpp
+++ b/include/osmium/osm/types_from_string.hpp
@@ -61,12 +61,14 @@ namespace osmium {
assert(input);
if (*input != '\0' && !std::isspace(*input)) {
char* end;
- auto id = std::strtoll(input, &end, 10);
- if (id != std::numeric_limits<long long>::min() && id != std::numeric_limits<long long>::max() && *end == '\0') {
+ const auto id = std::strtoll(input, &end, 10);
+ if (id != std::numeric_limits<long long>::min() &&
+ id != std::numeric_limits<long long>::max() &&
+ *end == '\0') {
return id;
}
}
- throw std::range_error(std::string("illegal id: '") + input + "'");
+ throw std::range_error{std::string{"illegal id: '"} + input + "'"};
}
/**
@@ -95,12 +97,12 @@ namespace osmium {
if (std::isdigit(*input)) {
return std::make_pair(default_type, string_to_object_id(input));
}
- osmium::item_type t = osmium::char_to_item_type(*input);
+ const osmium::item_type t = osmium::char_to_item_type(*input);
if (osmium::osm_entity_bits::from_item_type(t) & types) {
return std::make_pair(t, string_to_object_id(input + 1));
}
}
- throw std::range_error(std::string("not a valid id: '") + input + "'");
+ throw std::range_error{std::string{"not a valid id: '"} + input + "'"};
}
namespace detail {
@@ -108,12 +110,12 @@ namespace osmium {
inline unsigned long string_to_ulong(const char* input, const char* name) {
if (*input != '\0' && *input != '-' && !std::isspace(*input)) {
char* end;
- auto value = std::strtoul(input, &end, 10);
+ const auto value = std::strtoul(input, &end, 10);
if (value != std::numeric_limits<unsigned long>::max() && *end == '\0') {
return value;
}
}
- throw std::range_error(std::string("illegal ") + name + ": '" + input + "'");
+ throw std::range_error{std::string{"illegal "} + name + ": '" + input + "'"};
}
} // namespace detail
diff --git a/include/osmium/relations/collector.hpp b/include/osmium/relations/collector.hpp
index dfb6da8..ccfed99 100644
--- a/include/osmium/relations/collector.hpp
+++ b/include/osmium/relations/collector.hpp
@@ -250,7 +250,7 @@ namespace osmium {
* this is for instance used to only keep members of type way and
* ignore all others.
*/
- bool keep_member(const osmium::relations::RelationMeta& /*relation_meta*/, const osmium::RelationMember& /*member*/) const {
+ bool keep_member(const RelationMeta& /*relation_meta*/, const osmium::RelationMember& /*member*/) const {
return true;
}
@@ -419,7 +419,7 @@ namespace osmium {
return true;
}
- void clear_member_metas(const osmium::relations::RelationMeta& relation_meta) {
+ void clear_member_metas(const RelationMeta& relation_meta) {
const osmium::Relation& relation = get_relation(relation_meta);
for (const auto& member : relation.members()) {
if (member.ref() != 0) {
@@ -539,9 +539,8 @@ namespace osmium {
assert(!range.empty());
if (range.begin()->is_available()) {
return std::make_pair(true, range.begin()->buffer_offset());
- } else {
- return std::make_pair(false, 0);
}
+ return std::make_pair(false, 0);
}
template <typename TIter>
diff --git a/include/osmium/relations/manager_util.hpp b/include/osmium/relations/manager_util.hpp
new file mode 100644
index 0000000..1ee8dd4
--- /dev/null
+++ b/include/osmium/relations/manager_util.hpp
@@ -0,0 +1,197 @@
+#ifndef OSMIUM_RELATIONS_MANAGER_UTIL_HPP
+#define OSMIUM_RELATIONS_MANAGER_UTIL_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2017 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstddef>
+#include <initializer_list>
+#include <iomanip>
+#include <utility>
+
+#include <osmium/fwd.hpp>
+#include <osmium/handler.hpp>
+#include <osmium/handler/check_order.hpp>
+#include <osmium/io/file.hpp>
+#include <osmium/io/reader.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/osm/entity_bits.hpp>
+#include <osmium/util/progress_bar.hpp>
+#include <osmium/visitor.hpp>
+
+namespace osmium {
+
+ namespace relations {
+
+ /**
+ * This is a handler class used for the second pass of relation
+ * managers. An object of this class is instantiated as a member
+ * of the Manager and used to re-direct all calls to the handler
+ * to the "parent" manager.
+ *
+ * @tparam TManager The manager we want to call functions on.
+ */
+ template <typename TManager>
+ class SecondPassHandler : public osmium::handler::Handler {
+
+ TManager& m_manager;
+
+ public:
+
+ explicit SecondPassHandler(TManager& manager) noexcept :
+ m_manager(manager) {
+ }
+
+ /**
+ * Overwrites the function in the handler parent class.
+ */
+ void node(const osmium::Node& node) {
+ m_manager.handle_node(node);
+ }
+
+ /**
+ * Overwrites the function in the handler parent class.
+ */
+ void way(const osmium::Way& way) {
+ m_manager.handle_way(way);
+ }
+
+ /**
+ * Overwrites the function in the handler parent class.
+ */
+ void relation(const osmium::Relation& relation) {
+ m_manager.handle_relation(relation);
+ }
+
+ /**
+ * Overwrites the function in the handler parent class.
+ *
+ * Calls the flush_output() function on the manager.
+ */
+ void flush() {
+ m_manager.flush_output();
+ }
+
+ }; // class SecondPassHandler
+
+ /**
+ * Read relations from file and feed them into all the managers
+ * specified as parameters. Opens an osmium::io::Reader internally
+ * with the file parameter.
+ *
+ * After the file is read, the prepare_for_lookup() function is called
+ * on all the managers making them ready for querying the data they
+ * have stored.
+ *
+ * @tparam TManager Any number of relation manager types.
+ * @param file The file that should be opened with an osmium::io::Reader.
+ * @param managers Relation managers we want the relations to be sent
+ * to.
+ */
+ template <typename ...TManager>
+ void read_relations(const osmium::io::File& file, TManager&& ...managers) {
+ static_assert(sizeof...(TManager) > 0, "Need at least one manager as parameter.");
+ osmium::io::Reader reader{file, osmium::osm_entity_bits::relation};
+ osmium::apply(reader, std::forward<TManager>(managers)...);
+ reader.close();
+ (void)std::initializer_list<int>{
+ (std::forward<TManager>(managers).prepare_for_lookup(), 0)...
+ };
+ }
+
+ /**
+ * Read relations from file and feed them into all the managers
+ * specified as parameters. Opens an osmium::io::Reader internally
+ * with the file parameter.
+ *
+ * After the file is read, the prepare_for_lookup() function is called
+ * on all the managers making them ready for querying the data they
+ * have stored.
+ *
+ * @tparam TManager Any number of relation manager types.
+ * @param progress_bar Reference to osmium::ProgressBar object that
+ * will be updated while reading the data.
+ * @param file The file that should be opened with an osmium::io::Reader.
+ * @param managers Relation managers we want the relations to be sent
+ * to.
+ */
+ template <typename ...TManager>
+ void read_relations(osmium::ProgressBar& progress_bar, const osmium::io::File& file, TManager&& ...managers) {
+ static_assert(sizeof...(TManager) > 0, "Need at least one manager as parameter.");
+ osmium::io::Reader reader{file, osmium::osm_entity_bits::relation};
+ while (auto buffer = reader.read()) {
+ progress_bar.update(reader.offset());
+ osmium::apply(buffer, std::forward<TManager>(managers)...);
+ }
+ reader.close();
+ (void)std::initializer_list<int>{
+ (std::forward<TManager>(managers).prepare_for_lookup(), 0)...
+ };
+ progress_bar.file_done(file.size());
+ }
+
+ /**
+ * Struct for memory usage numbers returned by various relations
+ * managers from the used_memory() function.
+ */
+ struct relations_manager_memory_usage {
+ std::size_t relations_db;
+ std::size_t members_db;
+ std::size_t stash;
+ };
+
+ /**
+ * Prints relations managers memory usage numbers to the specified
+ * stream.
+ *
+ * @tparam TStream Output stream type (like std::cout, std::cerr, or
+ * osmium::util::VerboseOutput).
+ * @param stream Reference to stream where the output should go.
+ * @param mu Memory usage data as returned by the used_memory()
+ * functions of various relations managers.
+ */
+ template <typename TStream>
+ void print_used_memory(TStream& stream, const relations_manager_memory_usage& mu) {
+ const auto total = mu.relations_db + mu.members_db + mu.stash;
+
+ stream << " relations: " << std::setw(8) << (mu.relations_db / 1024) << " kB\n"
+ << " members: " << std::setw(8) << (mu.members_db / 1024) << " kB\n"
+ << " stash: " << std::setw(8) << (mu.stash / 1024) << " kB\n"
+ << " total: " << std::setw(8) << (total / 1024) << " kB\n"
+ << " ======================\n";
+ }
+
+ } // namespace relations
+
+} // namespace osmium
+
+#endif // OSMIUM_RELATIONS_MANAGER_UTIL_HPP
diff --git a/include/osmium/relations/members_database.hpp b/include/osmium/relations/members_database.hpp
new file mode 100644
index 0000000..975f003
--- /dev/null
+++ b/include/osmium/relations/members_database.hpp
@@ -0,0 +1,406 @@
+#ifndef OSMIUM_RELATIONS_MEMBERS_DATABASE_HPP
+#define OSMIUM_RELATIONS_MEMBERS_DATABASE_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2017 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <limits>
+#include <tuple>
+#include <type_traits>
+#include <vector>
+
+#include <osmium/osm/object.hpp>
+#include <osmium/osm/relation.hpp>
+#include <osmium/osm/types.hpp>
+#include <osmium/relations/relations_database.hpp>
+#include <osmium/storage/item_stash.hpp>
+#include <osmium/util/iterator.hpp>
+
+namespace osmium {
+
+ namespace relations {
+
+ /**
+ * This is the parent class for the MembersDatabase class. All the
+ * functionality which doesn't depend on the template parameter used
+ * in derived databases is contained in this class.
+ *
+ * Usually you want to use the MembersDatabase class only.
+ */
+ class MembersDatabaseCommon {
+
+ struct element {
+
+ /**
+ * Special value used for member_num to mark the element as
+ * removed.
+ */
+ static const size_t removed_value = std::numeric_limits<std::size_t>::max();
+
+ /**
+ * Object ID of this relation member. Can be a node, way,
+ * or relation ID. It depends on the database in which this
+ * object is stored which kind of object is referenced here.
+ */
+ osmium::object_id_type member_id;
+
+ /**
+ * Position of this member in the parent relation.
+ */
+ std::size_t member_num;
+
+ /**
+ * Position of the parent relation in the relations database.
+ */
+ std::size_t relation_pos;
+
+ /**
+ * Handle to the stash where the object is stored.
+ *
+ * The default value is the invalid one signifying that the
+ * object hasn't been found yet.
+ */
+ osmium::ItemStash::handle_type object_handle;
+
+ explicit element(std::size_t rel_pos, osmium::object_id_type memb_id, std::size_t memb_num) noexcept :
+ member_id(memb_id),
+ member_num(memb_num),
+ relation_pos(rel_pos) {
+ }
+
+ /**
+ * This constructor is used to create dummy elements that
+ * can be compared to the elements in a vector using the
+ * equal_range algorithm.
+ */
+ explicit element(osmium::object_id_type m_id) noexcept :
+ member_id(m_id),
+ member_num(0),
+ relation_pos(0) {
+ }
+
+ bool is_removed() const noexcept {
+ return member_num == removed_value;
+ }
+
+ void remove() noexcept {
+ member_num = removed_value;
+ }
+
+ bool operator<(const element& other) const noexcept {
+ return std::tie(member_id, member_num, relation_pos) <
+ std::tie(other.member_id, other.member_num, other.relation_pos);
+ }
+
+ }; // struct element
+
+ // comparison function only comparing member_id.
+ struct compare_member_id {
+ bool operator()(const element& a, const element& b) const noexcept {
+ return a.member_id < b.member_id;
+ }
+ };
+
+ std::vector<element> m_elements;
+
+ protected:
+
+ osmium::ItemStash& m_stash;
+ osmium::relations::RelationsDatabase& m_relations_db;
+
+#ifndef NDEBUG
+ // This is used only in debug builds to make sure the
+ // prepare_for_lookup() function is called at the right place.
+ bool m_init_phase = true;
+#endif
+
+ using iterator = std::vector<element>::iterator;
+ using const_iterator = std::vector<element>::const_iterator;
+
+ iterator_range<iterator> find(osmium::object_id_type id) {
+ return make_range(std::equal_range(m_elements.begin(), m_elements.end(), element{id}, compare_member_id{}));
+ }
+
+ iterator_range<const_iterator> find(osmium::object_id_type id) const {
+ return make_range(std::equal_range(m_elements.cbegin(), m_elements.cend(), element{id}, compare_member_id{}));
+ }
+
+ static typename iterator_range<iterator>::iterator::difference_type count_not_removed(const iterator_range<iterator>& range) noexcept {
+ return std::count_if(range.begin(), range.end(), [](const element& elem) {
+ return !elem.is_removed();
+ });
+ }
+
+ void add_object(const osmium::OSMObject& object, iterator_range<iterator>& range) {
+ const auto handle = m_stash.add_item(object);
+ for (auto& elem : range) {
+ elem.object_handle = handle;
+ }
+ }
+
+ MembersDatabaseCommon(osmium::ItemStash& stash, osmium::relations::RelationsDatabase& relations_db) :
+ m_elements(),
+ m_stash(stash),
+ m_relations_db(relations_db) {
+ }
+
+ public:
+
+ /**
+ * Return an estimate of the number of bytes currently needed
+ * for the MembersDatabase. This does NOT include the memory used
+ * in the stash. Used for debugging.
+ */
+ std::size_t used_memory() const noexcept {
+ return sizeof(element) * m_elements.capacity() +
+ sizeof(MembersDatabaseCommon);
+ }
+
+ /**
+ * The number of members tracked in the database. Includes
+ * members tracked, but not found yet, members found and members
+ * marked as removed.
+ *
+ * Complexity: Constant.
+ */
+ std::size_t size() const noexcept {
+ return m_elements.size();
+ }
+
+ /**
+ * Result from the count() function.
+ */
+ struct counts {
+ /// The number of members tracked and not found yet.
+ std::size_t tracked = 0;
+ /// The number of members tracked and found already.
+ std::size_t available = 0;
+ /// The number of members that were tracked, found and then removed because of a completed relation.
+ std::size_t removed = 0;
+ };
+
+ /**
+ * Counts the number of members in different states. Usually only
+ * used for testing and debugging.
+ *
+ * Complexity: Linear in the number of members tracked.
+ */
+ counts count() const noexcept {
+ counts c;
+
+ for (const auto& elem : m_elements) {
+ if (elem.is_removed()) {
+ ++c.removed;
+ } else if (elem.object_handle.valid()) {
+ ++c.available;
+ } else {
+ ++c.tracked;
+ }
+ }
+
+ return c;
+ }
+
+ /**
+ * Tell the database that you are interested in an object with
+ * the specified id and that it is a member of the given relation
+ * (as specified through the relation handle).
+ *
+ * @param rel_handle Relation this object is a member of.
+ * @param member_id Id of an object of type TObject.
+ * @param member_num This is the nth member in the relation.
+ */
+ void track(RelationHandle& rel_handle, osmium::object_id_type member_id, std::size_t member_num) {
+ assert(m_init_phase && "Can not call MembersDatabase::track() after MembersDatabase::prepare_for_lookup().");
+ assert(rel_handle.relation_database() == &m_relations_db);
+ m_elements.emplace_back(rel_handle.pos(), member_id, member_num);
+ rel_handle.increment_members();
+ }
+
+ /**
+ * Prepare the database for lookup. Call this function after
+ * calling track() for all objects needed and before adding
+ * the first object with add() or querying the first object
+ * with get(). You can only call this function once.
+ */
+ void prepare_for_lookup() {
+ assert(m_init_phase && "Can not call MembersDatabase::prepare_for_lookup() twice.");
+ std::sort(m_elements.begin(), m_elements.end());
+#ifndef NDEBUG
+ m_init_phase = false;
+#endif
+ }
+
+ /**
+ * Remove the entry with the specified member_id and relation_id
+ * from the database. If the entry doesn't exist, nothing happens.
+ */
+ void remove(osmium::object_id_type member_id, osmium::object_id_type relation_id) {
+ const auto range = find(member_id);
+
+ if (range.empty()) {
+ return;
+ }
+
+ // If this is the last time this object was needed, remove it
+ // from the stash.
+ if (count_not_removed(range) == 1) {
+ m_stash.remove_item(range.begin()->object_handle);
+ }
+
+ for (auto& elem : range) {
+ if (!elem.is_removed() && relation_id == m_relations_db[elem.relation_pos]->id()) {
+ elem.remove();
+ break;
+ }
+ }
+ }
+
+ /**
+ * Find the object with the specified id in the database and
+ * return a pointer to it. Returns nullptr if there is no object
+ * with that id in the database.
+ *
+ * Complexity: Logarithmic in the number of members tracked (as
+ * returned by size()).
+ */
+ const osmium::OSMObject* get_object(osmium::object_id_type id) const {
+ assert(!m_init_phase && "Call MembersDatabase::prepare_for_lookup() before calling get_object().");
+ const auto range = find(id);
+ if (range.empty()) {
+ return nullptr;
+ }
+ const auto handle = range.begin()->object_handle;
+ if (handle.valid()) {
+ return &m_stash.get<osmium::OSMObject>(handle);
+ }
+ return nullptr;
+ }
+
+ }; // class MembersDatabaseCommon
+
+ /**
+ * A MembersDatabase is used together with a RelationsDatabase to
+ * bring a relation and their members together. It tracks all members
+ * of a specific type needed to complete a relation.
+ *
+ * More documentation is in the MembersDatabaseCommon parent class
+ * which contains all the pieces that aren't dependent on the
+ * template parameter.
+ *
+ * @tparam TObject The object type stores in the members database.
+ * Can be osmium::Node, Way, or Relation.
+ */
+ template <typename TObject>
+ class MembersDatabase : public MembersDatabaseCommon {
+
+ static_assert(std::is_base_of<osmium::OSMObject, TObject>::value, "TObject must be osmium::Node, Way, or Relation.");
+
+ public:
+
+ /**
+ * Construct a MembersDatabase.
+ *
+ * @param stash Reference to an ItemStash object. All member objects
+ * will be stored in this stash. It must be available
+ * until the MembersDatabase is destroyed.
+ * @param relation_db The RelationsDatabase where relations are
+ * stored. Usually it will use the same ItemStash
+ * as the MembersDatabase.
+ */
+ MembersDatabase(osmium::ItemStash& stash, osmium::relations::RelationsDatabase& relation_db) :
+ MembersDatabaseCommon(stash, relation_db) {
+ }
+
+ /**
+ * Add the specified object to the database.
+ *
+ * @param object Object to add.
+ * @param func If the object is the last member to complete a
+ * relation, this function is called with the relation
+ * as a parameter.
+ * @returns true if the object was actually added, false if no
+ * relation needed this object.
+ */
+ template <typename TFunc>
+ bool add(const TObject& object, TFunc&& func) {
+ assert(!m_init_phase && "Call MembersDatabase::prepare_for_lookup() before calling add().");
+ auto range = find(object.id());
+
+ if (range.empty()) {
+ // No relation needs this object.
+ return false;
+ }
+
+ // At least one relation needs this object. Store it and
+ // "tell" all relations.
+ add_object(object, range);
+
+ for (auto& elem : range) {
+ assert(!elem.is_removed());
+ assert(elem.member_id == object.id());
+
+ auto rel_handle = m_relations_db[elem.relation_pos];
+ assert(elem.member_num < rel_handle->members().size());
+ rel_handle.decrement_members();
+
+ if (rel_handle.has_all_members()) {
+ func(rel_handle);
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Find the object with the specified id in the database and
+ * return a pointer to it. Returns nullptr if there is no object
+ * with that id in the database.
+ *
+ * Complexity: Logarithmic in the number of members tracked (as
+ * returned by size()).
+ */
+ const TObject* get(osmium::object_id_type id) const {
+ assert(!m_init_phase && "Call MembersDatabase::prepare_for_lookup() before calling get().");
+ return static_cast<const TObject*>(get_object(id));
+ }
+
+ }; // class MembersDatabase
+
+ } // namespace relations
+
+} // namespace osmium
+
+#endif // OSMIUM_RELATIONS_MEMBERS_DATABASE_HPP
diff --git a/include/osmium/relations/relations_database.hpp b/include/osmium/relations/relations_database.hpp
new file mode 100644
index 0000000..80dd102
--- /dev/null
+++ b/include/osmium/relations/relations_database.hpp
@@ -0,0 +1,335 @@
+#ifndef OSMIUM_RELATIONS_RELATIONS_DATABASE_HPP
+#define OSMIUM_RELATIONS_RELATIONS_DATABASE_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2017 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <utility>
+#include <vector>
+
+#include <osmium/osm/relation.hpp>
+#include <osmium/storage/item_stash.hpp>
+
+namespace osmium {
+
+ namespace relations {
+
+ class RelationHandle;
+
+ /**
+ * The RelationsDatabase is used for bringing relations and their
+ * members together. It stores the relations in memory and keeps
+ * track of how many members are needed to "complete" the relation.
+ * It is intended to work together with the MembersDatabase template
+ * class and usually used by relations manager classes.
+ *
+ * To access relations stored in the database a RelationHandle is
+ * used. It is returned from the add() function. The handle is used
+ * for all operations on the database contents, such as accessing
+ * the stored relation, incrementing the member count or removing a
+ * relation from the database.
+ *
+ * From the handle a "position" can be accessed, which, together with
+ * the database object, can be turned into a handle again. The position
+ * alone is smaller than the handle, so it can be stored elsewhere more
+ * efficiently. Specifically this is used in the MembersDatabase.
+ *
+ * @code
+ * osmium::ItemStash stash;
+ * osmium::relations::RelationsDatabase db{stash};
+ * auto handle = db.add(relation);
+ * auto pos = handle.pos();
+ * auto second_handle = db[pos];
+ * @endcode
+ *
+ * Now the `handle` and `second_handle` refer to the same relation.
+ *
+ * See the RelationHandle for information about what you can do with
+ * it.
+ */
+ class RelationsDatabase {
+
+ friend class RelationHandle;
+
+ struct element {
+
+ /// A handle to the relation in the ItemStash.
+ osmium::ItemStash::handle_type handle;
+
+ /**
+ * The number of members still needed before the relation is
+ * complete. This will be set to the number of members we are
+ * interested in (which can be all members of a relation or
+ * a subset of them) and then count down for every member we
+ * find. When it is 0, the relation is complete.
+ */
+ std::size_t members;
+
+ }; // struct element
+
+ osmium::ItemStash& m_stash;
+ std::vector<element> m_elements;
+
+ osmium::Relation& get_relation(std::size_t pos) {
+ assert(pos < m_elements.size());
+ return m_stash.get<osmium::Relation>(m_elements[pos].handle);
+ }
+
+ /**
+ * Access the number of members of the entry at the specified
+ * position. This returns a reference so it can be changed.
+ */
+ std::size_t& members(std::size_t pos) noexcept {
+ return m_elements[pos].members;
+ }
+
+ void remove(std::size_t pos) {
+ auto& elem = m_elements[pos];
+ m_stash.remove_item(elem.handle);
+ elem = element{osmium::ItemStash::handle_type{}, 0};
+ }
+
+ public:
+
+ /**
+ * Construct a RelationsDatabase.
+ *
+ * @param stash Reference to an ItemStash object. All relations
+ * will be stored in this stash. It must be available
+ * until the RelationsDatabase is destroyed.
+ */
+ explicit RelationsDatabase(osmium::ItemStash& stash) :
+ m_stash(stash) {
+ }
+
+ /**
+ * Return an estimate of the number of bytes currently needed for
+ * the RelationsDatabase. This does NOT include the memory used
+ * in the stash. Used for debugging.
+ *
+ * Complexity: Constant.
+ */
+ std::size_t used_memory() const noexcept {
+ return sizeof(element) * m_elements.capacity() +
+ sizeof(RelationsDatabase);
+ }
+
+ /**
+ * The number of relations stored in the database. Includes
+ * relations marked as removed.
+ *
+ * Complexity: Constant.
+ */
+ std::size_t size() const noexcept {
+ return m_elements.size();
+ }
+
+ /**
+ * Insert a relation into the database. The relation is copied
+ * into the stash.
+ *
+ * Complexity: Amortized constant.
+ *
+ * @param relation The relation to be copied into the database.
+ * @returns A handle to the relation.
+ */
+ RelationHandle add(const osmium::Relation& relation);
+
+ /**
+ * Return a handle to the relation at the specified position in
+ * the database.
+ *
+ * Complexity: Constant.
+ */
+ RelationHandle operator[](std::size_t pos) noexcept;
+
+ /**
+ * Return the number of non-removed relations in the database.
+ *
+ * Complexity: Linear in the number of relations (as returned
+ * by size()).
+ */
+ std::size_t count_relations() const noexcept {
+ return std::count_if(m_elements.cbegin(), m_elements.cend(), [&](const element& elem) {
+ return elem.handle.valid();
+ });
+ }
+
+ /**
+ * Iterate over all (not-removed) relations in the database.
+ *
+ * @tparam TFunc Function with type void(const RelationHandle&).
+ * @param func Callback function which will be called for every
+ * not-removed relation with a RelationHandle.
+ */
+ template <typename TFunc>
+ void for_each_relation(TFunc&& func);
+
+ }; // RelationsDatabase
+
+ /**
+ * A RelationHandle is used to access elements in a RelationsDatabase.
+ *
+ * RelationHandles can not be created by user code, they are only
+ * given out by a RelationsDatabase object.
+ */
+ class RelationHandle {
+
+ friend class RelationsDatabase;
+
+ RelationsDatabase* m_relation_database;
+ std::size_t m_pos;
+
+ RelationHandle(RelationsDatabase* relation_database, std::size_t pos) :
+ m_relation_database(relation_database),
+ m_pos(pos) {
+ }
+
+ public:
+
+ /**
+ * The RelationsDatabase this handle refers to.
+ */
+ RelationsDatabase* relation_database() const noexcept {
+ return m_relation_database;
+ }
+
+ /**
+ * The position of the element in the RelationsDatabase. Use the
+ * RelationsDatabase::operator[] to get the handle back from this
+ * position:
+ * @code
+ * auto pos = handle.pos();
+ * auto second_handle = relation_db[pos];
+ * @endcode
+ */
+ std::size_t pos() const noexcept {
+ return m_pos;
+ }
+
+ /**
+ * Access the relation stored in the database.
+ */
+ Relation& operator*() {
+ return m_relation_database->get_relation(m_pos);
+ }
+
+ /**
+ * Access the relation stored in the database.
+ */
+ const Relation& operator*() const {
+ return m_relation_database->get_relation(m_pos);
+ }
+
+ /**
+ * Call a function on the relation stored in the database.
+ */
+ Relation* operator->() {
+ return &m_relation_database->get_relation(m_pos);
+ }
+
+ /**
+ * Call a function on the relation stored in the database.
+ */
+ const Relation* operator->() const {
+ return &m_relation_database->get_relation(m_pos);
+ }
+
+ /**
+ * Remove the relation referred to by this handle from the database.
+ * All handles referring to this database element become invalid.
+ */
+ void remove() {
+ m_relation_database->remove(pos());
+ }
+
+ /**
+ * Set the number of relation members that we want to track.
+ */
+ void set_members(std::size_t value) noexcept {
+ m_relation_database->members(m_pos) = value;
+ }
+
+ /**
+ * Increment the number of relation members that we want to track.
+ */
+ void increment_members() noexcept {
+ ++(m_relation_database->members(m_pos));
+ }
+
+ /**
+ * Decrement the number of relation members that we want to track.
+ *
+ * @pre @code has_all_members() == false @endcode
+ */
+ void decrement_members() noexcept {
+ assert(m_relation_database->members(m_pos) > 0);
+ --(m_relation_database->members(m_pos));
+ }
+
+ /**
+ * Do we have all members? This is true if the number of tracked
+ * members is zero.
+ */
+ bool has_all_members() const noexcept {
+ return m_relation_database->members(m_pos) == 0;
+ }
+
+ }; // class RelationHandle
+
+ inline RelationHandle RelationsDatabase::operator[](std::size_t pos) noexcept {
+ assert(pos < m_elements.size());
+ return {this, pos};
+ }
+
+ inline RelationHandle RelationsDatabase::add(const osmium::Relation& relation) {
+ m_elements.push_back(element{m_stash.add_item(relation), 0});
+ return {this, m_elements.size() - 1};
+ }
+
+ template <typename TFunc>
+ void RelationsDatabase::for_each_relation(TFunc&& func) {
+ for (std::size_t pos = 0; pos < m_elements.size(); ++pos) {
+ if (m_elements[pos].handle.valid()) {
+ std::forward<TFunc>(func)(RelationHandle{this, pos});
+ }
+ }
+ }
+
+ } // namespace relations
+
+} // namespace osmium
+
+#endif // OSMIUM_RELATIONS_RELATIONS_DATABASE_HPP
diff --git a/include/osmium/relations/relations_manager.hpp b/include/osmium/relations/relations_manager.hpp
new file mode 100644
index 0000000..1831cb6
--- /dev/null
+++ b/include/osmium/relations/relations_manager.hpp
@@ -0,0 +1,567 @@
+#ifndef OSMIUM_RELATIONS_RELATIONS_MANAGER_HPP
+#define OSMIUM_RELATIONS_RELATIONS_MANAGER_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2017 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <stdexcept>
+#include <type_traits>
+#include <vector>
+
+#include <osmium/handler.hpp>
+#include <osmium/handler/check_order.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/memory/callback_buffer.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/relation.hpp>
+#include <osmium/osm/tag.hpp>
+#include <osmium/osm/way.hpp>
+#include <osmium/relations/manager_util.hpp>
+#include <osmium/relations/members_database.hpp>
+#include <osmium/relations/relations_database.hpp>
+#include <osmium/storage/item_stash.hpp>
+#include <osmium/tags/taglist.hpp>
+#include <osmium/tags/tags_filter.hpp>
+
+namespace osmium {
+
+ namespace relations {
+
+ /**
+ * This is a base class of the RelationsManager class template. It
+ * contains databases for the relations and the members that we need
+ * to keep track of and handles the ouput buffer. Unlike the
+ * RelationsManager class template this is a plain class.
+ *
+ * Usually it is better to use the RelationsManager class template
+ * as a basis for your code, but you can also use this class if you
+ * have special needs.
+ */
+ class RelationsManagerBase : public osmium::handler::Handler {
+
+ // All relations and members we are interested in will be kept
+ // in here.
+ osmium::ItemStash m_stash;
+
+ /// Database of all relations we are interested in.
+ relations::RelationsDatabase m_relations_db;
+
+ /// Databases of all members we are interested in.
+ relations::MembersDatabase<osmium::Node> m_member_nodes_db;
+ relations::MembersDatabase<osmium::Way> m_member_ways_db;
+ relations::MembersDatabase<osmium::Relation> m_member_relations_db;
+
+ /// Output buffer.
+ osmium::memory::CallbackBuffer m_output;
+
+ public:
+
+ RelationsManagerBase() :
+ m_stash(),
+ m_relations_db(m_stash),
+ m_member_nodes_db(m_stash, m_relations_db),
+ m_member_ways_db(m_stash, m_relations_db),
+ m_member_relations_db(m_stash, m_relations_db),
+ m_output() {
+ }
+
+ /// Access the internal RelationsDatabase.
+ osmium::relations::RelationsDatabase& relations_database() noexcept {
+ return m_relations_db;
+ }
+
+ /// Access the internal database containing member nodes.
+ osmium::relations::MembersDatabase<osmium::Node>& member_nodes_database() noexcept {
+ return m_member_nodes_db;
+ }
+
+ /// Access the internal database containing member nodes.
+ const osmium::relations::MembersDatabase<osmium::Node>& member_nodes_database() const noexcept {
+ return m_member_nodes_db;
+ }
+
+ /// Access the internal database containing member ways.
+ osmium::relations::MembersDatabase<osmium::Way>& member_ways_database() noexcept {
+ return m_member_ways_db;
+ }
+
+ /// Access the internal database containing member ways.
+ const osmium::relations::MembersDatabase<osmium::Way>& member_ways_database() const noexcept {
+ return m_member_ways_db;
+ }
+
+ /// Access the internal database containing member relations.
+ osmium::relations::MembersDatabase<osmium::Relation>& member_relations_database() noexcept {
+ return m_member_relations_db;
+ }
+
+ /// Access the internal database containing member relations.
+ const osmium::relations::MembersDatabase<osmium::Relation>& member_relations_database() const noexcept {
+ return m_member_relations_db;
+ }
+
+ /**
+ * Access the internal database containing members of the
+ * specified type (non-const version of this function).
+ *
+ * @param type osmium::item_type::node, way, or relation.
+ */
+ relations::MembersDatabaseCommon& member_database(osmium::item_type type) {
+ switch (type) {
+ case osmium::item_type::node:
+ return m_member_nodes_db;
+ case osmium::item_type::way:
+ return m_member_ways_db;
+ case osmium::item_type::relation:
+ return m_member_relations_db;
+ default:
+ break;
+ }
+ throw std::logic_error{"Should not be here."};
+ }
+
+ /**
+ * Access the internal database containing members of the
+ * specified type (const version of this function).
+ *
+ * @param type osmium::item_type::node, way, or relation.
+ */
+ const relations::MembersDatabaseCommon& member_database(osmium::item_type type) const {
+ switch (type) {
+ case osmium::item_type::node:
+ return m_member_nodes_db;
+ case osmium::item_type::way:
+ return m_member_ways_db;
+ case osmium::item_type::relation:
+ return m_member_relations_db;
+ default:
+ break;
+ }
+ throw std::logic_error{"Should not be here."};
+ }
+
+ /**
+ * Get member object from relation member.
+ *
+ * @returns A pointer to the member object if it is available.
+ * Returns nullptr otherwise.
+ */
+ const osmium::OSMObject* get_member_object(const osmium::RelationMember& member) const noexcept {
+ if (member.ref() == 0) {
+ return nullptr;
+ }
+ return member_database(member.type()).get_object(member.ref());
+ }
+
+ /**
+ * Get node with specified ID from members database.
+ *
+ * @param id The node ID we are looking for.
+ * @returns A pointer to the member node if it is available.
+ * Returns nullptr otherwise.
+ */
+ const osmium::Node* get_member_node(osmium::object_id_type id) const noexcept {
+ if (id == 0) {
+ return nullptr;
+ }
+ return member_nodes_database().get(id);
+ }
+
+ /**
+ * Get way with specified ID from members database.
+ *
+ * @param id The way ID we are looking for.
+ * @returns A pointer to the member way if it is available.
+ * Returns nullptr otherwise.
+ */
+ const osmium::Way* get_member_way(osmium::object_id_type id) const noexcept {
+ if (id == 0) {
+ return nullptr;
+ }
+ return member_ways_database().get(id);
+ }
+
+ /**
+ * Get relation with specified ID from members database.
+ *
+ * @param id The relation ID we are looking for.
+ * @returns A pointer to the member relation if it is available.
+ * Returns nullptr otherwise.
+ */
+ const osmium::Relation* get_member_relation(osmium::object_id_type id) const noexcept {
+ if (id == 0) {
+ return nullptr;
+ }
+ return member_relations_database().get(id);
+ }
+
+ /**
+ * Sort the members databases to prepare them for reading. Usually
+ * this is called between the first and second pass reading through
+ * an OSM data file.
+ */
+ void prepare_for_lookup() {
+ m_member_nodes_db.prepare_for_lookup();
+ m_member_ways_db.prepare_for_lookup();
+ m_member_relations_db.prepare_for_lookup();
+ }
+
+ /**
+ * Return the memory used by different components of the manager.
+ */
+ relations_manager_memory_usage used_memory() const noexcept {
+ return {
+ m_relations_db.used_memory(),
+ m_member_nodes_db.used_memory()
+ + m_member_ways_db.used_memory()
+ + m_member_relations_db.used_memory(),
+ m_stash.used_memory()
+ };
+ }
+
+ /// Access the output buffer.
+ osmium::memory::Buffer& buffer() noexcept {
+ return m_output.buffer();
+ }
+
+ /// Set the callback called when the output buffer is full.
+ void set_callback(const std::function<void(osmium::memory::Buffer&&)>& callback) {
+ m_output.set_callback(callback);
+ }
+
+ /// Flush the output buffer.
+ void flush_output() {
+ m_output.flush();
+ }
+
+ /// Flush the output buffer if it is full.
+ void possibly_flush() {
+ m_output.possibly_flush();
+ }
+
+ /// Return the contents of the output buffer.
+ osmium::memory::Buffer read() {
+ return m_output.read();
+ }
+
+ }; // class RelationsManagerBase
+
+ /**
+ * This is a base class for RelationManager classes. It keeps track of
+ * all interesting relations and all interesting members of those
+ * relations. When all members are available it calls code to handle
+ * the completed relation.
+ *
+ * This class is intended as a base class for classes that handle
+ * specific types of relations. Derive from this class, implement
+ * the complete_relation() function and overwrite certain other
+ * functions as needed.
+ *
+ * @tparam TManager The derived class (Uses CRTP).
+ * @tparam TNodes Are we interested in member nodes?
+ * @tparam TWays Are we interested in member ways?
+ * @tparam TRelations Are we interested in member relations?
+ * @tparam TCheckOrder Should the order of the input data be checked?
+ *
+ * @pre The Ids of all objects must be unique in the input data.
+ */
+ template <typename TManager, bool TNodes, bool TWays, bool TRelations, bool TCheckOrder = true>
+ class RelationsManager : public RelationsManagerBase {
+
+ using check_order_handler = typename std::conditional<TCheckOrder, osmium::handler::CheckOrder, osmium::handler::Handler>::type;
+
+ check_order_handler m_check_order_handler;
+
+ SecondPassHandler<RelationsManager> m_handler_pass2;
+
+ static bool wanted_type(osmium::item_type type) noexcept {
+ return (TNodes && type == osmium::item_type::node) ||
+ (TWays && type == osmium::item_type::way) ||
+ (TRelations && type == osmium::item_type::relation);
+ }
+
+ /**
+ * This method is called from the first pass handler for every
+ * relation in the input, to check whether it should be kept.
+ *
+ * Overwrite this method in a derived class to only add relations
+ * you are interested in, for instance depending on the type tag.
+ * Storing relations takes a lot of memory, so it makes sense to
+ * filter this as much as possible.
+ */
+ bool new_relation(const osmium::Relation& /*relation*/) const noexcept {
+ return true;
+ }
+
+ /**
+ * This method is called for every member of every relation that
+ * will be kept. It should decide if the member is interesting or
+ * not and return true or false to signal that. Only interesting
+ * members are later added to the relation.
+ *
+ * Overwrite this method in a derived class. In the
+ * MultipolygonManager class this is used for instance to only
+ * keep members of type way and ignore all others.
+ */
+ bool new_member(const osmium::Relation& /*relation*/, const osmium::RelationMember& /*member*/, std::size_t /*n*/) const noexcept {
+ return true;
+ }
+
+ /**
+ * This method is called for each complete relation, ie when
+ * all members you have expressed interest in are available.
+ *
+ * You have to overwrite this in a derived class.
+ */
+ void complete_relation(const osmium::Relation& /*relation*/) const noexcept {
+ }
+
+ /**
+ * This method is called for all nodes during the second pass
+ * before the relation member handling.
+ *
+ * Overwrite this method in a derived class if you are interested
+ * in this.
+ */
+ void before_node(const osmium::Node& /*node*/) const noexcept {
+ }
+
+ /**
+ * This method is called for all nodes that are not a member of
+ * any relation.
+ *
+ * Overwrite this method in a derived class if you are interested
+ * in this.
+ */
+ void node_not_in_any_relation(const osmium::Node& /*node*/) const noexcept {
+ }
+
+ /**
+ * This method is called for all nodes during the second pass
+ * after the relation member handling.
+ *
+ * Overwrite this method in a derived class if you are interested
+ * in this.
+ */
+ void after_node(const osmium::Node& /*node*/) const noexcept {
+ }
+
+ /**
+ * This method is called for all ways during the second pass
+ * before the relation member handling.
+ *
+ * Overwrite this method in a derived class if you are interested
+ * in this.
+ */
+ void before_way(const osmium::Way& /*way*/) const noexcept {
+ }
+
+ /**
+ * This method is called for all ways that are not a member of
+ * any relation.
+ *
+ * Overwrite this method in a derived class if you are interested
+ * in this.
+ */
+ void way_not_in_any_relation(const osmium::Way& /*way*/) const noexcept {
+ }
+
+ /**
+ * This method is called for all ways during the second pass
+ * after the relation member handling.
+ *
+ * Overwrite this method in a derived class if you are interested
+ * in this.
+ */
+ void after_way(const osmium::Way& /*way*/) const noexcept {
+ }
+
+ /**
+ * This method is called for all relations during the second pass
+ * before the relation member handling.
+ *
+ * Overwrite this method in a derived class if you are interested
+ * in this.
+ */
+ void before_relation(const osmium::Relation& /*relation*/) const noexcept {
+ }
+
+ /**
+ * This method is called for all relations that are not a member of
+ * any relation.
+ *
+ * Overwrite this method in a derived class if you are interested
+ * in this.
+ */
+ void relation_not_in_any_relation(const osmium::Relation& /*relation*/) const noexcept {
+ }
+
+ /**
+ * This method is called for all relations during the second pass
+ * after the relation member handling.
+ *
+ * Overwrite this method in a derived class if you are interested
+ * in this.
+ */
+ void after_relation(const osmium::Relation& /*relation*/) const noexcept {
+ }
+
+ TManager& derived() noexcept {
+ return *static_cast<TManager*>(this);
+ }
+
+ void handle_complete_relation(RelationHandle& rel_handle) {
+ derived().complete_relation(*rel_handle);
+ possibly_flush();
+
+ for (const auto& member : rel_handle->members()) {
+ if (member.ref() != 0) {
+ member_database(member.type()).remove(member.ref(), rel_handle->id());
+ }
+ }
+
+ rel_handle.remove();
+ }
+
+ public:
+
+ RelationsManager() :
+ RelationsManagerBase(),
+ m_check_order_handler(),
+ m_handler_pass2(*this) {
+ }
+
+ /**
+ * Return reference to second pass handler.
+ */
+ SecondPassHandler<RelationsManager>& handler(const std::function<void(osmium::memory::Buffer&&)>& callback = nullptr) {
+ set_callback(callback);
+ return m_handler_pass2;
+ }
+
+ /**
+ * Add the specified relation to the list of relations we want to
+ * build. This calls the new_relation() and new_member()
+ * functions to actually decide what to keep.
+ *
+ * This member function is named relation() so the manager can
+ * be used as a handler for the first pass through a data file.
+ *
+ * @param relation Relation we might want to build.
+ */
+ void relation(const osmium::Relation& relation) {
+ if (derived().new_relation(relation)) {
+ auto rel_handle = relations_database().add(relation);
+
+ std::size_t n = 0;
+ for (auto& member : rel_handle->members()) {
+ if (wanted_type(member.type()) &&
+ derived().new_member(relation, member, n)) {
+ member_database(member.type()).track(rel_handle, member.ref(), n);
+ } else {
+ member.set_ref(0); // set member id to zero to indicate we are not interested
+ }
+ ++n;
+ }
+ }
+ }
+
+ void handle_node(const osmium::Node& node) {
+ if (TNodes) {
+ m_check_order_handler.node(node);
+ derived().before_node(node);
+ const bool added = member_nodes_database().add(node, [this](RelationHandle& rel_handle) {
+ handle_complete_relation(rel_handle);
+ });
+ if (! added) {
+ derived().node_not_in_any_relation(node);
+ }
+ derived().after_node(node);
+ possibly_flush();
+ }
+ }
+
+ void handle_way(const osmium::Way& way) {
+ if (TWays) {
+ m_check_order_handler.way(way);
+ derived().before_way(way);
+ const bool added = member_ways_database().add(way, [this](RelationHandle& rel_handle) {
+ handle_complete_relation(rel_handle);
+ });
+ if (! added) {
+ derived().way_not_in_any_relation(way);
+ }
+ derived().after_way(way);
+ possibly_flush();
+ }
+ }
+
+ void handle_relation(const osmium::Relation& relation) {
+ if (TRelations) {
+ m_check_order_handler.relation(relation);
+ derived().before_relation(relation);
+ const bool added = member_relations_database().add(relation, [this](RelationHandle& rel_handle) {
+ handle_complete_relation(rel_handle);
+ });
+ if (! added) {
+ derived().relation_not_in_any_relation(relation);
+ }
+ derived().after_relation(relation);
+ possibly_flush();
+ }
+ }
+
+ /**
+ * Call this function it will call your function back for every
+ * incomplete relation, that is all relations that have missing
+ * members in the input data. Usually you call this only after
+ * your second pass through the data if you are interested in
+ * any relations that have all or some of their members missing
+ * in the input data.
+ */
+ template <typename TFunc>
+ void for_each_incomplete_relation(TFunc&& func) {
+ relations_database().for_each_relation(std::forward<TFunc>(func));
+ }
+
+ }; // class RelationsManager
+
+ } // namespace relations
+
+} // namespace osmium
+
+#endif // OSMIUM_RELATIONS_RELATIONS_MANAGER_HPP
diff --git a/include/osmium/storage/item_stash.hpp b/include/osmium/storage/item_stash.hpp
new file mode 100644
index 0000000..b49d88b
--- /dev/null
+++ b/include/osmium/storage/item_stash.hpp
@@ -0,0 +1,342 @@
+#ifndef OSMIUM_ITEM_STASH_HPP
+#define OSMIUM_ITEM_STASH_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2017 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cassert>
+#include <cstdlib>
+#include <limits>
+#include <ostream>
+#include <vector>
+
+#ifdef OSMIUM_ITEM_STORAGE_GC_DEBUG
+# include <iostream>
+# include <chrono>
+#endif
+
+#include <osmium/memory/buffer.hpp>
+#include <osmium/memory/item.hpp>
+
+namespace osmium {
+
+ /**
+ * Class for storing OSM data in memory. Any osmium::memory::Item can be
+ * added to the stash and it will be copied into its internal Buffer. To
+ * access the item again, an opaque handle is used.
+ */
+ class ItemStash {
+
+ public:
+
+ /**
+ * This is the type of the handle returned by the add_item() call.
+ * It is used to access the item again with get_item() or get<>()
+ * or erase it with remove_item().
+ *
+ * There is one special handle, the invalid handle. It can be created
+ * by calling the default constructor. You can use it for instance to
+ * mark removed objects in your data structures. Valid handles can
+ * only be constructed by the ItemStash class.
+ */
+ class handle_type {
+
+ friend class ItemStash;
+
+ std::size_t value;
+
+ explicit handle_type(std::size_t new_value) noexcept :
+ value(new_value) {
+ assert(new_value > 0);
+ }
+
+ public:
+
+ /// The defalt constructor creates an invalid handle.
+ handle_type() noexcept :
+ value(0) {
+ }
+
+ /// Is this a valid handle?
+ bool valid() const noexcept {
+ return value != 0;
+ }
+
+ /**
+ * Print the handle for debugging purposes. An invalid handle
+ * will be printed as the single letter '-'. A valid handle will
+ * be printed as a unique (for an ItemStash object) number.
+ */
+ template <typename TChar, typename TTraits>
+ friend inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const ItemStash::handle_type& handle) {
+ if (handle.valid()) {
+ out << handle.value;
+ } else {
+ out << '-';
+ }
+ return out;
+ }
+
+ }; // class handle_type
+
+ private:
+
+ static constexpr const std::size_t initial_buffer_size = 1024 * 1024;
+ static constexpr const std::size_t removed_item_offset = std::numeric_limits<std::size_t>::max();
+
+ osmium::memory::Buffer m_buffer;
+ std::vector<std::size_t> m_index;
+ std::size_t m_count_items = 0;
+ std::size_t m_count_removed = 0;
+#ifdef OSMIUM_ITEM_STORAGE_GC_DEBUG
+ int64_t m_gc_time = 0;
+#endif
+
+ class cleanup_helper {
+
+ std::vector<std::size_t>& m_index;
+ std::size_t m_pos = 0;
+
+ public:
+
+ explicit cleanup_helper(std::vector<std::size_t>& index) :
+ m_index(index) {
+ }
+
+ void moving_in_buffer(std::size_t old_offset, std::size_t new_offset) {
+ while (m_index[m_pos] != old_offset) {
+ ++m_pos;
+ assert(m_pos < m_index.size());
+ }
+ m_index[m_pos] = new_offset;
+ ++m_pos;
+ }
+
+ }; // cleanup_helper
+
+ std::size_t& get_item_offset_ref(handle_type handle) noexcept {
+ assert(handle.valid() && "handle must be valid");
+ assert(handle.value <= m_index.size());
+ auto& offset = m_index[handle.value - 1];
+ assert(offset != removed_item_offset);
+ assert(offset < m_buffer.committed());
+ return offset;
+ }
+
+ std::size_t get_item_offset(handle_type handle) const noexcept {
+ assert(handle.valid() && "handle must be valid");
+ assert(handle.value <= m_index.size());
+ const auto& offset = m_index[handle.value - 1];
+ assert(offset != removed_item_offset);
+ assert(offset < m_buffer.committed());
+ return offset;
+ }
+
+ // This function decides whether it makes sense to garbage collect the
+ // database. The values here are the result of some experimentation
+ // with real data. We need to balance the memory use with the time
+ // spent on garbage collecting. We don't need to garbage collect if
+ // there is enough space in the buffer anyway (*4). On the other hand,
+ // if there aren't enough removed objects we would just call the
+ // garbage collection again and again, then it is better to let the
+ // buffer grow (*3). The checks (*1) and (*2) make sure there is
+ // minimum and maximum for the number of removed objects.
+ bool should_gc() const noexcept {
+ if (m_count_removed < 10 * 1000) { // *1
+ return false;
+ }
+ if (m_count_removed > 5 * 1000 * 1000) { // *2
+ return true;
+ }
+ if (m_count_removed * 5 < m_count_items) { // *3
+ return false;
+ }
+ return m_buffer.capacity() - m_buffer.committed() < 10 * 1024; // *4
+ }
+
+ public:
+
+ ItemStash() :
+ m_buffer(initial_buffer_size, osmium::memory::Buffer::auto_grow::yes) {
+ }
+
+ /**
+ * Return an estimate of the number of bytes currently used by this
+ * ItemStash instance.
+ *
+ * Complexity: Constant.
+ */
+ std::size_t used_memory() const noexcept {
+ return sizeof(ItemStash) +
+ m_buffer.capacity() +
+ m_index.capacity() * sizeof(std::size_t);
+ }
+
+ /**
+ * The number of items currently in the stash. This is the number
+ * added minus the number removed.
+ *
+ * Complexity: Constant.
+ */
+ std::size_t size() const noexcept {
+ return m_count_items;
+ }
+
+ /**
+ * The number of removed items currently still taking up memory in
+ * the stash. You can call garbage_collect() to remove them.
+ *
+ * Complexity: Constant.
+ */
+ std::size_t count_removed() const noexcept {
+ return m_count_removed;
+ }
+
+ /**
+ * Clear all items from the stash. This will not necessarily release
+ * any memory. All handles are invalidated.
+ */
+ void clear() {
+ m_buffer.clear();
+ m_index.clear();
+ m_count_items = 0;
+ m_count_removed = 0;
+ }
+
+ /**
+ * Add an item to the stash. This will invalidate any pointers and
+ * references into the stash, but handles are still valid.
+ *
+ * Complexity: Amortized constant.
+ */
+ handle_type add_item(const osmium::memory::Item& item) {
+ if (should_gc()) {
+ garbage_collect();
+ }
+ ++m_count_items;
+ const auto offset = m_buffer.committed();
+ m_buffer.add_item(item);
+ m_buffer.commit();
+ m_index.push_back(offset);
+ return handle_type{m_index.size()};
+ }
+
+ /**
+ * Get a reference to an item in the stash. Note that this reference
+ * will be invalidated by any add_item() or clear() calls.
+ *
+ * Complexity: Constant.
+ *
+ * @param handle A handle returned by add_item().
+ *
+ * @pre Handle must be a valid handle and referring to a non-removed
+ * item.
+ */
+ osmium::memory::Item& get_item(handle_type handle) const {
+ return m_buffer.get<osmium::memory::Item>(get_item_offset(handle));
+ }
+
+ /**
+ * Get a reference to an item in the stash. Note that this reference
+ * will be invalidated by any add_item() or clear() calls.
+ *
+ * Complexity: Constant.
+ *
+ * @param handle A handle returned by add_item().
+ * @tparam T Type you want to the data to be interpreted as. You must
+ * be sure that the item has the specified type, this will
+ * not be checked!
+ * @returns Reference of given type pointing to the data in the
+ * stash.
+ * @pre Handle must be a valid handle and referring to a non-removed
+ * item.
+ */
+ template <typename T>
+ T& get(handle_type handle) const {
+ return static_cast<T&>(get_item(handle));
+ }
+
+ /**
+ * Garbage collect the memory used by the ItemStash. This will free up
+ * memory for adding new items. No memory is actually returned to the
+ * OS. Usually you do not need to call this, because add_item() will
+ * call it for you as necessary.
+ *
+ * Complexity: Linear in size() + count_removed().
+ */
+ void garbage_collect() {
+#ifdef OSMIUM_ITEM_STORAGE_GC_DEBUG
+ std::cerr << "GC items=" << m_count_items << " removed=" << m_count_removed << " buffer.committed=" << m_buffer.committed() << " buffer.capacity=" << m_buffer.capacity() << "\n";
+ using clock = std::chrono::high_resolution_clock;
+ std::chrono::time_point<clock> start = clock::now();
+#endif
+
+ m_count_removed = 0;
+ cleanup_helper helper{m_index};
+ m_buffer.purge_removed(&helper);
+
+#ifdef OSMIUM_ITEM_STORAGE_GC_DEBUG
+ std::chrono::time_point<clock> stop = clock::now();
+ const int64_t time = std::chrono::duration_cast<std::chrono::microseconds>(stop - start).count();
+ m_gc_time += time;
+ std::cerr << " time=" << time
+ << "us total=" << m_gc_time << "us\n";
+#endif
+ }
+
+ /**
+ * Remove an item from the stash. The item will be marked as removed
+ * and the handle will be invalidated. No memory will actually be
+ * freed.
+ *
+ * Complexity: Constant.
+ *
+ * @param handle A handle returned by add_item().
+ *
+ * @pre Handle must be a valid handle and referring to a non-removed
+ * item.
+ */
+ void remove_item(handle_type handle) {
+ auto& offset = get_item_offset_ref(handle);
+ auto& item = m_buffer.get<osmium::memory::Item>(offset);
+ assert(!item.removed() && "can not call remove_item() on already removed item");
+ item.set_removed(true);
+ offset = removed_item_offset;
+ --m_count_items;
+ ++m_count_removed;
+ }
+
+ }; // class ItemStash
+
+} // namespace osmium
+
+#endif // OSMIUM_ITEM_STASH_HPP
diff --git a/include/osmium/thread/function_wrapper.hpp b/include/osmium/thread/function_wrapper.hpp
index eeb9425..ed68d8f 100644
--- a/include/osmium/thread/function_wrapper.hpp
+++ b/include/osmium/thread/function_wrapper.hpp
@@ -79,6 +79,7 @@ namespace osmium {
// Constructor must not be "explicit" for wrapper
// to work seemlessly.
template <typename TFunction>
+ // cppcheck-suppress noExplicitConstructor
function_wrapper(TFunction&& f) :
impl(new impl_type<TFunction>(std::forward<TFunction>(f))) {
}
@@ -86,7 +87,7 @@ namespace osmium {
// The integer parameter is only used to signal that we want
// the special function wrapper that makes the worker thread
// shut down.
- function_wrapper(int) :
+ explicit function_wrapper(int) :
impl(new impl_base()) {
}
diff --git a/include/osmium/thread/pool.hpp b/include/osmium/thread/pool.hpp
index a89b3e9..5539e7a 100644
--- a/include/osmium/thread/pool.hpp
+++ b/include/osmium/thread/pool.hpp
@@ -76,8 +76,8 @@ namespace osmium {
return num_threads;
}
- inline size_t get_work_queue_size() noexcept {
- const size_t n = osmium::config::get_max_queue_size("WORK", 10);
+ inline std::size_t get_work_queue_size() noexcept {
+ const std::size_t n = osmium::config::get_max_queue_size("WORK", 10);
return n > 2 ? n : 2;
}
@@ -130,6 +130,11 @@ namespace osmium {
}
}
+ public:
+
+ static constexpr int default_num_threads = 0;
+ static constexpr int default_queue_size = 0;
+
/**
* Create thread pool with the given number of threads. If
* num_threads is 0, the number of threads is read from
@@ -141,9 +146,12 @@ namespace osmium {
* given number, ie it will leave a number of cores unused.
*
* In all cases the minimum number of threads in the pool is 1.
+ *
+ * If max_queue_size is 0, the queue size is read from
+ * the environment variable OSMIUM_MAX_WORK_QUEUE_SIZE.
*/
- explicit Pool(int num_threads, size_t max_queue_size) :
- m_work_queue(max_queue_size, "work"),
+ explicit Pool(int num_threads = default_num_threads, std::size_t max_queue_size = default_queue_size) :
+ m_work_queue(max_queue_size > 0 ? max_queue_size : detail::get_work_queue_size(), "work"),
m_threads(),
m_joiner(m_threads),
m_num_threads(detail::get_pool_size(num_threads, osmium::config::get_pool_threads(), std::thread::hardware_concurrency())) {
@@ -158,12 +166,8 @@ namespace osmium {
}
}
- public:
-
- static constexpr int default_num_threads = 0;
-
- static Pool& instance() {
- static Pool pool(default_num_threads, detail::get_work_queue_size());
+ static Pool& default_instance() {
+ static Pool pool{};
return pool;
}
@@ -178,7 +182,11 @@ namespace osmium {
shutdown_all_workers();
}
- size_t queue_size() const {
+ int num_threads() const noexcept {
+ return m_num_threads;
+ }
+
+ std::size_t queue_size() const {
return m_work_queue.size();
}
@@ -188,11 +196,10 @@ namespace osmium {
template <typename TFunction>
std::future<typename std::result_of<TFunction()>::type> submit(TFunction&& func) {
-
using result_type = typename std::result_of<TFunction()>::type;
- std::packaged_task<result_type()> task(std::forward<TFunction>(func));
- std::future<result_type> future_result(task.get_future());
+ std::packaged_task<result_type()> task{std::forward<TFunction>(func)};
+ std::future<result_type> future_result{task.get_future()};
m_work_queue.push(std::move(task));
return future_result;
diff --git a/include/osmium/thread/queue.hpp b/include/osmium/thread/queue.hpp
index 3896fef..39df685 100644
--- a/include/osmium/thread/queue.hpp
+++ b/include/osmium/thread/queue.hpp
@@ -39,7 +39,6 @@ DEALINGS IN THE SOFTWARE.
#include <mutex>
#include <queue>
#include <string>
-#include <thread>
#include <utility> // IWYU pragma: keep
#ifdef OSMIUM_DEBUG_QUEUE_SIZE
@@ -61,7 +60,7 @@ namespace osmium {
/// Maximum size of this queue. If the queue is full pushing to
/// the queue will block.
- const size_t m_max_size;
+ const std::size_t m_max_size;
/// Name of this queue (for debugging only).
const std::string m_name;
@@ -78,7 +77,7 @@ namespace osmium {
#ifdef OSMIUM_DEBUG_QUEUE_SIZE
/// The largest size the queue has been so far.
- size_t m_largest_size;
+ std::size_t m_largest_size;
/// The number of times push() was called on the queue.
std::atomic<int> m_push_counter;
@@ -107,7 +106,7 @@ namespace osmium {
* 0 for an unlimited size.
* @param name Optional name for this queue. (Used for debugging.)
*/
- explicit Queue(size_t max_size = 0, const std::string& name = "") :
+ explicit Queue(std::size_t max_size = 0, const std::string& name = "") :
m_max_size(max_size),
m_name(name),
m_mutex(),
@@ -216,7 +215,7 @@ namespace osmium {
return m_queue.empty();
}
- size_t size() const {
+ std::size_t size() const {
std::lock_guard<std::mutex> lock{m_mutex};
return m_queue.size();
}
diff --git a/include/osmium/util/config.hpp b/include/osmium/util/config.hpp
index 8dba911..f9cc96c 100644
--- a/include/osmium/util/config.hpp
+++ b/include/osmium/util/config.hpp
@@ -33,6 +33,8 @@ DEALINGS IN THE SOFTWARE.
*/
+#include <cassert>
+#include <cstddef>
#include <cstdlib>
#include <cstring>
#include <string>
@@ -66,7 +68,8 @@ namespace osmium {
return true;
}
- inline size_t get_max_queue_size(const char* queue_name, size_t default_value) noexcept {
+ inline std::size_t get_max_queue_size(const char* queue_name, std::size_t default_value) noexcept {
+ assert(queue_name);
std::string name{"OSMIUM_MAX_"};
name += queue_name;
name += "_QUEUE_SIZE";
diff --git a/include/osmium/util/file.hpp b/include/osmium/util/file.hpp
index 17897b4..431445b 100644
--- a/include/osmium/util/file.hpp
+++ b/include/osmium/util/file.hpp
@@ -67,7 +67,7 @@ namespace osmium {
* @returns file size
* @throws std::system_error If system call failed
*/
- inline size_t file_size(int fd) {
+ inline std::size_t file_size(int fd) {
#ifdef _MSC_VER
// Windows implementation
// https://msdn.microsoft.com/en-us/library/dfbc2kec.aspx
@@ -75,14 +75,14 @@ namespace osmium {
if (size == -1L) {
throw std::system_error{errno, std::system_category(), "Could not get file size"};
}
- return size_t(size);
+ return static_cast<std::size_t>(size);
#else
// Unix implementation
struct stat s;
if (::fstat(fd, &s) != 0) {
throw std::system_error{errno, std::system_category(), "Could not get file size"};
}
- return size_t(s.st_size);
+ return static_cast<std::size_t>(s.st_size);
#endif
}
@@ -94,7 +94,7 @@ namespace osmium {
* @returns file size
* @throws std::system_error If system call failed
*/
- inline size_t file_size(const char* name) {
+ inline std::size_t file_size(const char* name) {
#ifdef _MSC_VER
// Windows implementation
// https://msdn.microsoft.com/en-us/library/14h5k7ff.aspx
@@ -109,7 +109,7 @@ namespace osmium {
throw std::system_error{errno, std::system_category(), std::string{"Could not get file size of file '"} + name + "'"};
}
#endif
- return size_t(s.st_size);
+ return static_cast<std::size_t>(s.st_size);
}
/**
@@ -120,7 +120,7 @@ namespace osmium {
* @returns file size
* @throws std::system_error If system call failed
*/
- inline size_t file_size(const std::string& name) {
+ inline std::size_t file_size(const std::string& name) {
return file_size(name.c_str());
}
@@ -132,7 +132,7 @@ namespace osmium {
* @param new_size New size
* @throws std::system_error If ftruncate(2) call failed
*/
- inline void resize_file(int fd, size_t new_size) {
+ inline void resize_file(int fd, std::size_t new_size) {
#ifdef _WIN32
// https://msdn.microsoft.com/en-us/library/whx354w1.aspx
if (::_chsize_s(fd, static_cast_with_assert<__int64>(new_size)) != 0) {
@@ -146,7 +146,7 @@ namespace osmium {
/**
* Get the page size for this system.
*/
- inline size_t get_pagesize() {
+ inline std::size_t get_pagesize() {
#ifdef _WIN32
// Windows implementation
SYSTEM_INFO si;
@@ -154,7 +154,7 @@ namespace osmium {
return si.dwPageSize;
#else
// Unix implementation
- return size_t(::sysconf(_SC_PAGESIZE));
+ return static_cast<std::size_t>(::sysconf(_SC_PAGESIZE));
#endif
}
@@ -164,17 +164,17 @@ namespace osmium {
* @param fd Open file descriptor.
* @returns File offset or 0 if it is not available.
*/
- inline size_t file_offset(int fd) {
+ inline std::size_t file_offset(int fd) {
#ifdef _MSC_VER
// https://msdn.microsoft.com/en-us/library/1yee101t.aspx
- auto offset = _lseeki64(fd, 0, SEEK_CUR);
+ const auto offset = _lseeki64(fd, 0, SEEK_CUR);
#else
- auto offset = ::lseek(fd, 0, SEEK_CUR);
+ const auto offset = ::lseek(fd, 0, SEEK_CUR);
#endif
if (offset == -1) {
return 0;
}
- return size_t(offset);
+ return static_cast<std::size_t>(offset);
}
/**
diff --git a/include/osmium/util/iterator.hpp b/include/osmium/util/iterator.hpp
index 1cc6e0e..bd8a692 100644
--- a/include/osmium/util/iterator.hpp
+++ b/include/osmium/util/iterator.hpp
@@ -33,7 +33,6 @@ DEALINGS IN THE SOFTWARE.
*/
-#include <cstddef>
#include <type_traits>
#include <utility>
@@ -44,27 +43,19 @@ namespace osmium {
using iterator = It;
- explicit iterator_range(P&& p) :
+ explicit iterator_range(P&& p) noexcept :
P(std::forward<P>(p)) {
}
-/*
- It begin() {
- return this->first;
- }
- It end() {
- return this->second;
- }
-*/
- It begin() const {
+ It begin() const noexcept {
return this->first;
}
- It end() const {
+ It end() const noexcept {
return this->second;
}
- size_t empty() const {
+ bool empty() const noexcept {
return begin() == end();
}
@@ -74,9 +65,9 @@ namespace osmium {
* Helper function to create iterator_range from std::pair.
*/
template <typename P, typename It = typename P::first_type>
- inline iterator_range<It> make_range(P&& p) {
+ inline iterator_range<It> make_range(P&& p) noexcept {
static_assert(std::is_same<P, std::pair<It, It>>::value, "make_range needs pair of iterators as argument");
- return iterator_range<It>(std::forward<P>(p));
+ return iterator_range<It>{std::forward<P>(p)};
}
} // namespace osmium
diff --git a/include/osmium/util/memory_mapping.hpp b/include/osmium/util/memory_mapping.hpp
index 7504c3f..a26e372 100644
--- a/include/osmium/util/memory_mapping.hpp
+++ b/include/osmium/util/memory_mapping.hpp
@@ -105,7 +105,7 @@ namespace osmium {
private:
/// The size of the mapping
- size_t m_size;
+ std::size_t m_size;
/// Offset into the file
off_t m_offset;
@@ -137,9 +137,9 @@ namespace osmium {
flag_type get_flags() const noexcept;
- static size_t check_size(size_t size) {
+ static std::size_t check_size(std::size_t size) {
if (size == 0) {
- throw std::runtime_error("Zero-sized mapping is not allowed.");
+ throw std::runtime_error{"Zero-sized mapping is not allowed."};
}
return size;
}
@@ -181,14 +181,14 @@ namespace osmium {
* @param offset Offset into the file where the mapping should start
* @throws std::system_error if the mapping fails
*/
- MemoryMapping(size_t size, mapping_mode mode, int fd=-1, off_t offset=0);
+ MemoryMapping(std::size_t size, mapping_mode mode, int fd=-1, off_t offset=0);
/**
* @deprecated
* For backwards compatibility only. Use the constructor taking
* a mapping_mode as second argument instead.
*/
- OSMIUM_DEPRECATED MemoryMapping(size_t size, bool writable=true, int fd=-1, off_t offset=0) :
+ OSMIUM_DEPRECATED MemoryMapping(std::size_t size, bool writable=true, int fd=-1, off_t offset=0) :
MemoryMapping(size, writable ? mapping_mode::write_shared : mapping_mode::readonly, fd, offset) {
}
@@ -240,7 +240,7 @@ namespace osmium {
*
* @throws std::system_error if the remapping fails.
*/
- void resize(size_t new_size);
+ void resize(std::size_t new_size);
/**
* In a boolean context a MemoryMapping is true when it is a valid
@@ -255,7 +255,7 @@ namespace osmium {
* the mapping with. The actual mapping will probably be larger
* because the system will round it to the page size.
*/
- size_t size() const noexcept {
+ std::size_t size() const noexcept {
return m_size;
}
@@ -285,7 +285,7 @@ namespace osmium {
if (is_valid()) {
return reinterpret_cast<T*>(m_addr);
}
- throw std::runtime_error("invalid memory mapping");
+ throw std::runtime_error{"invalid memory mapping"};
}
}; // class MemoryMapping
@@ -304,7 +304,7 @@ namespace osmium {
public:
- explicit AnonymousMemoryMapping(size_t size) :
+ explicit AnonymousMemoryMapping(std::size_t size) :
MemoryMapping(size, mapping_mode::write_private) {
}
@@ -313,7 +313,7 @@ namespace osmium {
* On systems other than Linux anonymous mappings can not be
* resized!
*/
- void resize(size_t) = delete;
+ void resize(std::size_t) = delete;
#endif
}; // class AnonymousMemoryMapping
@@ -340,7 +340,7 @@ namespace osmium {
* @param size Number of objects of type T to be mapped
* @throws std::system_error if the mapping fails
*/
- explicit TypedMemoryMapping(size_t size) :
+ explicit TypedMemoryMapping(std::size_t size) :
m_mapping(sizeof(T) * size, MemoryMapping::mapping_mode::write_private) {
}
@@ -354,7 +354,7 @@ namespace osmium {
* @param offset Offset into the file where the mapping should start
* @throws std::system_error if the mapping fails
*/
- TypedMemoryMapping(size_t size, MemoryMapping::mapping_mode mode, int fd, off_t offset = 0) :
+ TypedMemoryMapping(std::size_t size, MemoryMapping::mapping_mode mode, int fd, off_t offset = 0) :
m_mapping(sizeof(T) * size, mode, fd, sizeof(T) * offset) {
}
@@ -363,8 +363,11 @@ namespace osmium {
* For backwards compatibility only. Use the constructor taking
* a mapping_mode as second argument instead.
*/
- OSMIUM_DEPRECATED TypedMemoryMapping(size_t size, bool writable, int fd, off_t offset = 0) :
- m_mapping(sizeof(T) * size, writable ? MemoryMapping::mapping_mode::write_shared : MemoryMapping::mapping_mode::readonly, fd, sizeof(T) * offset) {
+ OSMIUM_DEPRECATED TypedMemoryMapping(std::size_t size, bool writable, int fd, off_t offset = 0) :
+ m_mapping(sizeof(T) * size,
+ writable ? MemoryMapping::mapping_mode::write_shared : MemoryMapping::mapping_mode::readonly,
+ fd,
+ sizeof(T) * offset) {
}
/// You can not copy construct a TypedMemoryMapping.
@@ -410,7 +413,7 @@ namespace osmium {
* @param new_size Number of objects of type T to resize to
* @throws std::system_error if the remapping fails
*/
- void resize(size_t new_size) {
+ void resize(std::size_t new_size) {
m_mapping.resize(sizeof(T) * new_size);
}
@@ -427,7 +430,7 @@ namespace osmium {
* you created the mapping with. The actual mapping will probably
* be larger because the system will round it to the page size.
*/
- size_t size() const noexcept {
+ std::size_t size() const noexcept {
assert(m_mapping.size() % sizeof(T) == 0);
return m_mapping.size() / sizeof(T);
}
@@ -489,7 +492,7 @@ namespace osmium {
public:
- explicit AnonymousTypedMemoryMapping(size_t size) :
+ explicit AnonymousTypedMemoryMapping(std::size_t size) :
TypedMemoryMapping<T>(size) {
}
@@ -498,7 +501,7 @@ namespace osmium {
* On systems other than Linux anonymous mappings can not be
* resized!
*/
- void resize(size_t) = delete;
+ void resize(std::size_t) = delete;
#endif
}; // class AnonymousTypedMemoryMapping
@@ -547,7 +550,7 @@ inline int osmium::util::MemoryMapping::get_flags() const noexcept {
return MAP_PRIVATE;
}
-inline osmium::util::MemoryMapping::MemoryMapping(size_t size, mapping_mode mode, int fd, off_t offset) :
+inline osmium::util::MemoryMapping::MemoryMapping(std::size_t size, mapping_mode mode, int fd, off_t offset) :
m_size(check_size(size)),
m_offset(offset),
m_fd(resize_fd(fd)),
@@ -555,7 +558,7 @@ inline osmium::util::MemoryMapping::MemoryMapping(size_t size, mapping_mode mode
m_addr(::mmap(nullptr, m_size, get_protection(), get_flags(), m_fd, m_offset)) {
assert(!(fd == -1 && mode == mapping_mode::readonly));
if (!is_valid()) {
- throw std::system_error(errno, std::system_category(), "mmap failed");
+ throw std::system_error{errno, std::system_category(), "mmap failed"};
}
}
@@ -582,19 +585,19 @@ inline osmium::util::MemoryMapping& osmium::util::MemoryMapping::operator=(osmiu
inline void osmium::util::MemoryMapping::unmap() {
if (is_valid()) {
if (::munmap(m_addr, m_size) != 0) {
- throw std::system_error(errno, std::system_category(), "munmap failed");
+ throw std::system_error{errno, std::system_category(), "munmap failed"};
}
make_invalid();
}
}
-inline void osmium::util::MemoryMapping::resize(size_t new_size) {
+inline void osmium::util::MemoryMapping::resize(std::size_t new_size) {
assert(new_size > 0 && "can not resize to zero size");
if (m_fd == -1) { // anonymous mapping
#ifdef __linux__
m_addr = ::mremap(m_addr, m_size, new_size, MREMAP_MAYMOVE);
if (!is_valid()) {
- throw std::system_error(errno, std::system_category(), "mremap failed");
+ throw std::system_error{errno, std::system_category(), "mremap failed"};
}
m_size = new_size;
#else
@@ -606,7 +609,7 @@ inline void osmium::util::MemoryMapping::resize(size_t new_size) {
resize_fd(m_fd);
m_addr = ::mmap(nullptr, new_size, get_protection(), get_flags(), m_fd, m_offset);
if (!is_valid()) {
- throw std::system_error(errno, std::system_category(), "mmap (remap) failed");
+ throw std::system_error{errno, std::system_category(), "mmap (remap) failed"};
}
}
}
@@ -673,11 +676,20 @@ inline HANDLE osmium::util::MemoryMapping::create_file_mapping() const noexcept
if (m_fd != -1) {
_setmode(m_fd, _O_BINARY);
}
- return CreateFileMapping(get_handle(), nullptr, get_protection(), osmium::util::dword_hi(static_cast<uint64_t>(m_size) + m_offset), osmium::util::dword_lo(static_cast<uint64_t>(m_size) + m_offset), nullptr);
+ return CreateFileMapping(get_handle(),
+ nullptr,
+ get_protection(),
+ osmium::util::dword_hi(static_cast<uint64_t>(m_size) + m_offset),
+ osmium::util::dword_lo(static_cast<uint64_t>(m_size) + m_offset),
+ nullptr);
}
inline void* osmium::util::MemoryMapping::map_view_of_file() const noexcept {
- return MapViewOfFile(m_handle, get_flags(), osmium::util::dword_hi(m_offset), osmium::util::dword_lo(m_offset), m_size);
+ return MapViewOfFile(m_handle,
+ get_flags(),
+ osmium::util::dword_hi(m_offset),
+ osmium::util::dword_lo(m_offset),
+ m_size);
}
inline bool osmium::util::MemoryMapping::is_valid() const noexcept {
@@ -688,7 +700,14 @@ inline void osmium::util::MemoryMapping::make_invalid() noexcept {
m_addr = nullptr;
}
-inline osmium::util::MemoryMapping::MemoryMapping(size_t size, MemoryMapping::mapping_mode mode, int fd, off_t offset) :
+// GetLastError() returns a DWORD (A 32-bit unsigned integer), but the error
+// code for std::system_error is an int. So we convert this here and hope
+// it all works.
+inline int last_error() noexcept {
+ return static_cast<int>(GetLastError());
+}
+
+inline osmium::util::MemoryMapping::MemoryMapping(std::size_t size, MemoryMapping::mapping_mode mode, int fd, off_t offset) :
m_size(check_size(size)),
m_offset(offset),
m_fd(resize_fd(fd)),
@@ -697,12 +716,12 @@ inline osmium::util::MemoryMapping::MemoryMapping(size_t size, MemoryMapping::ma
m_addr(nullptr) {
if (!m_handle) {
- throw std::system_error(GetLastError(), std::system_category(), "CreateFileMapping failed");
+ throw std::system_error{last_error(), std::system_category(), "CreateFileMapping failed"};
}
m_addr = map_view_of_file();
if (!is_valid()) {
- throw std::system_error(GetLastError(), std::system_category(), "MapViewOfFile failed");
+ throw std::system_error{last_error(), std::system_category(), "MapViewOfFile failed"};
}
}
@@ -732,21 +751,21 @@ inline osmium::util::MemoryMapping& osmium::util::MemoryMapping::operator=(osmiu
inline void osmium::util::MemoryMapping::unmap() {
if (is_valid()) {
- if (! UnmapViewOfFile(m_addr)) {
- throw std::system_error(GetLastError(), std::system_category(), "UnmapViewOfFile failed");
+ if (!UnmapViewOfFile(m_addr)) {
+ throw std::system_error{last_error(), std::system_category(), "UnmapViewOfFile failed"};
}
make_invalid();
}
if (m_handle) {
- if (! CloseHandle(m_handle)) {
- throw std::system_error(GetLastError(), std::system_category(), "CloseHandle failed");
+ if (!CloseHandle(m_handle)) {
+ throw std::system_error{last_error(), std::system_category(), "CloseHandle failed"};
}
m_handle = nullptr;
}
}
-inline void osmium::util::MemoryMapping::resize(size_t new_size) {
+inline void osmium::util::MemoryMapping::resize(std::size_t new_size) {
unmap();
m_size = new_size;
@@ -754,12 +773,12 @@ inline void osmium::util::MemoryMapping::resize(size_t new_size) {
m_handle = create_file_mapping();
if (!m_handle) {
- throw std::system_error(GetLastError(), std::system_category(), "CreateFileMapping failed");
+ throw std::system_error{last_error(), std::system_category(), "CreateFileMapping failed"};
}
m_addr = map_view_of_file();
if (!is_valid()) {
- throw std::system_error(GetLastError(), std::system_category(), "MapViewOfFile failed");
+ throw std::system_error{last_error(), std::system_category(), "MapViewOfFile failed"};
}
}
diff --git a/include/osmium/util/options.hpp b/include/osmium/util/options.hpp
index 7b23652..c39bdbf 100644
--- a/include/osmium/util/options.hpp
+++ b/include/osmium/util/options.hpp
@@ -108,11 +108,11 @@ namespace osmium {
* be set to "true".
*/
void set(const std::string& data) {
- const size_t pos = data.find_first_of('=');
+ const std::size_t pos = data.find_first_of('=');
if (pos == std::string::npos) {
m_options[data] = "true";
} else {
- std::string value = data.substr(pos+1);
+ const std::string value{data.substr(pos+1)};
set(data.substr(0, pos), value);
}
}
@@ -121,7 +121,7 @@ namespace osmium {
* Get value of "key" option. If not set, the default_value (or
* empty string) is returned.
*/
- std::string get(const std::string& key, const std::string& default_value="") const noexcept {
+ std::string get(const std::string& key, const std::string& default_value = "") const noexcept {
const auto it = m_options.find(key);
if (it == m_options.end()) {
return default_value;
@@ -134,7 +134,7 @@ namespace osmium {
* Will return false if the value is unset.
*/
bool is_true(const std::string& key) const noexcept {
- const std::string value = get(key);
+ const std::string value{get(key)};
return (value == "true" || value == "yes");
}
@@ -143,14 +143,14 @@ namespace osmium {
* Will return true if the value is unset.
*/
bool is_not_false(const std::string& key) const noexcept {
- const std::string value = get(key);
+ const std::string value{get(key)};
return !(value == "false" || value == "no");
}
/**
* The number of options set.
*/
- size_t size() const noexcept {
+ std::size_t size() const noexcept {
return m_options.size();
}
diff --git a/include/osmium/util/progress_bar.hpp b/include/osmium/util/progress_bar.hpp
index 6e6d012..fed37eb 100644
--- a/include/osmium/util/progress_bar.hpp
+++ b/include/osmium/util/progress_bar.hpp
@@ -33,6 +33,7 @@ DEALINGS IN THE SOFTWARE.
*/
+#include <cstddef>
#include <iostream>
namespace osmium {
@@ -51,23 +52,23 @@ namespace osmium {
return " ";
}
- static constexpr const size_t length = 70;
+ static constexpr const std::size_t length = 70;
// The max size is the file size if there is a single file and the
// sum of all file sizes if there are multiple files. It corresponds
// to 100%.
- size_t m_max_size;
+ std::size_t m_max_size;
// The sum of the file sizes already done.
- size_t m_done_size = 0;
+ std::size_t m_done_size = 0;
// The currently read size in the current file.
- size_t m_current_size = 0;
+ std::size_t m_current_size = 0;
// The percentage calculated when it was last displayed. Used to decide
// whether we need to update the display. Start setting is one that
// will always be different from any legal setting.
- size_t m_prev_percent = 100 + 1;
+ std::size_t m_prev_percent = 100 + 1;
// Is the progress bar enabled at all?
bool m_enable;
@@ -77,13 +78,13 @@ namespace osmium {
bool m_do_cleanup = true;
void display() {
- const size_t percent = 100 * (m_done_size + m_current_size) / m_max_size;
+ const std::size_t percent = 100 * (m_done_size + m_current_size) / m_max_size;
if (m_prev_percent == percent) {
return;
}
m_prev_percent = percent;
- const size_t num = size_t(percent * (length / 100.0));
+ const auto num = static_cast<std::size_t>(percent * (length / 100.0));
std::cerr << '[';
if (num >= length) {
std::cerr << bar();
@@ -109,7 +110,7 @@ namespace osmium {
* @param enable Set to false to disable (for instance if stderr is
* not a TTY).
*/
- ProgressBar(size_t max_size, bool enable) noexcept :
+ ProgressBar(std::size_t max_size, bool enable) noexcept :
m_max_size(max_size),
m_enable(max_size > 0 && enable) {
}
@@ -133,7 +134,7 @@ namespace osmium {
* @param current_size Current size. Used together with the max_size
* from constructor to calculate the percentage.
*/
- void update(size_t current_size) {
+ void update(std::size_t current_size) {
if (!m_enable) {
return;
}
@@ -149,7 +150,7 @@ namespace osmium {
*
* @param file_size The size of the file just finished.
*/
- void file_done(size_t file_size) {
+ void file_done(std::size_t file_size) {
if (m_enable) {
m_done_size += file_size;
m_current_size = 0;
diff --git a/include/osmium/util/string.hpp b/include/osmium/util/string.hpp
index 595307e..6eef05f 100644
--- a/include/osmium/util/string.hpp
+++ b/include/osmium/util/string.hpp
@@ -44,15 +44,15 @@ namespace osmium {
*
* @param str The string to be split.
* @param sep The separator character.
- * @param compact Set this to true to remove empty strings from result
+ * @param compact Set this to true to remove empty strings from result.
* @returns Vector with the parts of the string split up.
*/
inline std::vector<std::string> split_string(const std::string& str, const char sep, bool compact = false) {
std::vector<std::string> tokens;
if (!str.empty()) {
- size_t pos = 0;
- size_t nextpos = str.find_first_of(sep);
+ std::size_t pos = 0;
+ std::size_t nextpos = str.find_first_of(sep);
while (nextpos != std::string::npos) {
if (!compact || (nextpos - pos != 0)) {
tokens.push_back(str.substr(pos, nextpos-pos));
@@ -69,19 +69,19 @@ namespace osmium {
}
/**
- * Split string on the separator character(s).
+ * Split string on any of the separator characters.
*
* @param str The string to be split.
* @param sep The separator character(s).
- * @param compact Set this to true to remove empty strings from result
+ * @param compact Set this to true to remove empty strings from result.
* @returns Vector with the parts of the string split up.
*/
inline std::vector<std::string> split_string(const std::string& str, const char* sep, bool compact = false) {
std::vector<std::string> tokens;
if (!str.empty()) {
- size_t pos = 0;
- size_t nextpos = str.find_first_of(sep);
+ std::size_t pos = 0;
+ std::size_t nextpos = str.find_first_of(sep);
while (nextpos != std::string::npos) {
if (!compact || (nextpos - pos != 0)) {
tokens.push_back(str.substr(pos, nextpos-pos));
diff --git a/include/osmium/util/verbose_output.hpp b/include/osmium/util/verbose_output.hpp
index a47d29a..e6f6654 100644
--- a/include/osmium/util/verbose_output.hpp
+++ b/include/osmium/util/verbose_output.hpp
@@ -88,7 +88,7 @@ namespace osmium {
public:
explicit VerboseOutput(bool verbose = false) noexcept :
- m_start(time(NULL)),
+ m_start(time(nullptr)),
m_verbose(verbose),
m_newline(true) {
}
@@ -101,7 +101,7 @@ namespace osmium {
VerboseOutput& operator=(VerboseOutput&&) = default;
time_t runtime() const noexcept {
- return time(NULL) - m_start;
+ return time(nullptr) - m_start;
}
/// Get "verbose" setting.
diff --git a/include/osmium/version.hpp b/include/osmium/version.hpp
index 5f3b10e..eb1aa36 100644
--- a/include/osmium/version.hpp
+++ b/include/osmium/version.hpp
@@ -34,9 +34,9 @@ DEALINGS IN THE SOFTWARE.
*/
#define LIBOSMIUM_VERSION_MAJOR 2
-#define LIBOSMIUM_VERSION_MINOR 12
-#define LIBOSMIUM_VERSION_PATCH 2
+#define LIBOSMIUM_VERSION_MINOR 13
+#define LIBOSMIUM_VERSION_PATCH 0
-#define LIBOSMIUM_VERSION_STRING "2.12.2"
+#define LIBOSMIUM_VERSION_STRING "2.13.0"
#endif // OSMIUM_VERSION_HPP
diff --git a/include/protozero/pbf_builder.hpp b/include/protozero/pbf_builder.hpp
index c40727c..8197395 100644
--- a/include/protozero/pbf_builder.hpp
+++ b/include/protozero/pbf_builder.hpp
@@ -46,7 +46,7 @@ public:
using enum_type = T;
- pbf_builder(std::string& data) noexcept :
+ explicit pbf_builder(std::string& data) noexcept :
pbf_writer(data) {
}
@@ -83,10 +83,18 @@ public:
pbf_writer::add_bytes(pbf_tag_type(tag), value, size);
}
+ void add_bytes(T tag, const data_view& value) {
+ pbf_writer::add_bytes(pbf_tag_type(tag), value);
+ }
+
void add_bytes(T tag, const std::string& value) {
pbf_writer::add_bytes(pbf_tag_type(tag), value);
}
+ void add_bytes(T tag, const char* value) {
+ pbf_writer::add_bytes(pbf_tag_type(tag), value);
+ }
+
template <typename... Ts>
void add_bytes_vectored(T tag, Ts&&... values) {
pbf_writer::add_bytes_vectored(pbf_tag_type(tag), std::forward<Ts>(values)...);
@@ -96,6 +104,10 @@ public:
pbf_writer::add_string(pbf_tag_type(tag), value, size);
}
+ void add_string(T tag, const data_view& value) {
+ pbf_writer::add_string(pbf_tag_type(tag), value);
+ }
+
void add_string(T tag, const std::string& value) {
pbf_writer::add_string(pbf_tag_type(tag), value);
}
@@ -108,6 +120,10 @@ public:
pbf_writer::add_message(pbf_tag_type(tag), value, size);
}
+ void add_message(T tag, const data_view& value) {
+ pbf_writer::add_message(pbf_tag_type(tag), value);
+ }
+
void add_message(T tag, const std::string& value) {
pbf_writer::add_message(pbf_tag_type(tag), value);
}
diff --git a/include/protozero/pbf_message.hpp b/include/protozero/pbf_message.hpp
index f66604a..c599cf1 100644
--- a/include/protozero/pbf_message.hpp
+++ b/include/protozero/pbf_message.hpp
@@ -83,6 +83,10 @@ public:
return pbf_reader::next(pbf_tag_type(next_tag));
}
+ bool next(T next_tag, pbf_wire_type type) {
+ return pbf_reader::next(pbf_tag_type(next_tag), type);
+ }
+
T tag() const noexcept {
return T(pbf_reader::tag());
}
diff --git a/include/protozero/pbf_reader.hpp b/include/protozero/pbf_reader.hpp
index 98920fa..905ca0a 100644
--- a/include/protozero/pbf_reader.hpp
+++ b/include/protozero/pbf_reader.hpp
@@ -179,7 +179,7 @@ public:
*
* @post There is no current field.
*/
- pbf_reader(const std::pair<const char*, std::size_t>& data) noexcept
+ explicit pbf_reader(const std::pair<const char*, std::size_t>& data) noexcept
: m_data(data.first),
m_end(data.first + data.second),
m_wire_type(pbf_wire_type::unknown),
@@ -196,7 +196,7 @@ public:
*
* @post There is no current field.
*/
- pbf_reader(const std::string& data) noexcept
+ explicit pbf_reader(const std::string& data) noexcept
: m_data(data.data()),
m_end(data.data() + data.size()),
m_wire_type(pbf_wire_type::unknown),
@@ -367,9 +367,9 @@ public:
* @pre There must be no current field.
* @post If it returns `true` there is a current field now with the given tag.
*/
- bool next(pbf_tag_type next_tag, pbf_wire_type wire_type) {
+ bool next(pbf_tag_type next_tag, pbf_wire_type type) {
while (next()) {
- if (m_tag == next_tag && m_wire_type == wire_type) {
+ if (m_tag == next_tag && m_wire_type == type) {
return true;
} else {
skip();
diff --git a/include/protozero/pbf_writer.hpp b/include/protozero/pbf_writer.hpp
index 39dd795..af626bd 100644
--- a/include/protozero/pbf_writer.hpp
+++ b/include/protozero/pbf_writer.hpp
@@ -502,6 +502,17 @@ public:
}
/**
+ * Add "bytes" field to data. Bytes from the value are written until
+ * a null byte is encountered. The null byte is not added.
+ *
+ * @param tag Tag (field number) of the field
+ * @param value Pointer to zero-delimited value to be written
+ */
+ void add_bytes(pbf_tag_type tag, const char* value) {
+ add_bytes(tag, value, std::strlen(value));
+ }
+
+ /**
* Add "bytes" field to data using vectored input. All the data in the
* 2nd and further arguments is "concatenated" with only a single copy
* into the final buffer.
diff --git a/include/protozero/types.hpp b/include/protozero/types.hpp
index 5e14972..3dbdaf1 100644
--- a/include/protozero/types.hpp
+++ b/include/protozero/types.hpp
@@ -16,6 +16,7 @@ documentation.
* @brief Contains the declaration of low-level types used in the pbf format.
*/
+#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <cstring>
@@ -138,6 +139,11 @@ public:
return m_size;
}
+ /// Returns true if size is 0.
+ constexpr bool empty() const noexcept {
+ return m_size == 0;
+ }
+
/**
* Convert data view to string.
*
@@ -178,7 +184,7 @@ inline void swap(data_view& lhs, data_view& rhs) noexcept {
* @param rhs Second object.
*/
inline bool operator==(const data_view& lhs, const data_view& rhs) noexcept {
- return lhs.size() == rhs.size() && !std::strcmp(lhs.data(), rhs.data());
+ return lhs.size() == rhs.size() && std::equal(lhs.data(), lhs.data() + lhs.size(), rhs.data());
}
/**
diff --git a/include/protozero/version.hpp b/include/protozero/version.hpp
index 9103bdc..6d82823 100644
--- a/include/protozero/version.hpp
+++ b/include/protozero/version.hpp
@@ -23,12 +23,12 @@ documentation.
#define PROTOZERO_VERSION_MINOR 5
/// The patch number
-#define PROTOZERO_VERSION_PATCH 1
+#define PROTOZERO_VERSION_PATCH 2
/// The complete version number
#define PROTOZERO_VERSION_CODE (PROTOZERO_VERSION_MAJOR * 10000 + PROTOZERO_VERSION_MINOR * 100 + PROTOZERO_VERSION_PATCH)
/// Version number as string
-#define PROTOZERO_VERSION_STRING "1.5.1"
+#define PROTOZERO_VERSION_STRING "1.5.2"
#endif // PROTOZERO_VERSION_HPP
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 767972e..b23c39a 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -142,6 +142,8 @@ add_unit_test(osm test_way)
add_unit_test(memory test_buffer_basics)
add_unit_test(memory test_buffer_node)
add_unit_test(memory test_buffer_purge)
+add_unit_test(memory test_callback_buffer)
+add_unit_test(memory test_item)
add_unit_test(memory test_type_is_compatible)
add_unit_test(builder test_attr)
@@ -161,6 +163,9 @@ add_unit_test(geom test_tile)
add_unit_test(geom test_wkb)
add_unit_test(geom test_wkt)
+add_unit_test(handler test_check_order_handler)
+add_unit_test(handler test_dynamic_handler)
+
add_unit_test(index test_id_set)
add_unit_test(index test_id_to_location ENABLE_IF ${SPARSEHASH_FOUND})
add_unit_test(index test_file_based_index)
@@ -182,6 +187,13 @@ add_unit_test(io test_writer ENABLE_IF ${Threads_FOUND} LIBS ${OSMIUM_XML_LIBRAR
add_unit_test(io test_writer_with_mock_compression ENABLE_IF ${Threads_FOUND} LIBS ${OSMIUM_XML_LIBRARIES})
add_unit_test(io test_writer_with_mock_encoder ENABLE_IF ${Threads_FOUND} LIBS ${OSMIUM_XML_LIBRARIES})
+add_unit_test(relations test_members_database)
+add_unit_test(relations test_read_relations ENABLE_IF ${Threads_FOUND} LIBS ${OSMIUM_XML_LIBRARIES})
+add_unit_test(relations test_relations_database)
+add_unit_test(relations test_relations_manager ENABLE_IF ${Threads_FOUND} LIBS ${OSMIUM_XML_LIBRARIES})
+
+add_unit_test(storage test_item_stash)
+
add_unit_test(tags test_filter)
add_unit_test(tags test_operators)
add_unit_test(tags test_tag_list)
@@ -189,8 +201,10 @@ add_unit_test(tags test_tag_matcher)
add_unit_test(tags test_tags_filter)
add_unit_test(thread test_pool ENABLE_IF ${Threads_FOUND} LIBS ${CMAKE_THREAD_LIBS_INIT})
+add_unit_test(thread test_util ENABLE_IF ${Threads_FOUND} LIBS ${CMAKE_THREAD_LIBS_INIT})
add_unit_test(util test_cast_with_assert)
+add_unit_test(util test_config)
add_unit_test(util test_delta)
add_unit_test(util test_double)
add_unit_test(util test_file)
@@ -200,6 +214,8 @@ add_unit_test(util test_minmax)
add_unit_test(util test_options)
add_unit_test(util test_string)
add_unit_test(util test_string_matcher)
+add_unit_test(util test_timer_disabled)
+add_unit_test(util test_timer_enabled)
#-----------------------------------------------------------------------------
diff --git a/test/data-tests/testdata-multipolygon.cpp b/test/data-tests/testdata-multipolygon.cpp
index 6d0328c..06385fb 100644
--- a/test/data-tests/testdata-multipolygon.cpp
+++ b/test/data-tests/testdata-multipolygon.cpp
@@ -9,7 +9,7 @@
#include <osmium/index/map/sparse_mem_array.hpp>
-#include <osmium/area/assembler.hpp>
+#include <osmium/area/assembler_legacy.hpp>
#include <osmium/area/multipolygon_collector.hpp>
#include <osmium/area/problem_reporter_ogr.hpp>
#include <osmium/geom/ogr.hpp>
@@ -156,12 +156,12 @@ int main(int argc, char* argv[]) {
gdalcpp::Dataset dataset{output_format, output_filename, gdalcpp::SRS{}, {"SPATIALITE=TRUE"}};
osmium::area::ProblemReporterOGR problem_reporter{dataset};
- osmium::area::Assembler::config_type assembler_config;
+ osmium::area::AssemblerLegacy::config_type assembler_config;
assembler_config.problem_reporter = &problem_reporter;
assembler_config.check_roles = true;
assembler_config.create_empty_areas = true;
assembler_config.debug_level = 2;
- osmium::area::MultipolygonCollector<osmium::area::Assembler> collector{assembler_config};
+ osmium::area::MultipolygonCollector<osmium::area::AssemblerLegacy> collector{assembler_config};
std::cerr << "Pass 1...\n";
osmium::io::Reader reader1{input_filename};
diff --git a/test/data-tests/testdata-xml.cpp b/test/data-tests/testdata-xml.cpp
index 5f11429..0808d3f 100644
--- a/test/data-tests/testdata-xml.cpp
+++ b/test/data-tests/testdata-xml.cpp
@@ -73,8 +73,9 @@ static std::string read_gz_file(const char* test_id, const char* suffix) {
return input;
}
-
+// cppcheck-suppress passedByValue
static header_buffer_type parse_xml(std::string input) {
+ osmium::thread::Pool pool;
osmium::io::detail::future_string_queue_type input_queue;
osmium::io::detail::future_buffer_queue_type output_queue;
std::promise<osmium::io::Header> header_promise;
@@ -84,6 +85,7 @@ static header_buffer_type parse_xml(std::string input) {
osmium::io::detail::add_to_queue(input_queue, std::string{});
osmium::io::detail::parser_arguments args = {
+ pool,
input_queue,
output_queue,
header_promise,
diff --git a/test/examples/t/amenity_list/CMakeLists.txt b/test/examples/t/amenity_list/CMakeLists.txt
index c12fc7d..3a99a8a 100644
--- a/test/examples/t/amenity_list/CMakeLists.txt
+++ b/test/examples/t/amenity_list/CMakeLists.txt
@@ -1,7 +1,13 @@
-add_test(NAME examples_amenity_list
+add_test(NAME examples_amenity_list_node
COMMAND osmium_amenity_list ${CMAKE_CURRENT_SOURCE_DIR}/node.osm)
-set_tests_properties(examples_amenity_list PROPERTIES
+set_tests_properties(examples_amenity_list_node PROPERTIES
PASS_REGULAR_EXPRESSION " 8\\.8721, 53\\.0966 post_office")
+add_test(NAME examples_amenity_list_area
+ COMMAND osmium_amenity_list ${CMAKE_CURRENT_SOURCE_DIR}/area.osm)
+
+set_tests_properties(examples_amenity_list_area PROPERTIES
+ PASS_REGULAR_EXPRESSION " 8\\.5839, 53\\.5602 restaurant")
+
diff --git a/test/examples/t/amenity_list/area.osm b/test/examples/t/amenity_list/area.osm
new file mode 100644
index 0000000..bbf60fb
--- /dev/null
+++ b/test/examples/t/amenity_list/area.osm
@@ -0,0 +1,18 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6">
+ <node id="2791512283" visible="true" version="1" changeset="21695983" timestamp="2014-04-14T20:45:22Z" user="Gerd Taddicken" uid="25464" lat="53.5601034" lon="8.5840408"/>
+ <node id="2791512284" visible="true" version="1" changeset="21695983" timestamp="2014-04-14T20:45:22Z" user="Gerd Taddicken" uid="25464" lat="53.5601127" lon="8.5837753"/>
+ <node id="2791512287" visible="true" version="1" changeset="21695983" timestamp="2014-04-14T20:45:22Z" user="Gerd Taddicken" uid="25464" lat="53.5602544" lon="8.5837933"/>
+ <node id="2791512289" visible="true" version="1" changeset="21695983" timestamp="2014-04-14T20:45:22Z" user="Gerd Taddicken" uid="25464" lat="53.5602464" lon="8.5840476"/>
+ <way id="274425514" visible="true" version="4" changeset="41519398" timestamp="2016-08-17T19:16:40Z" user="Lutalica_1974" uid="2096672">
+ <nd ref="2791512283"/>
+ <nd ref="2791512284"/>
+ <nd ref="2791512287"/>
+ <nd ref="2791512289"/>
+ <nd ref="2791512283"/>
+ <tag k="amenity" v="restaurant"/>
+ <tag k="building" v="house"/>
+ <tag k="cuisine" v="american"/>
+ <tag k="name" v="Seamen's Club"/>
+ </way>
+</osm>
diff --git a/test/examples/t/area_test/CMakeLists.txt b/test/examples/t/area_test/CMakeLists.txt
new file mode 100644
index 0000000..81899a1
--- /dev/null
+++ b/test/examples/t/area_test/CMakeLists.txt
@@ -0,0 +1,25 @@
+
+add_test(NAME examples_area_test_help
+ COMMAND osmium_area_test -h)
+
+set_tests_properties(examples_area_test_help PROPERTIES
+ PASS_REGULAR_EXPRESSION "^osmium_area_test .* OSMFILE")
+
+add_test(NAME examples_area_test_data
+ COMMAND osmium_area_test ${CMAKE_CURRENT_SOURCE_DIR}/data.osm)
+
+set_tests_properties(examples_area_test_data PROPERTIES
+ PASS_REGULAR_EXPRESSION "\nWarning! Some member ways missing for these multipolygon relations: 701901\n$")
+
+add_test(NAME examples_area_test_dump
+ COMMAND osmium_area_test -o ${CMAKE_CURRENT_SOURCE_DIR}/data.osm)
+
+set_tests_properties(examples_area_test_dump PROPERTIES
+ PASS_REGULAR_EXPRESSION " id=1403801")
+
+add_test(NAME examples_area_test_wkt
+ COMMAND osmium_area_test -w ${CMAKE_CURRENT_SOURCE_DIR}/data.osm)
+
+set_tests_properties(examples_area_test_wkt PROPERTIES
+ PASS_REGULAR_EXPRESSION "MULTIPOLYGON\\(\\(\\(7.11 1.01,7.14 1.01,7.14 1.04,7.11 1.04,7.11 1.01\\)\\)\\)\n")
+
diff --git a/test/examples/t/area_test/data.osm b/test/examples/t/area_test/data.osm
new file mode 100644
index 0000000..cbdeeaa
--- /dev/null
+++ b/test/examples/t/area_test/data.osm
@@ -0,0 +1,34 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+ <node id="701000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.11" lat="1.01"/>
+ <node id="701001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.11" lat="1.04"/>
+ <node id="701002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.14" lat="1.04"/>
+ <node id="701003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.14" lat="1.01"/>
+ <way id="701800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+ <nd ref="701000"/>
+ <nd ref="701001"/>
+ <nd ref="701002"/>
+ <tag k="test:section" v="mp-geom"/>
+ <tag k="test:id" v="701"/>
+ </way>
+ <way id="701801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+ <nd ref="701002"/>
+ <nd ref="701003"/>
+ <nd ref="701000"/>
+ <tag k="test:section" v="mp-geom"/>
+ <tag k="test:id" v="701"/>
+ </way>
+ <relation id="701900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+ <member type="way" ref="701800" role="outer"/>
+ <member type="way" ref="701801" role="outer"/>
+ <tag k="type" v="multipolygon"/>
+ <tag k="test:section" v="mp-geom"/>
+ <tag k="test:id" v="701"/>
+ <tag k="landuse" v="forest"/>
+ </relation>
+ <relation id="701901" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+ <member type="way" ref="701802" role="outer"/> <!-- missing member -->
+ <tag k="type" v="multipolygon"/>
+ <tag k="landuse" v="forest"/>
+ </relation>
+</osm>
diff --git a/test/examples/t/change_tags/CMakeLists.txt b/test/examples/t/change_tags/CMakeLists.txt
new file mode 100644
index 0000000..b054aa9
--- /dev/null
+++ b/test/examples/t/change_tags/CMakeLists.txt
@@ -0,0 +1,9 @@
+
+add_test(NAME examples_change_tags
+ COMMAND osmium_change_tags ${CMAKE_CURRENT_SOURCE_DIR}/data.osm ${CMAKE_CURRENT_BINARY_DIR}/result.osm)
+
+add_test(NAME examples_change_tags_compare
+ COMMAND ${CMAKE_COMMAND} -E compare_files ${CMAKE_CURRENT_SOURCE_DIR}/result.osm ${CMAKE_CURRENT_BINARY_DIR}/result.osm)
+
+set_tests_properties(examples_change_tags_compare PROPERTIES DEPENDS example_change_tags)
+
diff --git a/test/examples/t/change_tags/data.osm b/test/examples/t/change_tags/data.osm
new file mode 100644
index 0000000..d65c716
--- /dev/null
+++ b/test/examples/t/change_tags/data.osm
@@ -0,0 +1,20 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+ <node id="10" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lat="1.01" lon="7.11">
+ <tag k="created_by" v="some editor"/>
+ </node>
+ <node id="11" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lat="1.04" lon="7.11"/>
+ <node id="12" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lat="1.04" lon="7.14"/>
+ <way id="20" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+ <nd ref="10"/>
+ <nd ref="11"/>
+ <nd ref="12"/>
+ <tag k="created_by" v="some editor"/>
+ <tag k="landuse" v="forest"/>
+ <tag k="name" v="Example Forest"/>
+ </way>
+ <relation id="30" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+ <tag k="created_by" v="some editor"/>
+ <tag k="note" v=" relation without members"/>
+ </relation>
+</osm>
diff --git a/test/examples/t/change_tags/result.osm b/test/examples/t/change_tags/result.osm
new file mode 100644
index 0000000..1898b89
--- /dev/null
+++ b/test/examples/t/change_tags/result.osm
@@ -0,0 +1,16 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="osmium_change_tags">
+ <node id="10" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lat="1.01" lon="7.11"/>
+ <node id="11" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lat="1.04" lon="7.11"/>
+ <node id="12" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lat="1.04" lon="7.14"/>
+ <way id="20" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+ <nd ref="10"/>
+ <nd ref="11"/>
+ <nd ref="12"/>
+ <tag k="natural" v="wood"/>
+ <tag k="name" v="Example Forest"/>
+ </way>
+ <relation id="30" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+ <tag k="note" v=" relation without members"/>
+ </relation>
+</osm>
diff --git a/test/examples/t/convert/CMakeLists.txt b/test/examples/t/convert/CMakeLists.txt
new file mode 100644
index 0000000..a5f06fa
--- /dev/null
+++ b/test/examples/t/convert/CMakeLists.txt
@@ -0,0 +1,46 @@
+
+add_test(NAME examples_convert_help
+ COMMAND osmium_convert -h)
+
+set_tests_properties(examples_convert_help PROPERTIES
+ PASS_REGULAR_EXPRESSION "^osmium_convert .*OUTFILE")
+
+
+add_test(NAME examples_convert_xml_debug
+ COMMAND osmium_convert -t debug ${CMAKE_CURRENT_SOURCE_DIR}/data.osm)
+
+set_tests_properties(examples_convert_xml_debug PROPERTIES
+ PASS_REGULAR_EXPRESSION "node 701000\n version: 1 visible")
+
+
+add_test(NAME examples_convert_xml_opl
+ COMMAND osmium_convert -f osm -t opl ${CMAKE_CURRENT_SOURCE_DIR}/data.osm)
+
+set_tests_properties(examples_convert_xml_opl PROPERTIES
+ PASS_REGULAR_EXPRESSION "n701001 v1 dV c1 t2014-01-01T00:00:00Z i1 utest T x7.11 y1.04")
+
+
+add_test(NAME examples_convert_xml_pbf
+ COMMAND osmium_convert -t pbf ${CMAKE_CURRENT_SOURCE_DIR}/data.osm -)
+
+
+add_test(NAME examples_convert_xml_xml
+ COMMAND osmium_convert -t xml ${CMAKE_CURRENT_SOURCE_DIR}/data.osm)
+
+set_tests_properties(examples_convert_xml_xml PROPERTIES
+ PASS_REGULAR_EXPRESSION "<node id=\"701001\" ")
+
+# Should give a warning when converting from history to non-history file
+add_test(NAME examples_convert_osh_xml
+ COMMAND osmium_convert -f osh -t osm ${CMAKE_CURRENT_SOURCE_DIR}/data.osm)
+
+set_tests_properties(examples_convert_osh_xml PROPERTIES
+ PASS_REGULAR_EXPRESSION "Warning! You are converting from an OSM file")
+
+# Should fail when an unknown command line option is used
+add_test(NAME examples_convert_unknown_option
+ COMMAND osmium_convert --unknown)
+
+set_tests_properties(examples_convert_unknown_option PROPERTIES
+ WILL_FAIL true)
+
diff --git a/test/examples/t/convert/data.osm b/test/examples/t/convert/data.osm
new file mode 100644
index 0000000..cbdeeaa
--- /dev/null
+++ b/test/examples/t/convert/data.osm
@@ -0,0 +1,34 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+ <node id="701000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.11" lat="1.01"/>
+ <node id="701001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.11" lat="1.04"/>
+ <node id="701002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.14" lat="1.04"/>
+ <node id="701003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.14" lat="1.01"/>
+ <way id="701800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+ <nd ref="701000"/>
+ <nd ref="701001"/>
+ <nd ref="701002"/>
+ <tag k="test:section" v="mp-geom"/>
+ <tag k="test:id" v="701"/>
+ </way>
+ <way id="701801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+ <nd ref="701002"/>
+ <nd ref="701003"/>
+ <nd ref="701000"/>
+ <tag k="test:section" v="mp-geom"/>
+ <tag k="test:id" v="701"/>
+ </way>
+ <relation id="701900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+ <member type="way" ref="701800" role="outer"/>
+ <member type="way" ref="701801" role="outer"/>
+ <tag k="type" v="multipolygon"/>
+ <tag k="test:section" v="mp-geom"/>
+ <tag k="test:id" v="701"/>
+ <tag k="landuse" v="forest"/>
+ </relation>
+ <relation id="701901" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+ <member type="way" ref="701802" role="outer"/> <!-- missing member -->
+ <tag k="type" v="multipolygon"/>
+ <tag k="landuse" v="forest"/>
+ </relation>
+</osm>
diff --git a/test/examples/t/count/CMakeLists.txt b/test/examples/t/count/CMakeLists.txt
new file mode 100644
index 0000000..07ac6f4
--- /dev/null
+++ b/test/examples/t/count/CMakeLists.txt
@@ -0,0 +1,8 @@
+
+add_test(NAME examples_count
+ COMMAND osmium_count ${CMAKE_CURRENT_SOURCE_DIR}/data.osm)
+
+set_tests_properties(examples_count PROPERTIES
+ PASS_REGULAR_EXPRESSION "^Nodes: 2\nWays: 1\nRelations: 1\n\nMemory used:"
+)
+
diff --git a/test/examples/t/count/data.osm b/test/examples/t/count/data.osm
new file mode 100644
index 0000000..2a62ece
--- /dev/null
+++ b/test/examples/t/count/data.osm
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<osm version="0.6">
+ <node id="1" version="1" changeset="1" timestamp="2000-01-01T10:11:12Z" user="test" uid="1" lat="51.0271601" lon="13.7252197"/>
+ <node id="2" version="1" changeset="1" timestamp="2000-01-01T10:11:12Z" user="test" uid="1" lat="51.0288568" lon="13.7248159"/>
+ <way id="10" version="1" changeset="1" timestamp="2000-01-01T10:11:12Z" user="test" uid="1">
+ <nd ref="1"/>
+ <nd ref="2"/>
+ </way>
+ <relation id="20" version="1" changeset="1" timestamp="2000-01-01T10:11:12Z" user="test" uid="1">
+ <member type="way" ref="10" role=""/>
+ </relation>
+</osm>
diff --git a/test/examples/t/create_pois/CMakeLists.txt b/test/examples/t/create_pois/CMakeLists.txt
new file mode 100644
index 0000000..a2aa7cb
--- /dev/null
+++ b/test/examples/t/create_pois/CMakeLists.txt
@@ -0,0 +1,13 @@
+
+add_test(NAME examples_create_pois_okay
+ COMMAND osmium_create_pois -)
+
+set_tests_properties(examples_create_pois_okay PROPERTIES
+ PASS_REGULAR_EXPRESSION "^n-1 v1 dV c0 t....-..-..T..:..:..Z i0 u Tamenity=post_box x1\\.23 y3\\.45\nn-2 v1 dV c0 t....-..-..T..:..:..Z i0 u Tamenity=restaurant,name=Chez%20%OSM x1\\.24 y3\\.46\n$"
+)
+
+add_test(NAME examples_create_pois_unknown_file_type
+ COMMAND osmium_create_pois foo)
+
+set_tests_properties(examples_create_pois_unknown_file_type PROPERTIES WILL_FAIL true)
+
diff --git a/test/examples/t/debug/CMakeLists.txt b/test/examples/t/debug/CMakeLists.txt
new file mode 100644
index 0000000..6e2462c
--- /dev/null
+++ b/test/examples/t/debug/CMakeLists.txt
@@ -0,0 +1,55 @@
+
+add_test(NAME examples_debug_all
+ COMMAND osmium_debug ${CMAKE_CURRENT_SOURCE_DIR}/data.osm)
+
+set_tests_properties(examples_debug_all PROPERTIES
+ PASS_REGULAR_EXPRESSION " id=1\n.* id=2\n.* id=10\n.* id=20\n"
+)
+
+
+add_test(NAME examples_debug_nodes
+ COMMAND osmium_debug ${CMAKE_CURRENT_SOURCE_DIR}/data.osm n)
+
+set_tests_properties(examples_debug_nodes PROPERTIES
+ PASS_REGULAR_EXPRESSION "id=1\n.* id=2\n"
+)
+
+set_tests_properties(examples_debug_nodes PROPERTIES
+ FAIL_REGULAR_EXPRESSION "id=10\n"
+)
+
+
+add_test(NAME examples_debug_ways
+ COMMAND osmium_debug ${CMAKE_CURRENT_SOURCE_DIR}/data.osm w)
+
+set_tests_properties(examples_debug_ways PROPERTIES
+ PASS_REGULAR_EXPRESSION " id=10\n"
+)
+
+set_tests_properties(examples_debug_ways PROPERTIES
+ FAIL_REGULAR_EXPRESSION "id=20\n"
+)
+
+
+add_test(NAME examples_debug_relations
+ COMMAND osmium_debug ${CMAKE_CURRENT_SOURCE_DIR}/data.osm r)
+
+set_tests_properties(examples_debug_relations PROPERTIES
+ PASS_REGULAR_EXPRESSION " id=20\n"
+)
+
+set_tests_properties(examples_debug_relations PROPERTIES
+ FAIL_REGULAR_EXPRESSION "id=10\n"
+)
+
+add_test(NAME examples_debug_changesets
+ COMMAND osmium_debug ${CMAKE_CURRENT_SOURCE_DIR}/changesets.osm c)
+
+set_tests_properties(examples_debug_changesets PROPERTIES
+ PASS_REGULAR_EXPRESSION " id=15449962\n"
+)
+
+set_tests_properties(examples_debug_changesets PROPERTIES
+ FAIL_REGULAR_EXPRESSION "id=10\n"
+)
+
diff --git a/test/examples/t/debug/changesets.osm b/test/examples/t/debug/changesets.osm
new file mode 100644
index 0000000..61ee023
--- /dev/null
+++ b/test/examples/t/debug/changesets.osm
@@ -0,0 +1,7 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="Osmosis 0.41">
+ <changeset id="15449962" created_at="2013-03-22T02:10:17Z" num_changes="140" closed_at="2013-03-22T02:10:24Z" open="false" min_lon="106.8146927" min_lat="-6.1207748" max_lon="106.8212512" max_lat="-6.1133246" user="Vivianecahen" uid="1241761">
+ <tag k="comment" v="Adding Initial buildings and roads"/>
+ <tag k="created_by" v="JOSM/1.5 (5697 en)"/>
+ </changeset>
+</osm>
diff --git a/test/examples/t/debug/data.osm b/test/examples/t/debug/data.osm
new file mode 100644
index 0000000..15fbda3
--- /dev/null
+++ b/test/examples/t/debug/data.osm
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<osm version="0.6">
+ <bounds minlon="13.7248159" minlat="51.0271601" maxlon="13.7252197" maxlat="51.0288568"/>
+ <node id="1" version="1" changeset="1" timestamp="2000-01-01T10:11:12Z" user="test" uid="1" lat="51.0271601" lon="13.7252197"/>
+ <node id="2" version="1" changeset="1" timestamp="2000-01-01T10:11:12Z" user="test" uid="1" lat="51.0288568" lon="13.7248159"/>
+ <way id="10" version="1" changeset="1" timestamp="2000-01-01T10:11:12Z" user="test" uid="1">
+ <nd ref="1"/>
+ <nd ref="2"/>
+ </way>
+ <relation id="20" version="1" changeset="1" timestamp="2000-01-01T10:11:12Z" user="test" uid="1">
+ <member type="way" ref="10" role=""/>
+ </relation>
+</osm>
diff --git a/test/examples/t/dump_internal/CMakeLists.txt b/test/examples/t/dump_internal/CMakeLists.txt
new file mode 100644
index 0000000..6938563
--- /dev/null
+++ b/test/examples/t/dump_internal/CMakeLists.txt
@@ -0,0 +1,41 @@
+
+add_test(NAME examples_dump_internal
+ COMMAND osmium_dump_internal ${CMAKE_CURRENT_SOURCE_DIR}/data.osm ${CMAKE_CURRENT_BINARY_DIR}/out)
+
+# XXX Disable failing tests on Windows until we figure out what's wrong
+# See https://github.com/osmcode/libosmium/issues/220
+if(NOT MSVC)
+
+ add_test(NAME examples_dump_internal_index_nodes
+ COMMAND osmium_index_lookup --list=${CMAKE_CURRENT_BINARY_DIR}/out/nodes.idx --type=offset --dump)
+
+ set_tests_properties(examples_dump_internal_index_nodes PROPERTIES
+ DEPENDS examples_dump_internal
+ PASS_REGULAR_EXPRESSION "^701000 .*\n701001 .*\n")
+
+
+ add_test(NAME examples_dump_internal_index_ways
+ COMMAND osmium_index_lookup --list=${CMAKE_CURRENT_BINARY_DIR}/out/ways.idx --type=offset --dump)
+
+ set_tests_properties(examples_dump_internal_index_ways PROPERTIES
+ DEPENDS examples_dump_internal
+ PASS_REGULAR_EXPRESSION "^701800 .*\n701801 .*\n")
+
+
+ add_test(NAME examples_dump_internal_map_node2way_dump
+ COMMAND osmium_index_lookup --list=${CMAKE_CURRENT_BINARY_DIR}/out/node2way.map --type=id --dump)
+
+ set_tests_properties(examples_dump_internal_map_node2way_dump PROPERTIES
+ DEPENDS examples_dump_internal
+ PASS_REGULAR_EXPRESSION "^701000 701800\n701000 701801\n701001 701800\n")
+
+
+ add_test(NAME examples_dump_internal_map_node2way_search
+ COMMAND osmium_index_lookup --list=${CMAKE_CURRENT_BINARY_DIR}/out/node2way.map --type=id --search=701002)
+
+ set_tests_properties(examples_dump_internal_map_node2way_search PROPERTIES
+ DEPENDS examples_dump_internal
+ PASS_REGULAR_EXPRESSION "^701002 701800\n701002 701801\n$")
+
+endif()
+
diff --git a/test/examples/t/dump_internal/data.osm b/test/examples/t/dump_internal/data.osm
new file mode 100644
index 0000000..cbdeeaa
--- /dev/null
+++ b/test/examples/t/dump_internal/data.osm
@@ -0,0 +1,34 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+ <node id="701000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.11" lat="1.01"/>
+ <node id="701001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.11" lat="1.04"/>
+ <node id="701002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.14" lat="1.04"/>
+ <node id="701003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.14" lat="1.01"/>
+ <way id="701800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+ <nd ref="701000"/>
+ <nd ref="701001"/>
+ <nd ref="701002"/>
+ <tag k="test:section" v="mp-geom"/>
+ <tag k="test:id" v="701"/>
+ </way>
+ <way id="701801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+ <nd ref="701002"/>
+ <nd ref="701003"/>
+ <nd ref="701000"/>
+ <tag k="test:section" v="mp-geom"/>
+ <tag k="test:id" v="701"/>
+ </way>
+ <relation id="701900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+ <member type="way" ref="701800" role="outer"/>
+ <member type="way" ref="701801" role="outer"/>
+ <tag k="type" v="multipolygon"/>
+ <tag k="test:section" v="mp-geom"/>
+ <tag k="test:id" v="701"/>
+ <tag k="landuse" v="forest"/>
+ </relation>
+ <relation id="701901" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+ <member type="way" ref="701802" role="outer"/> <!-- missing member -->
+ <tag k="type" v="multipolygon"/>
+ <tag k="landuse" v="forest"/>
+ </relation>
+</osm>
diff --git a/test/examples/t/filter_discussions/CMakeLists.txt b/test/examples/t/filter_discussions/CMakeLists.txt
new file mode 100644
index 0000000..21e8f72
--- /dev/null
+++ b/test/examples/t/filter_discussions/CMakeLists.txt
@@ -0,0 +1,10 @@
+
+add_test(NAME examples_filter_discussions
+ COMMAND osmium_filter_discussions ${CMAKE_CURRENT_SOURCE_DIR}/changesets.osm -)
+
+set_tests_properties(examples_filter_discussions PROPERTIES
+ FAIL_REGULAR_EXPRESSION "<changeset id=\"402757\"")
+
+set_tests_properties(examples_filter_discussions PROPERTIES
+ PASS_REGULAR_EXPRESSION "<changeset id=\"402758\"")
+
diff --git a/test/examples/t/filter_discussions/changesets.osm b/test/examples/t/filter_discussions/changesets.osm
new file mode 100644
index 0000000..350a717
--- /dev/null
+++ b/test/examples/t/filter_discussions/changesets.osm
@@ -0,0 +1,11 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="Osmosis 0.41">
+ <changeset id="402757" created_at="2008-12-15T12:57:57Z" closed_at="2008-12-15T14:00:54Z" open="false" user="mrettig" uid="38842" min_lat="50.8899870" min_lon="8.0981539" max_lat="50.9508652" max_lon="8.1665031" num_changes="33" comments_count="0"/>
+ <changeset id="402758" created_at="2008-07-05T11:17:12Z" closed_at="2008-07-05T12:17:12Z" open="false" user="Jaycos" uid="45048" min_lat="51.7305590" min_lon="6.5904108" max_lat="51.7305590" max_lon="6.5904108" num_changes="1" comments_count="1">
+ <discussion>
+ <comment uid="123" user="foobar" date="2008-07-05T11:17:13Z">
+ <text>fake comment</text>
+ </comment>
+ </discussion>
+ </changeset>
+</osm>
diff --git a/test/examples/t/index_lookup/CMakeLists.txt b/test/examples/t/index_lookup/CMakeLists.txt
new file mode 100644
index 0000000..ac4c434
--- /dev/null
+++ b/test/examples/t/index_lookup/CMakeLists.txt
@@ -0,0 +1,46 @@
+
+add_test(NAME examples_index_lookup_help
+ COMMAND osmium_index_lookup -h)
+
+set_tests_properties(examples_index_lookup_help PROPERTIES
+ PASS_REGULAR_EXPRESSION "^Usage: osmium_index_lookup")
+
+# Fails with message if index file doesn't exist
+add_test(NAME examples_index_lookup_no_file
+ COMMAND osmium_index_lookup --list=file_does_not_exist --type=location --dump)
+
+set_tests_properties(examples_index_lookup_no_file PROPERTIES
+ PASS_REGULAR_EXPRESSION "^Can not open file")
+
+
+# Fails with message if --type option is not used
+add_test(NAME examples_index_lookup_no_type_option
+ COMMAND osmium_index_lookup --list=file_does_not_exist --dump)
+
+set_tests_properties(examples_index_lookup_no_type_option PROPERTIES
+ PASS_REGULAR_EXPRESSION "^Need --type argument.")
+
+
+# Fails with message if --type option is used with unknown type
+add_test(NAME examples_index_lookup_unknown_type
+ COMMAND osmium_index_lookup --list=file_does_not_exist --type=UNKNOWN --dump)
+
+set_tests_properties(examples_index_lookup_unknown_type PROPERTIES
+ PASS_REGULAR_EXPRESSION "^Unknown type 'UNKNOWN'")
+
+
+# Fails with message when combining options --array and --list
+add_test(NAME examples_index_lookup_array_list
+ COMMAND osmium_index_lookup --list=a --array=b)
+
+set_tests_properties(examples_index_lookup_array_list PROPERTIES
+ PASS_REGULAR_EXPRESSION "^Need option --array or --list, but not both\n$")
+
+
+# Fails with message when combining options --dump and --search
+add_test(NAME examples_index_lookup_dump_search
+ COMMAND osmium_index_lookup --list=x --dump --search=123)
+
+set_tests_properties(examples_index_lookup_dump_search PROPERTIES
+ PASS_REGULAR_EXPRESSION "Need option --dump or --search, but not both")
+
diff --git a/test/examples/t/location_cache/CMakeLists.txt b/test/examples/t/location_cache/CMakeLists.txt
new file mode 100644
index 0000000..8ca8b79
--- /dev/null
+++ b/test/examples/t/location_cache/CMakeLists.txt
@@ -0,0 +1,36 @@
+
+add_test(NAME examples_location_cache_create
+ COMMAND osmium_location_cache_create ${CMAKE_CURRENT_SOURCE_DIR}/data.osm ${CMAKE_CURRENT_BINARY_DIR}/locations.idx)
+
+
+# Fails with message if index file doesn't exist
+add_test(NAME examples_location_cache_no_file
+ COMMAND osmium_location_cache_use ${CMAKE_CURRENT_SOURCE_DIR}/way.osm ${CMAKE_CURRENT_BINARY_DIR}/file_does_not_exist)
+
+set_tests_properties(examples_location_cache_no_file PROPERTIES
+ PASS_REGULAR_EXPRESSION "Can not open location cache file")
+
+
+add_test(NAME examples_location_cache_use
+ COMMAND osmium_location_cache_use ${CMAKE_CURRENT_SOURCE_DIR}/way.osm ${CMAKE_CURRENT_BINARY_DIR}/locations.idx)
+
+set_tests_properties(examples_location_cache_use PROPERTIES
+ DEPENDS examples_location_cache_create
+ PASS_REGULAR_EXPRESSION "^way 20\n node 10 \\(7.11,1.01\\)\n node 11 \\(7.11,1.04\\)\n node 12 \\(7.14,1.04\\)\n$")
+
+
+add_test(NAME examples_location_cache_dump
+ COMMAND osmium_index_lookup --list=${CMAKE_CURRENT_BINARY_DIR}/locations.idx --type=location --dump)
+
+set_tests_properties(examples_location_cache_dump PROPERTIES
+ DEPENDS examples_location_cache_create
+ PASS_REGULAR_EXPRESSION "^10 \\(7.11,1.01\\)\n11 \\(7.11,1.04\\)\n12 \\(7.14,1.04\\)\n13 \\(7.14,1.01\\)\n$")
+
+
+add_test(NAME examples_location_cache_search
+ COMMAND osmium_index_lookup --list=${CMAKE_CURRENT_BINARY_DIR}/locations.idx --type=location --search=12)
+
+set_tests_properties(examples_location_cache_search PROPERTIES
+ DEPENDS examples_location_cache_create
+ PASS_REGULAR_EXPRESSION "^12 \\(7.14,1.04\\)\n$")
+
diff --git a/test/examples/t/location_cache/data.osm b/test/examples/t/location_cache/data.osm
new file mode 100644
index 0000000..04cb6fd
--- /dev/null
+++ b/test/examples/t/location_cache/data.osm
@@ -0,0 +1,7 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+ <node id="10" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.11" lat="1.01"/>
+ <node id="11" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.11" lat="1.04"/>
+ <node id="12" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.14" lat="1.04"/>
+ <node id="13" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.14" lat="1.01"/>
+</osm>
diff --git a/test/examples/t/location_cache/way.osm b/test/examples/t/location_cache/way.osm
new file mode 100644
index 0000000..f64a170
--- /dev/null
+++ b/test/examples/t/location_cache/way.osm
@@ -0,0 +1,9 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+ <way id="20" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+ <nd ref="10"/>
+ <nd ref="11"/>
+ <nd ref="12"/>
+ <tag k="highway" v="primary"/>
+ </way>
+</osm>
diff --git a/test/examples/t/pub_names/CMakeLists.txt b/test/examples/t/pub_names/CMakeLists.txt
index 9a68ae8..3abefa3 100644
--- a/test/examples/t/pub_names/CMakeLists.txt
+++ b/test/examples/t/pub_names/CMakeLists.txt
@@ -1,7 +1,21 @@
-add_test(NAME examples_pub_names
- COMMAND osmium_pub_names ${CMAKE_CURRENT_SOURCE_DIR}/pubs.osm)
-
-set_tests_properties(examples_pub_names PROPERTIES
+add_test(NAME examples_pub_names_node
+ COMMAND osmium_pub_names ${CMAKE_CURRENT_SOURCE_DIR}/pub-node.osm)
+set_tests_properties(examples_pub_names_node PROPERTIES
PASS_REGULAR_EXPRESSION "^Im Holze\n$")
+add_test(NAME examples_pub_names_way
+ COMMAND osmium_pub_names ${CMAKE_CURRENT_SOURCE_DIR}/pub-way.osm)
+set_tests_properties(examples_pub_names_way PROPERTIES
+ PASS_REGULAR_EXPRESSION "^Vereinsheim\n$")
+
+add_test(NAME examples_pub_names_noname
+ COMMAND osmium_pub_names ${CMAKE_CURRENT_SOURCE_DIR}/pub-noname.osm)
+set_tests_properties(examples_pub_names_noname PROPERTIES
+ PASS_REGULAR_EXPRESSION "^pub with unknown name\n$")
+
+add_test(NAME examples_pub_names_addr
+ COMMAND osmium_pub_names ${CMAKE_CURRENT_SOURCE_DIR}/pub-addr.osm)
+set_tests_properties(examples_pub_names_addr PROPERTIES
+ PASS_REGULAR_EXPRESSION "^Im Holze\n addr:city: Bremen\n")
+
diff --git a/test/examples/t/pub_names/pubs.osm b/test/examples/t/pub_names/pub-addr.osm
similarity index 69%
copy from test/examples/t/pub_names/pubs.osm
copy to test/examples/t/pub_names/pub-addr.osm
index ee54226..6199961 100644
--- a/test/examples/t/pub_names/pubs.osm
+++ b/test/examples/t/pub_names/pub-addr.osm
@@ -1,6 +1,9 @@
<?xml version='1.0' encoding='UTF-8'?>
<osm version="0.6">
<node id="167199652" version="3" timestamp="2010-12-27T13:15:02Z" uid="57645" user="KartoGrapHiti" changeset="6777507" lat="53.0526516" lon="8.8919477">
+ <tag k="addr:city" v="Bremen"/>
+ <tag k="addr:housenumber" v="28"/>
+ <tag k="addr:street" v="Kleine Westerholzstraße"/>
<tag k="amenity" v="pub"/>
<tag k="name" v="Im Holze"/>
</node>
diff --git a/test/examples/t/pub_names/pubs.osm b/test/examples/t/pub_names/pub-node.osm
similarity index 100%
copy from test/examples/t/pub_names/pubs.osm
copy to test/examples/t/pub_names/pub-node.osm
diff --git a/test/examples/t/pub_names/pubs.osm b/test/examples/t/pub_names/pub-noname.osm
similarity index 88%
rename from test/examples/t/pub_names/pubs.osm
rename to test/examples/t/pub_names/pub-noname.osm
index ee54226..3217889 100644
--- a/test/examples/t/pub_names/pubs.osm
+++ b/test/examples/t/pub_names/pub-noname.osm
@@ -2,6 +2,5 @@
<osm version="0.6">
<node id="167199652" version="3" timestamp="2010-12-27T13:15:02Z" uid="57645" user="KartoGrapHiti" changeset="6777507" lat="53.0526516" lon="8.8919477">
<tag k="amenity" v="pub"/>
- <tag k="name" v="Im Holze"/>
</node>
</osm>
diff --git a/test/examples/t/pub_names/pub-way.osm b/test/examples/t/pub_names/pub-way.osm
new file mode 100644
index 0000000..aec7a86
--- /dev/null
+++ b/test/examples/t/pub_names/pub-way.osm
@@ -0,0 +1,21 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6">
+ <node id="498785553" version="4" timestamp="2012-08-05T19:02:18Z" uid="342705" user="KonB" changeset="12624818" lat="53.5657289" lon="8.5727548"/>
+ <node id="498785555" version="4" timestamp="2012-08-05T19:02:18Z" uid="342705" user="KonB" changeset="12624818" lat="53.5657308" lon="8.5730408"/>
+ <node id="498785556" version="4" timestamp="2012-08-05T19:02:18Z" uid="342705" user="KonB" changeset="12624818" lat="53.5656184" lon="8.5730429"/>
+ <node id="498785558" version="4" timestamp="2012-08-05T19:02:18Z" uid="342705" user="KonB" changeset="12624818" lat="53.5656176" lon="8.5729218"/>
+ <node id="498785560" version="4" timestamp="2012-08-05T19:02:18Z" uid="342705" user="KonB" changeset="12624818" lat="53.5654994" lon="8.572924"/>
+ <node id="498785561" version="4" timestamp="2012-08-05T19:02:18Z" uid="342705" user="KonB" changeset="12624818" lat="53.5654983" lon="8.5727591"/>
+ <way id="40948654" version="2" timestamp="2009-09-17T09:27:41Z" uid="42429" user="42429" changeset="2509937">
+ <nd ref="498785553"/>
+ <nd ref="498785555"/>
+ <nd ref="498785556"/>
+ <nd ref="498785558"/>
+ <nd ref="498785560"/>
+ <nd ref="498785561"/>
+ <nd ref="498785553"/>
+ <tag k="name" v="Vereinsheim"/>
+ <tag k="amenity" v="pub"/>
+ <tag k="building" v="yes"/>
+ </way>
+</osm>
diff --git a/test/examples/t/read/CMakeLists.txt b/test/examples/t/read/CMakeLists.txt
new file mode 100644
index 0000000..ff2b7aa
--- /dev/null
+++ b/test/examples/t/read/CMakeLists.txt
@@ -0,0 +1,4 @@
+
+add_test(NAME examples_read
+ COMMAND osmium_read ${CMAKE_CURRENT_SOURCE_DIR}/data.osm)
+
diff --git a/test/examples/t/read/data.osm b/test/examples/t/read/data.osm
new file mode 100644
index 0000000..98462b6
--- /dev/null
+++ b/test/examples/t/read/data.osm
@@ -0,0 +1,29 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+ <node id="701000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.11" lat="1.01"/>
+ <node id="701001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.11" lat="1.04"/>
+ <node id="701002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.14" lat="1.04"/>
+ <node id="701003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.14" lat="1.01"/>
+ <way id="701800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+ <nd ref="701000"/>
+ <nd ref="701001"/>
+ <nd ref="701002"/>
+ <tag k="test:section" v="mp-geom"/>
+ <tag k="test:id" v="701"/>
+ </way>
+ <way id="701801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+ <nd ref="701002"/>
+ <nd ref="701003"/>
+ <nd ref="701000"/>
+ <tag k="test:section" v="mp-geom"/>
+ <tag k="test:id" v="701"/>
+ </way>
+ <relation id="701900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+ <member type="way" ref="701800" role="outer"/>
+ <member type="way" ref="701801" role="outer"/>
+ <tag k="type" v="multipolygon"/>
+ <tag k="test:section" v="mp-geom"/>
+ <tag k="test:id" v="701"/>
+ <tag k="landuse" v="forest"/>
+ </relation>
+</osm>
diff --git a/test/examples/t/read_with_progress/CMakeLists.txt b/test/examples/t/read_with_progress/CMakeLists.txt
new file mode 100644
index 0000000..2bc0881
--- /dev/null
+++ b/test/examples/t/read_with_progress/CMakeLists.txt
@@ -0,0 +1,4 @@
+
+add_test(NAME examples_read_with_progress
+ COMMAND osmium_read_with_progress ${CMAKE_CURRENT_SOURCE_DIR}/data.osm)
+
diff --git a/test/examples/t/read_with_progress/data.osm b/test/examples/t/read_with_progress/data.osm
new file mode 100644
index 0000000..98462b6
--- /dev/null
+++ b/test/examples/t/read_with_progress/data.osm
@@ -0,0 +1,29 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+ <node id="701000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.11" lat="1.01"/>
+ <node id="701001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.11" lat="1.04"/>
+ <node id="701002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.14" lat="1.04"/>
+ <node id="701003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.14" lat="1.01"/>
+ <way id="701800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+ <nd ref="701000"/>
+ <nd ref="701001"/>
+ <nd ref="701002"/>
+ <tag k="test:section" v="mp-geom"/>
+ <tag k="test:id" v="701"/>
+ </way>
+ <way id="701801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+ <nd ref="701002"/>
+ <nd ref="701003"/>
+ <nd ref="701000"/>
+ <tag k="test:section" v="mp-geom"/>
+ <tag k="test:id" v="701"/>
+ </way>
+ <relation id="701900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+ <member type="way" ref="701800" role="outer"/>
+ <member type="way" ref="701801" role="outer"/>
+ <tag k="type" v="multipolygon"/>
+ <tag k="test:section" v="mp-geom"/>
+ <tag k="test:id" v="701"/>
+ <tag k="landuse" v="forest"/>
+ </relation>
+</osm>
diff --git a/test/examples/t/tiles/CMakeLists.txt b/test/examples/t/tiles/CMakeLists.txt
new file mode 100644
index 0000000..5a4fbaa
--- /dev/null
+++ b/test/examples/t/tiles/CMakeLists.txt
@@ -0,0 +1,18 @@
+
+add_test(NAME examples_tiles_zoom_too_large
+ COMMAND osmium_tiles 50 1 1)
+
+set_tests_properties(examples_tiles_zoom_too_large PROPERTIES WILL_FAIL true)
+
+add_test(NAME examples_tiles_location_invalid
+ COMMAND osmium_tiles 1 200 200)
+
+set_tests_properties(examples_tiles_location_invalid PROPERTIES WILL_FAIL true)
+
+add_test(NAME examples_tiles_okay
+ COMMAND osmium_tiles 8 55.3 11.7)
+
+set_tests_properties(examples_tiles_okay PROPERTIES
+ PASS_REGULAR_EXPRESSION "^WGS84: lon=55.3 lat=11.7\nMercator: x=.*\nTile: zoom=8 x=167 y=119\n$"
+)
+
diff --git a/test/include/catch.hpp b/test/include/catch.hpp
index 6f9334b..7c351e9 100644
--- a/test/include/catch.hpp
+++ b/test/include/catch.hpp
@@ -1,6 +1,6 @@
/*
- * Catch v1.8.1
- * Generated: 2017-03-01 16:04:19.016511
+ * Catch v1.9.7
+ * Generated: 2017-08-10 23:49:15.233907
* ----------------------------------------------------------
* This file has been merged from multiple headers. Please don't edit it directly
* Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved.
@@ -40,11 +40,7 @@
#elif defined __GNUC__
# pragma GCC diagnostic ignored "-Wvariadic-macros"
# pragma GCC diagnostic ignored "-Wunused-variable"
-
- // For newer version we can use __Pragma to disable the warnings locally
-# if __GNUC__ == 4 && __GNUC_MINOR__ >= 4 && __GNUC_MINOR__ <= 7
-# pragma GCC diagnostic ignored "-Wparentheses"
-# endif
+# pragma GCC diagnostic ignored "-Wparentheses"
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wpadded"
@@ -124,6 +120,12 @@
# endif
# if defined(CATCH_CPP11_OR_GREATER)
+# define CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
+ _Pragma( "clang diagnostic push" ) \
+ _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" )
+# define CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \
+ _Pragma( "clang diagnostic pop" )
+
# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
_Pragma( "clang diagnostic push" ) \
_Pragma( "clang diagnostic ignored \"-Wparentheses\"" )
@@ -134,13 +136,24 @@
#endif // __clang__
////////////////////////////////////////////////////////////////////////////////
-// Cygwin
-#ifdef __CYGWIN__
+// We know some environments not to support full POSIX signals
+#if defined(__CYGWIN__) || defined(__QNX__)
# if !defined(CATCH_CONFIG_POSIX_SIGNALS)
# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS
# endif
+#endif
+
+#ifdef __OS400__
+# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS
+# define CATCH_CONFIG_COLOUR_NONE
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// Cygwin
+#ifdef __CYGWIN__
+
// Required for some versions of Cygwin to declare gettimeofday
// see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin
# define _BSD_SOURCE
@@ -169,22 +182,10 @@
// GCC
#ifdef __GNUC__
-# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)
-# define CATCH_GCC_HAS_NEW_PRAGMA
-# endif
-
# if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__)
# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR
# endif
-# if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) && defined(CATCH_GCC_HAS_NEW_PRAGMA)
-# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
- _Pragma( "GCC diagnostic push" ) \
- _Pragma( "GCC diagnostic ignored \"-Wparentheses\"" )
-# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
- _Pragma( "GCC diagnostic pop" )
-# endif
-
// - otherwise more recent versions define __cplusplus >= 201103L
// and will get picked up below
@@ -224,7 +225,7 @@
// Use __COUNTER__ if the compiler supports it
#if ( defined _MSC_VER && _MSC_VER >= 1300 ) || \
- ( defined __GNUC__ && __GNUC__ >= 4 && __GNUC_MINOR__ >= 3 ) || \
+ ( defined __GNUC__ && ( __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3 )) ) || \
( defined __clang__ && __clang_major__ >= 3 )
#define CATCH_INTERNAL_CONFIG_COUNTER
@@ -332,6 +333,10 @@
# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS
# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS
#endif
+#if !defined(CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS)
+# define CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS
+# define CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS
+#endif
// noexcept support:
#if defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_NOEXCEPT)
@@ -414,14 +419,14 @@ namespace Catch {
};
template<typename ContainerT>
- inline void deleteAll( ContainerT& container ) {
+ void deleteAll( ContainerT& container ) {
typename ContainerT::const_iterator it = container.begin();
typename ContainerT::const_iterator itEnd = container.end();
for(; it != itEnd; ++it )
delete *it;
}
template<typename AssociativeContainerT>
- inline void deleteAllValues( AssociativeContainerT& container ) {
+ void deleteAllValues( AssociativeContainerT& container ) {
typename AssociativeContainerT::const_iterator it = container.begin();
typename AssociativeContainerT::const_iterator itEnd = container.end();
for(; it != itEnd; ++it )
@@ -501,7 +506,6 @@ namespace Catch {
{
public:
NotImplementedException( SourceLineInfo const& lineInfo );
- NotImplementedException( NotImplementedException const& ) {}
virtual ~NotImplementedException() CATCH_NOEXCEPT {}
@@ -770,59 +774,76 @@ void registerTestCaseFunction
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \
static void TestName(); \
- namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); }\
+ CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
+ namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); } /* NOLINT */ \
+ CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \
static void TestName()
#define INTERNAL_CATCH_TESTCASE( ... ) \
INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), __VA_ARGS__ )
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \
- namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); }
+ CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
+ namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); } /* NOLINT */ \
+ CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\
+ CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
namespace{ \
struct TestName : ClassName{ \
void test(); \
}; \
- Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestName::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); \
+ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestName::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); /* NOLINT */ \
} \
+ CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \
void TestName::test()
#define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \
INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, __VA_ARGS__ )
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \
- Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) );
+ CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
+ Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); /* NOLINT */ \
+ CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS
#else
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_TESTCASE2( TestName, Name, Desc ) \
static void TestName(); \
- namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); }\
+ CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
+ namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); } /* NOLINT */ \
+ CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \
static void TestName()
#define INTERNAL_CATCH_TESTCASE( Name, Desc ) \
INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), Name, Desc )
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \
- namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); }
+ CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
+ namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); } /* NOLINT */ \
+ CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_TEST_CASE_METHOD2( TestCaseName, ClassName, TestName, Desc )\
+ CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
namespace{ \
struct TestCaseName : ClassName{ \
void test(); \
}; \
- Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestCaseName::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); \
+ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestCaseName::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); /* NOLINT */ \
} \
+ CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \
void TestCaseName::test()
#define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, TestName, Desc )\
INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, TestName, Desc )
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_REGISTER_TESTCASE( Function, Name, Desc ) \
- Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) );
+ CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \
+ Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); /* NOLINT */ \
+ CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS
+
#endif
// #included from: internal/catch_capture.hpp
@@ -910,22 +931,24 @@ namespace Catch {
template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( T const& );
template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( T const& );
- private:
- DecomposedExpression& operator = (DecomposedExpression const&);
+ private:
+ DecomposedExpression& operator = (DecomposedExpression const&);
};
struct AssertionInfo
{
- AssertionInfo() {}
- AssertionInfo( std::string const& _macroName,
+ AssertionInfo();
+ AssertionInfo( char const * _macroName,
SourceLineInfo const& _lineInfo,
- std::string const& _capturedExpression,
- ResultDisposition::Flags _resultDisposition );
+ char const * _capturedExpression,
+ ResultDisposition::Flags _resultDisposition,
+ char const * _secondArg = "");
- std::string macroName;
+ char const * macroName;
SourceLineInfo lineInfo;
- std::string capturedExpression;
+ char const * capturedExpression;
ResultDisposition::Flags resultDisposition;
+ char const * secondArg;
};
struct AssertionResultData
@@ -1021,16 +1044,24 @@ namespace Matchers {
}
protected:
+ virtual ~MatcherUntypedBase();
virtual std::string describe() const = 0;
mutable std::string m_cachedToString;
private:
MatcherUntypedBase& operator = ( MatcherUntypedBase const& );
};
- template<typename ObjectT, typename ComparatorT = ObjectT>
- struct MatcherBase : MatcherUntypedBase {
-
+ template<typename ObjectT>
+ struct MatcherMethod {
virtual bool match( ObjectT const& arg ) const = 0;
+ };
+ template<typename PtrT>
+ struct MatcherMethod<PtrT*> {
+ virtual bool match( PtrT* arg ) const = 0;
+ };
+
+ template<typename ObjectT, typename ComparatorT = ObjectT>
+ struct MatcherBase : MatcherUntypedBase, MatcherMethod<ObjectT> {
MatchAllOf<ComparatorT> operator && ( MatcherBase const& other ) const;
MatchAnyOf<ComparatorT> operator || ( MatcherBase const& other ) const;
@@ -1131,23 +1162,23 @@ namespace Matchers {
// This allows the types to be inferred
// - deprecated: prefer ||, && and !
template<typename T>
- inline Impl::MatchNotOf<T> Not( Impl::MatcherBase<T> const& underlyingMatcher ) {
+ Impl::MatchNotOf<T> Not( Impl::MatcherBase<T> const& underlyingMatcher ) {
return Impl::MatchNotOf<T>( underlyingMatcher );
}
template<typename T>
- inline Impl::MatchAllOf<T> AllOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2 ) {
+ Impl::MatchAllOf<T> AllOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2 ) {
return Impl::MatchAllOf<T>() && m1 && m2;
}
template<typename T>
- inline Impl::MatchAllOf<T> AllOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2, Impl::MatcherBase<T> const& m3 ) {
+ Impl::MatchAllOf<T> AllOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2, Impl::MatcherBase<T> const& m3 ) {
return Impl::MatchAllOf<T>() && m1 && m2 && m3;
}
template<typename T>
- inline Impl::MatchAnyOf<T> AnyOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2 ) {
+ Impl::MatchAnyOf<T> AnyOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2 ) {
return Impl::MatchAnyOf<T>() || m1 || m2;
}
template<typename T>
- inline Impl::MatchAnyOf<T> AnyOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2, Impl::MatcherBase<T> const& m3 ) {
+ Impl::MatchAnyOf<T> AnyOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2, Impl::MatcherBase<T> const& m3 ) {
return Impl::MatchAnyOf<T>() || m1 || m2 || m3;
}
@@ -1184,6 +1215,7 @@ namespace Catch {
char const* capturedExpression,
ResultDisposition::Flags resultDisposition,
char const* secondArg = "" );
+ ~ResultBuilder();
template<typename T>
ExpressionLhs<T const&> operator <= ( T const& operand );
@@ -1191,7 +1223,7 @@ namespace Catch {
template<typename T>
ResultBuilder& operator << ( T const& value ) {
- m_stream.oss << value;
+ stream().oss << value;
return *this;
}
@@ -1218,13 +1250,33 @@ namespace Catch {
template<typename ArgT, typename MatcherT>
void captureMatch( ArgT const& arg, MatcherT const& matcher, char const* matcherString );
+ void setExceptionGuard();
+ void unsetExceptionGuard();
+
private:
AssertionInfo m_assertionInfo;
AssertionResultData m_data;
- CopyableStream m_stream;
+
+ CopyableStream &stream()
+ {
+ if(!m_usedStream)
+ {
+ m_usedStream = true;
+ m_stream().oss.str("");
+ }
+ return m_stream();
+ }
+
+ static CopyableStream &m_stream()
+ {
+ static CopyableStream s;
+ return s;
+ }
bool m_shouldDebugBreak;
bool m_shouldThrow;
+ bool m_guardException;
+ bool m_usedStream;
};
} // namespace Catch
@@ -1265,7 +1317,7 @@ namespace Internal {
template<> struct OperatorTraits<IsGreaterThanOrEqualTo>{ static const char* getName(){ return ">="; } };
template<typename T>
- inline T& opCast(T const& t) { return const_cast<T&>(t); }
+ T& opCast(T const& t) { return const_cast<T&>(t); }
// nullptr_t support based on pull request #154 from Konstantin Baumann
#ifdef CATCH_CONFIG_CPP11_NULLPTR
@@ -1275,7 +1327,7 @@ namespace Internal {
// So the compare overloads can be operator agnostic we convey the operator as a template
// enum, which is used to specialise an Evaluator for doing the comparison.
template<typename T1, typename T2, Operator Op>
- class Evaluator{};
+ struct Evaluator{};
template<typename T1, typename T2>
struct Evaluator<T1, T2, IsEqualTo> {
@@ -1541,7 +1593,7 @@ std::string toString( std::nullptr_t );
#ifdef __OBJC__
std::string toString( NSString const * const& nsstring );
- std::string toString( NSString * CATCH_ARC_STRONG const& nsstring );
+ std::string toString( NSString * CATCH_ARC_STRONG & nsstring );
std::string toString( NSObject* const& nsObject );
#endif
@@ -1549,6 +1601,7 @@ namespace Detail {
extern const std::string unprintableString;
+ #if !defined(CATCH_CONFIG_CPP11_STREAM_INSERTABLE_CHECK)
struct BorgType {
template<typename T> BorgType( T const& );
};
@@ -1567,6 +1620,20 @@ namespace Detail {
static T const&t;
enum { value = sizeof( testStreamable(s << t) ) == sizeof( TrueType ) };
};
+#else
+ template<typename T>
+ class IsStreamInsertable {
+ template<typename SS, typename TT>
+ static auto test(int)
+ -> decltype( std::declval<SS&>() << std::declval<TT>(), std::true_type() );
+
+ template<typename, typename>
+ static auto test(...) -> std::false_type;
+
+ public:
+ static const bool value = decltype(test<std::ostream,const T&>(0))::value;
+ };
+#endif
#if defined(CATCH_CONFIG_CPP11_IS_ENUM)
template<typename T,
@@ -1615,7 +1682,7 @@ namespace Detail {
std::string rawMemoryToString( const void *object, std::size_t size );
template<typename T>
- inline std::string rawMemoryToString( const T& object ) {
+ std::string rawMemoryToString( const T& object ) {
return rawMemoryToString( &object, sizeof(object) );
}
@@ -1810,7 +1877,7 @@ public:
}
virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE {
- dest = Catch::toString( m_truthy );
+ dest = Catch::toString( m_lhs );
}
private:
@@ -1904,7 +1971,7 @@ private:
namespace Catch {
template<typename T>
- inline ExpressionLhs<T const&> ResultBuilder::operator <= ( T const& operand ) {
+ ExpressionLhs<T const&> ResultBuilder::operator <= ( T const& operand ) {
return ExpressionLhs<T const&>( *this, operand );
}
@@ -1913,7 +1980,7 @@ namespace Catch {
}
template<typename ArgT, typename MatcherT>
- inline void ResultBuilder::captureMatch( ArgT const& arg, MatcherT const& matcher,
+ void ResultBuilder::captureMatch( ArgT const& arg, MatcherT const& matcher,
char const* matcherString ) {
MatchExpression<ArgT const&, MatcherT const&> expr( arg, matcher, matcherString );
setResultType( matcher.match( arg ) );
@@ -2009,7 +2076,13 @@ namespace Catch {
virtual std::string getCurrentTestName() const = 0;
virtual const AssertionResult* getLastResult() const = 0;
+ virtual void exceptionEarlyReported() = 0;
+
virtual void handleFatalErrorCondition( std::string const& message ) = 0;
+
+ virtual bool lastAssertionPassed() = 0;
+ virtual void assertionPassed() = 0;
+ virtual void assertionRun() = 0;
};
IResultCapture& getResultCapture();
@@ -2052,9 +2125,9 @@ namespace Catch{
#if defined(__ppc64__) || defined(__ppc__)
#define CATCH_TRAP() \
__asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \
- : : : "memory","r0","r3","r4" )
+ : : : "memory","r0","r3","r4" ) /* NOLINT */
#else
- #define CATCH_TRAP() __asm__("int $3\n" : : )
+ #define CATCH_TRAP() __asm__("int $3\n" : : /* NOLINT */ )
#endif
#elif defined(CATCH_PLATFORM_LINUX)
@@ -2062,7 +2135,7 @@ namespace Catch{
// directly at the location of the failing check instead of breaking inside
// raise() called from it, i.e. one stack frame below.
#if defined(__GNUC__) && (defined(__i386) || defined(__x86_64))
- #define CATCH_TRAP() asm volatile ("int $3")
+ #define CATCH_TRAP() asm volatile ("int $3") /* NOLINT */
#else // Fall back to the generic way.
#include <signal.h>
@@ -2093,45 +2166,6 @@ namespace Catch {
};
}
-// #included from: catch_type_traits.hpp
-#define TWOBLUECUBES_CATCH_TYPE_TRAITS_HPP_INCLUDED
-
-#if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS)
-#include <type_traits>
-#endif
-
-namespace Catch {
-
-#if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS)
-
- template <typename T>
- using add_lvalue_reference = std::add_lvalue_reference<T>;
-
- template <typename T>
- using add_const = std::add_const<T>;
-
-#else
-
- template <typename T>
- struct add_const {
- typedef const T type;
- };
-
- template <typename T>
- struct add_lvalue_reference {
- typedef T& type;
- };
- template <typename T>
- struct add_lvalue_reference<T&> {
- typedef T& type;
- };
- // No && overload, because that is C++11, in which case we have
- // proper type_traits implementation from the standard library
-
-#endif
-
-}
-
#if defined(CATCH_CONFIG_FAST_COMPILE)
///////////////////////////////////////////////////////////////////////////////
// We can speedup compilation significantly by breaking into debugger lower in
@@ -2139,6 +2173,33 @@ namespace Catch {
// macro in each assertion
#define INTERNAL_CATCH_REACT( resultBuilder ) \
resultBuilder.react();
+
+///////////////////////////////////////////////////////////////////////////////
+// Another way to speed-up compilation is to omit local try-catch for REQUIRE*
+// macros.
+// This can potentially cause false negative, if the test code catches
+// the exception before it propagates back up to the runner.
+#define INTERNAL_CATCH_TEST_NO_TRY( macroName, resultDisposition, expr ) \
+ do { \
+ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
+ __catchResult.setExceptionGuard(); \
+ CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
+ ( __catchResult <= expr ).endExpression(); \
+ CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
+ __catchResult.unsetExceptionGuard(); \
+ INTERNAL_CATCH_REACT( __catchResult ) \
+ } while( Catch::isTrue( false && static_cast<bool>( !!(expr) ) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look
+// The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&.
+
+#define INTERNAL_CHECK_THAT_NO_TRY( macroName, matcher, resultDisposition, arg ) \
+ do { \
+ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \
+ __catchResult.setExceptionGuard(); \
+ __catchResult.captureMatch( arg, matcher, #matcher ); \
+ __catchResult.unsetExceptionGuard(); \
+ INTERNAL_CATCH_REACT( __catchResult ) \
+ } while( Catch::alwaysFalse() )
+
#else
///////////////////////////////////////////////////////////////////////////////
// In the event of a failure works out if the debugger needs to be invoked
@@ -2151,7 +2212,7 @@ namespace Catch {
#endif
///////////////////////////////////////////////////////////////////////////////
-#define INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ) \
+#define INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ) \
do { \
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
try { \
@@ -2167,17 +2228,17 @@ namespace Catch {
// The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&.
///////////////////////////////////////////////////////////////////////////////
-#define INTERNAL_CATCH_IF( expr, resultDisposition, macroName ) \
- INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \
- if( Catch::getResultCapture().getLastResult()->succeeded() )
+#define INTERNAL_CATCH_IF( macroName, resultDisposition, expr ) \
+ INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ); \
+ if( Catch::getResultCapture().lastAssertionPassed() )
///////////////////////////////////////////////////////////////////////////////
-#define INTERNAL_CATCH_ELSE( expr, resultDisposition, macroName ) \
- INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \
- if( !Catch::getResultCapture().getLastResult()->succeeded() )
+#define INTERNAL_CATCH_ELSE( macroName, resultDisposition, expr ) \
+ INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ); \
+ if( !Catch::getResultCapture().lastAssertionPassed() )
///////////////////////////////////////////////////////////////////////////////
-#define INTERNAL_CATCH_NO_THROW( expr, resultDisposition, macroName ) \
+#define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, expr ) \
do { \
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
try { \
@@ -2191,7 +2252,7 @@ namespace Catch {
} while( Catch::alwaysFalse() )
///////////////////////////////////////////////////////////////////////////////
-#define INTERNAL_CATCH_THROWS( expr, resultDisposition, matcher, macroName ) \
+#define INTERNAL_CATCH_THROWS( macroName, resultDisposition, matcher, expr ) \
do { \
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition, #matcher ); \
if( __catchResult.allowThrows() ) \
@@ -2208,7 +2269,7 @@ namespace Catch {
} while( Catch::alwaysFalse() )
///////////////////////////////////////////////////////////////////////////////
-#define INTERNAL_CATCH_THROWS_AS( expr, exceptionType, resultDisposition, macroName ) \
+#define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \
do { \
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr ", " #exceptionType, resultDisposition ); \
if( __catchResult.allowThrows() ) \
@@ -2216,7 +2277,7 @@ namespace Catch {
static_cast<void>(expr); \
__catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \
} \
- catch( Catch::add_const<Catch::add_lvalue_reference<exceptionType>::type>::type ) { \
+ catch( exceptionType ) { \
__catchResult.captureResult( Catch::ResultWas::Ok ); \
} \
catch( ... ) { \
@@ -2229,7 +2290,7 @@ namespace Catch {
///////////////////////////////////////////////////////////////////////////////
#ifdef CATCH_CONFIG_VARIADIC_MACROS
- #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, ... ) \
+ #define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \
do { \
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \
__catchResult << __VA_ARGS__ + ::Catch::StreamEndStop(); \
@@ -2237,7 +2298,7 @@ namespace Catch {
INTERNAL_CATCH_REACT( __catchResult ) \
} while( Catch::alwaysFalse() )
#else
- #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, log ) \
+ #define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, log ) \
do { \
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \
__catchResult << log + ::Catch::StreamEndStop(); \
@@ -2247,11 +2308,11 @@ namespace Catch {
#endif
///////////////////////////////////////////////////////////////////////////////
-#define INTERNAL_CATCH_INFO( log, macroName ) \
+#define INTERNAL_CATCH_INFO( macroName, log ) \
Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage ) = Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log;
///////////////////////////////////////////////////////////////////////////////
-#define INTERNAL_CHECK_THAT( arg, matcher, resultDisposition, macroName ) \
+#define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \
do { \
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \
try { \
@@ -2368,14 +2429,19 @@ namespace Catch {
// #included from: catch_timer.h
#define TWOBLUECUBES_CATCH_TIMER_H_INCLUDED
-#ifdef CATCH_PLATFORM_WINDOWS
-typedef unsigned long long uint64_t;
+#ifdef _MSC_VER
+
+namespace Catch {
+ typedef unsigned long long UInt64;
+}
#else
#include <stdint.h>
+namespace Catch {
+ typedef uint64_t UInt64;
+}
#endif
namespace Catch {
-
class Timer {
public:
Timer() : m_ticks( 0 ) {}
@@ -2385,7 +2451,7 @@ namespace Catch {
double getElapsedSeconds() const;
private:
- uint64_t m_ticks;
+ UInt64 m_ticks;
};
} // namespace Catch
@@ -2424,7 +2490,6 @@ namespace Catch {
// #included from: internal/catch_generators.hpp
#define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED
-#include <iterator>
#include <vector>
#include <string>
#include <stdlib.h>
@@ -2538,7 +2603,7 @@ public:
private:
void move( CompositeGenerator& other ) {
- std::copy( other.m_composed.begin(), other.m_composed.end(), std::back_inserter( m_composed ) );
+ m_composed.insert( m_composed.end(), other.m_composed.begin(), other.m_composed.end() );
m_totalSize += other.m_totalSize;
other.m_composed.clear();
}
@@ -2620,12 +2685,15 @@ namespace Catch {
struct IExceptionTranslator;
struct IReporterRegistry;
struct IReporterFactory;
+ struct ITagAliasRegistry;
struct IRegistryHub {
virtual ~IRegistryHub();
virtual IReporterRegistry const& getReporterRegistry() const = 0;
virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0;
+ virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0;
+
virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0;
};
@@ -2635,6 +2703,7 @@ namespace Catch {
virtual void registerListener( Ptr<IReporterFactory> const& factory ) = 0;
virtual void registerTest( TestCase const& testInfo ) = 0;
virtual void registerTranslator( const IExceptionTranslator* translator ) = 0;
+ virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0;
};
IRegistryHub& getRegistryHub();
@@ -2726,26 +2795,25 @@ namespace Detail {
m_value( value )
{}
- Approx( Approx const& other )
- : m_epsilon( other.m_epsilon ),
- m_margin( other.m_margin ),
- m_scale( other.m_scale ),
- m_value( other.m_value )
- {}
-
static Approx custom() {
return Approx( 0 );
}
- Approx operator()( double value ) {
- Approx approx( value );
+#if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS)
+
+ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+ Approx operator()( T value ) {
+ Approx approx( static_cast<double>(value) );
approx.epsilon( m_epsilon );
approx.margin( m_margin );
approx.scale( m_scale );
return approx;
}
-#if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS)
+ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+ explicit Approx( T value ): Approx(static_cast<double>(value))
+ {}
+
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
friend bool operator == ( const T& lhs, Approx const& rhs ) {
// Thanks to Richard Harris for his help refining this formula
@@ -2773,29 +2841,53 @@ namespace Detail {
}
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
- friend bool operator <= ( T lhs, Approx const& rhs )
- {
- return double(lhs) < rhs.m_value || lhs == rhs;
+ friend bool operator <= ( T lhs, Approx const& rhs ) {
+ return double(lhs) < rhs.m_value || lhs == rhs;
}
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
- friend bool operator <= ( Approx const& lhs, T rhs )
- {
- return lhs.m_value < double(rhs) || lhs == rhs;
+ friend bool operator <= ( Approx const& lhs, T rhs ) {
+ return lhs.m_value < double(rhs) || lhs == rhs;
}
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
- friend bool operator >= ( T lhs, Approx const& rhs )
- {
- return double(lhs) > rhs.m_value || lhs == rhs;
+ friend bool operator >= ( T lhs, Approx const& rhs ) {
+ return double(lhs) > rhs.m_value || lhs == rhs;
}
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
- friend bool operator >= ( Approx const& lhs, T rhs )
- {
- return lhs.m_value > double(rhs) || lhs == rhs;
+ friend bool operator >= ( Approx const& lhs, T rhs ) {
+ return lhs.m_value > double(rhs) || lhs == rhs;
+ }
+
+ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+ Approx& epsilon( T newEpsilon ) {
+ m_epsilon = double(newEpsilon);
+ return *this;
}
+
+ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+ Approx& margin( T newMargin ) {
+ m_margin = double(newMargin);
+ return *this;
+ }
+
+ template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
+ Approx& scale( T newScale ) {
+ m_scale = double(newScale);
+ return *this;
+ }
+
#else
+
+ Approx operator()( double value ) {
+ Approx approx( value );
+ approx.epsilon( m_epsilon );
+ approx.margin( m_margin );
+ approx.scale( m_scale );
+ return approx;
+ }
+
friend bool operator == ( double lhs, Approx const& rhs ) {
// Thanks to Richard Harris for his help refining this formula
bool relativeOK = std::fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( std::fabs(lhs), std::fabs(rhs.m_value) ) );
@@ -2817,26 +2909,21 @@ namespace Detail {
return !operator==( rhs, lhs );
}
- friend bool operator <= ( double lhs, Approx const& rhs )
- {
- return lhs < rhs.m_value || lhs == rhs;
+ friend bool operator <= ( double lhs, Approx const& rhs ) {
+ return lhs < rhs.m_value || lhs == rhs;
}
- friend bool operator <= ( Approx const& lhs, double rhs )
- {
- return lhs.m_value < rhs || lhs == rhs;
+ friend bool operator <= ( Approx const& lhs, double rhs ) {
+ return lhs.m_value < rhs || lhs == rhs;
}
- friend bool operator >= ( double lhs, Approx const& rhs )
- {
- return lhs > rhs.m_value || lhs == rhs;
+ friend bool operator >= ( double lhs, Approx const& rhs ) {
+ return lhs > rhs.m_value || lhs == rhs;
}
- friend bool operator >= ( Approx const& lhs, double rhs )
- {
- return lhs.m_value > rhs || lhs == rhs;
+ friend bool operator >= ( Approx const& lhs, double rhs ) {
+ return lhs.m_value > rhs || lhs == rhs;
}
-#endif
Approx& epsilon( double newEpsilon ) {
m_epsilon = newEpsilon;
@@ -2852,6 +2939,7 @@ namespace Detail {
m_scale = newScale;
return *this;
}
+#endif
std::string toString() const {
std::ostringstream oss;
@@ -2893,7 +2981,7 @@ namespace Matchers {
};
struct StringMatcherBase : MatcherBase<std::string> {
- StringMatcherBase( std::string operation, CasedString const& comparator );
+ StringMatcherBase( std::string const& operation, CasedString const& comparator );
virtual std::string describe() const CATCH_OVERRIDE;
CasedString m_comparator;
@@ -3032,7 +3120,7 @@ namespace Matchers {
namespace Catch {
struct TagAlias {
- TagAlias( std::string _tag, SourceLineInfo _lineInfo ) : tag( _tag ), lineInfo( _lineInfo ) {}
+ TagAlias( std::string const& _tag, SourceLineInfo _lineInfo ) : tag( _tag ), lineInfo( _lineInfo ) {}
std::string tag;
SourceLineInfo lineInfo;
@@ -3104,8 +3192,18 @@ namespace Catch {
}
private:
- T* nullableValue;
- char storage[sizeof(T)];
+ T *nullableValue;
+ union {
+ char storage[sizeof(T)];
+
+ // These are here to force alignment for the storage
+ long double dummy1;
+ void (*dummy2)();
+ long double dummy3;
+#ifdef CATCH_CONFIG_CPP11_LONG_LONG
+ long long dummy4;
+#endif
+ };
};
} // end namespace Catch
@@ -3304,64 +3402,67 @@ namespace Catch {
namespace Impl {
namespace NSStringMatchers {
- template<typename MatcherT>
- struct StringHolder : MatcherImpl<MatcherT, NSString*>{
+ struct StringHolder : MatcherBase<NSString*>{
StringHolder( NSString* substr ) : m_substr( [substr copy] ){}
StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){}
StringHolder() {
arcSafeRelease( m_substr );
}
+ virtual bool match( NSString* arg ) const CATCH_OVERRIDE {
+ return false;
+ }
+
NSString* m_substr;
};
- struct Equals : StringHolder<Equals> {
+ struct Equals : StringHolder {
Equals( NSString* substr ) : StringHolder( substr ){}
- virtual bool match( ExpressionType const& str ) const {
+ virtual bool match( NSString* str ) const CATCH_OVERRIDE {
return (str != nil || m_substr == nil ) &&
[str isEqualToString:m_substr];
}
- virtual std::string toString() const {
+ virtual std::string describe() const CATCH_OVERRIDE {
return "equals string: " + Catch::toString( m_substr );
}
};
- struct Contains : StringHolder<Contains> {
+ struct Contains : StringHolder {
Contains( NSString* substr ) : StringHolder( substr ){}
- virtual bool match( ExpressionType const& str ) const {
+ virtual bool match( NSString* str ) const {
return (str != nil || m_substr == nil ) &&
[str rangeOfString:m_substr].location != NSNotFound;
}
- virtual std::string toString() const {
+ virtual std::string describe() const CATCH_OVERRIDE {
return "contains string: " + Catch::toString( m_substr );
}
};
- struct StartsWith : StringHolder<StartsWith> {
+ struct StartsWith : StringHolder {
StartsWith( NSString* substr ) : StringHolder( substr ){}
- virtual bool match( ExpressionType const& str ) const {
+ virtual bool match( NSString* str ) const {
return (str != nil || m_substr == nil ) &&
[str rangeOfString:m_substr].location == 0;
}
- virtual std::string toString() const {
+ virtual std::string describe() const CATCH_OVERRIDE {
return "starts with: " + Catch::toString( m_substr );
}
};
- struct EndsWith : StringHolder<EndsWith> {
+ struct EndsWith : StringHolder {
EndsWith( NSString* substr ) : StringHolder( substr ){}
- virtual bool match( ExpressionType const& str ) const {
+ virtual bool match( NSString* str ) const {
return (str != nil || m_substr == nil ) &&
[str rangeOfString:m_substr].location == [str length] - [m_substr length];
}
- virtual std::string toString() const {
+ virtual std::string describe() const CATCH_OVERRIDE {
return "ends with: " + Catch::toString( m_substr );
}
};
@@ -3408,16 +3509,16 @@ return @ desc; \
#include <crtdbg.h>
class LeakDetector {
public:
- LeakDetector() {
- int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
- flag |= _CRTDBG_LEAK_CHECK_DF;
- flag |= _CRTDBG_ALLOC_MEM_DF;
- _CrtSetDbgFlag(flag);
- _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
- _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
- // Change this to leaking allocation's number to break there
- _CrtSetBreakAlloc(-1);
- }
+ LeakDetector() {
+ int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
+ flag |= _CRTDBG_LEAK_CHECK_DF;
+ flag |= _CRTDBG_ALLOC_MEM_DF;
+ _CrtSetDbgFlag(flag);
+ _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
+ _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
+ // Change this to leaking allocation's number to break there
+ _CrtSetBreakAlloc(-1);
+ }
};
#else
class LeakDetector {};
@@ -3617,7 +3718,7 @@ namespace Catch {
ITagAliasRegistry const* m_tagAliases;
public:
- TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {}
+ TestSpecParser( ITagAliasRegistry const& tagAliases ) :m_mode(None), m_exclusion(false), m_start(0), m_pos(0), m_tagAliases( &tagAliases ) {}
TestSpecParser& parse( std::string const& arg ) {
m_mode = None;
@@ -3801,6 +3902,7 @@ namespace Catch {
std::ostream& cout();
std::ostream& cerr();
+ std::ostream& clog();
struct IStream {
virtual ~IStream() CATCH_NOEXCEPT;
@@ -3856,6 +3958,7 @@ namespace Catch {
listTags( false ),
listReporters( false ),
listTestNamesOnly( false ),
+ listExtraInfo( false ),
showSuccessfulTests( false ),
shouldDebugBreak( false ),
noThrow( false ),
@@ -3875,6 +3978,7 @@ namespace Catch {
bool listTags;
bool listReporters;
bool listTestNamesOnly;
+ bool listExtraInfo;
bool showSuccessfulTests;
bool shouldDebugBreak;
@@ -3933,6 +4037,7 @@ namespace Catch {
bool listTestNamesOnly() const { return m_data.listTestNamesOnly; }
bool listTags() const { return m_data.listTags; }
bool listReporters() const { return m_data.listReporters; }
+ bool listExtraInfo() const { return m_data.listExtraInfo; }
std::string getProcessName() const { return m_data.processName; }
@@ -4020,6 +4125,7 @@ namespace Catch {
#include <vector>
#include <sstream>
#include <algorithm>
+#include <cctype>
// Use optional outer namespace
#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE
@@ -4129,7 +4235,7 @@ namespace Tbc {
return oss.str();
}
- inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) {
+ friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) {
for( Text::const_iterator it = _text.begin(), itEnd = _text.end();
it != itEnd; ++it ) {
if( it != _text.begin() )
@@ -4362,7 +4468,7 @@ namespace Clara {
_dest = _source;
}
char toLowerCh(char c) {
- return static_cast<char>( ::tolower( c ) );
+ return static_cast<char>( std::tolower( c ) );
}
inline void convertInto( std::string const& _source, bool& _dest ) {
std::string sourceLC = _source;
@@ -4516,12 +4622,13 @@ namespace Clara {
}
void parseIntoTokens( std::string const& arg, std::vector<Token>& tokens ) {
- for( std::size_t i = 0; i <= arg.size(); ++i ) {
+ for( std::size_t i = 0; i < arg.size(); ++i ) {
char c = arg[i];
if( c == '"' )
inQuotes = !inQuotes;
mode = handleMode( i, c, arg, tokens );
}
+ mode = handleMode( arg.size(), '\0', arg, tokens );
}
Mode handleMode( std::size_t i, char c, std::string const& arg, std::vector<Token>& tokens ) {
switch( mode ) {
@@ -4554,6 +4661,7 @@ namespace Clara {
default: from = i; return ShortOpt;
}
}
+
Mode handleOpt( std::size_t i, char c, std::string const& arg, std::vector<Token>& tokens ) {
if( std::string( ":=\0", 3 ).find( c ) == std::string::npos )
return mode;
@@ -4885,7 +4993,7 @@ namespace Clara {
}
std::vector<Parser::Token> parseInto( std::vector<std::string> const& args, ConfigT& config ) const {
- std::string processName = args[0];
+ std::string processName = args.empty() ? std::string() : args[0];
std::size_t lastSlash = processName.find_last_of( "/\\" );
if( lastSlash != std::string::npos )
processName = processName.substr( lastSlash+1 );
@@ -5191,6 +5299,10 @@ namespace Catch {
.describe( "list all/matching test cases names only" )
.bind( &ConfigData::listTestNamesOnly );
+ cli["--list-extra-info"]
+ .describe( "list all/matching test cases with more info" )
+ .bind( &ConfigData::listExtraInfo );
+
cli["--list-reporters"]
.describe( "list all reporters" )
.bind( &ConfigData::listReporters );
@@ -5719,8 +5831,9 @@ namespace Catch {
}
std::size_t matchedTests = 0;
- TextAttributes nameAttr, tagsAttr;
+ TextAttributes nameAttr, descAttr, tagsAttr;
nameAttr.setInitialIndent( 2 ).setIndent( 4 );
+ descAttr.setIndent( 4 );
tagsAttr.setIndent( 6 );
std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
@@ -5735,6 +5848,13 @@ namespace Catch {
Colour colourGuard( colour );
Catch::cout() << Text( testCaseInfo.name, nameAttr ) << std::endl;
+ if( config.listExtraInfo() ) {
+ Catch::cout() << " " << testCaseInfo.lineInfo << std::endl;
+ std::string description = testCaseInfo.description;
+ if( description.empty() )
+ description = "(NO DESCRIPTION)";
+ Catch::cout() << Text( description, descAttr ) << std::endl;
+ }
if( !testCaseInfo.tags.empty() )
Catch::cout() << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl;
}
@@ -5758,9 +5878,12 @@ namespace Catch {
matchedTests++;
TestCaseInfo const& testCaseInfo = it->getTestCaseInfo();
if( startsWith( testCaseInfo.name, '#' ) )
- Catch::cout() << '"' << testCaseInfo.name << '"' << std::endl;
+ Catch::cout() << '"' << testCaseInfo.name << '"';
else
- Catch::cout() << testCaseInfo.name << std::endl;
+ Catch::cout() << testCaseInfo.name;
+ if ( config.listExtraInfo() )
+ Catch::cout() << "\t@" << testCaseInfo.lineInfo;
+ Catch::cout() << std::endl;
}
return matchedTests;
}
@@ -5852,7 +5975,7 @@ namespace Catch {
inline Option<std::size_t> list( Config const& config ) {
Option<std::size_t> listedCount;
- if( config.listTests() )
+ if( config.listTests() || ( config.listExtraInfo() && !config.listTestNamesOnly() ) )
listedCount = listedCount.valueOr(0) + listTests( config );
if( config.listTestNamesOnly() )
listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config );
@@ -5871,13 +5994,14 @@ namespace Catch {
// #included from: catch_test_case_tracker.hpp
#define TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED
-#include <map>
+#include <algorithm>
#include <string>
#include <assert.h>
#include <vector>
-#include <iterator>
#include <stdexcept>
+CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS
+
namespace Catch {
namespace TestCaseTracking {
@@ -6148,12 +6272,12 @@ namespace TestCaseTracking {
if( !filters.empty() ) {
m_filters.push_back(""); // Root - should never be consulted
m_filters.push_back(""); // Test Case - not a section filter
- std::copy( filters.begin(), filters.end(), std::back_inserter( m_filters ) );
+ m_filters.insert( m_filters.end(), filters.begin(), filters.end() );
}
}
void addNextFilters( std::vector<std::string> const& filters ) {
if( filters.size() > 1 )
- std::copy( filters.begin()+1, filters.end(), std::back_inserter( m_filters ) );
+ m_filters.insert( m_filters.end(), ++filters.begin(), filters.end() );
}
};
@@ -6223,6 +6347,8 @@ using TestCaseTracking::IndexTracker;
} // namespace Catch
+CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS
+
// #included from: catch_fatal_condition.hpp
#define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED
@@ -6292,7 +6418,6 @@ namespace Catch {
static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) {
for (int i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) {
if (ExceptionInfo->ExceptionRecord->ExceptionCode == signalDefs[i].id) {
- reset();
reportFatal(signalDefs[i].name);
}
}
@@ -6462,6 +6587,29 @@ namespace Catch {
std::string& m_targetString;
};
+ // StdErr has two constituent streams in C++, std::cerr and std::clog
+ // This means that we need to redirect 2 streams into 1 to keep proper
+ // order of writes and cannot use StreamRedirect on its own
+ class StdErrRedirect {
+ public:
+ StdErrRedirect(std::string& targetString)
+ :m_cerrBuf( cerr().rdbuf() ), m_clogBuf(clog().rdbuf()),
+ m_targetString(targetString){
+ cerr().rdbuf(m_oss.rdbuf());
+ clog().rdbuf(m_oss.rdbuf());
+ }
+ ~StdErrRedirect() {
+ m_targetString += m_oss.str();
+ cerr().rdbuf(m_cerrBuf);
+ clog().rdbuf(m_clogBuf);
+ }
+ private:
+ std::streambuf* m_cerrBuf;
+ std::streambuf* m_clogBuf;
+ std::ostringstream m_oss;
+ std::string& m_targetString;
+ };
+
///////////////////////////////////////////////////////////////////////////
class RunContext : public IResultCapture, public IRunner {
@@ -6476,7 +6624,8 @@ namespace Catch {
m_context( getCurrentMutableContext() ),
m_activeTestCase( CATCH_NULL ),
m_config( _config ),
- m_reporter( reporter )
+ m_reporter( reporter ),
+ m_shouldReportUnexpected ( true )
{
m_context.setRunner( this );
m_context.setConfig( m_config );
@@ -6554,14 +6703,32 @@ namespace Catch {
m_totals.assertions.failed++;
}
- if( m_reporter->assertionEnded( AssertionStats( result, m_messages, m_totals ) ) )
- m_messages.clear();
+ // We have no use for the return value (whether messages should be cleared), because messages were made scoped
+ // and should be let to clear themselves out.
+ static_cast<void>(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals)));
// Reset working state
- m_lastAssertionInfo = AssertionInfo( std::string(), m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition );
+ m_lastAssertionInfo = AssertionInfo( "", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition );
m_lastResult = result;
}
+ virtual bool lastAssertionPassed()
+ {
+ return m_totals.assertions.passed == (m_prevPassed + 1);
+ }
+
+ virtual void assertionPassed()
+ {
+ m_totals.assertions.passed++;
+ m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}";
+ m_lastAssertionInfo.macroName = "";
+ }
+
+ virtual void assertionRun()
+ {
+ m_prevPassed = m_totals.assertions.passed;
+ }
+
virtual bool sectionStarted (
SectionInfo const& sectionInfo,
Counts& assertions
@@ -6633,11 +6800,19 @@ namespace Catch {
return &m_lastResult;
}
+ virtual void exceptionEarlyReported() {
+ m_shouldReportUnexpected = false;
+ }
+
virtual void handleFatalErrorCondition( std::string const& message ) {
- ResultBuilder resultBuilder = makeUnexpectedResultBuilder();
- resultBuilder.setResultType( ResultWas::FatalErrorCondition );
- resultBuilder << message;
- resultBuilder.captureExpression();
+ // Don't rebuild the result -- the stringification itself can cause more fatal errors
+ // Instead, fake a result data.
+ AssertionResultData tempResult;
+ tempResult.resultType = ResultWas::FatalErrorCondition;
+ tempResult.message = message;
+ AssertionResult result(m_lastAssertionInfo, tempResult);
+
+ getResultCapture().assertionEnded(result);
handleUnfinishedSections();
@@ -6654,6 +6829,7 @@ namespace Catch {
Totals deltaTotals;
deltaTotals.testCases.failed = 1;
+ deltaTotals.assertions.failed = 1;
m_reporter->testCaseEnded( TestCaseStats( testInfo,
deltaTotals,
std::string(),
@@ -6678,8 +6854,9 @@ namespace Catch {
m_reporter->sectionStarting( testCaseSection );
Counts prevAssertions = m_totals.assertions;
double duration = 0;
+ m_shouldReportUnexpected = true;
try {
- m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, std::string(), ResultDisposition::Normal );
+ m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal );
seedRng( *m_config );
@@ -6687,7 +6864,7 @@ namespace Catch {
timer.start();
if( m_reporter->getPreferences().shouldRedirectStdOut ) {
StreamRedirect coutRedir( Catch::cout(), redirectedCout );
- StreamRedirect cerrRedir( Catch::cerr(), redirectedCerr );
+ StdErrRedirect errRedir( redirectedCerr );
invokeActiveTestCase();
}
else {
@@ -6699,7 +6876,11 @@ namespace Catch {
// This just means the test was aborted due to failure
}
catch(...) {
- makeUnexpectedResultBuilder().useActiveException();
+ // Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions
+ // are reported without translation at the point of origin.
+ if (m_shouldReportUnexpected) {
+ makeUnexpectedResultBuilder().useActiveException();
+ }
}
m_testCaseTracker->close();
handleUnfinishedSections();
@@ -6727,9 +6908,9 @@ namespace Catch {
private:
ResultBuilder makeUnexpectedResultBuilder() const {
- return ResultBuilder( m_lastAssertionInfo.macroName.c_str(),
+ return ResultBuilder( m_lastAssertionInfo.macroName,
m_lastAssertionInfo.lineInfo,
- m_lastAssertionInfo.capturedExpression.c_str(),
+ m_lastAssertionInfo.capturedExpression,
m_lastAssertionInfo.resultDisposition );
}
@@ -6759,6 +6940,8 @@ namespace Catch {
std::vector<SectionEndInfo> m_unfinishedSections;
std::vector<ITracker*> m_activeSections;
TrackerContext m_trackerContext;
+ size_t m_prevPassed;
+ bool m_shouldReportUnexpected;
};
IResultCapture& getResultCapture() {
@@ -6780,7 +6963,7 @@ namespace Catch {
Version( unsigned int _majorVersion,
unsigned int _minorVersion,
unsigned int _patchNumber,
- std::string const& _branchName,
+ char const * const _branchName,
unsigned int _buildNumber );
unsigned int const majorVersion;
@@ -6788,7 +6971,7 @@ namespace Catch {
unsigned int const patchNumber;
// buildNumber is only used if branchName is not null
- std::string const branchName;
+ char const * const branchName;
unsigned int const buildNumber;
friend std::ostream& operator << ( std::ostream& os, Version const& version );
@@ -6797,7 +6980,7 @@ namespace Catch {
void operator=( Version const& );
};
- extern Version libraryVersion;
+ inline Version libraryVersion();
}
#include <fstream>
@@ -6816,10 +6999,14 @@ namespace Catch {
return reporter;
}
+#if !defined(CATCH_CONFIG_DEFAULT_REPORTER)
+#define CATCH_CONFIG_DEFAULT_REPORTER "console"
+#endif
+
Ptr<IStreamingReporter> makeReporter( Ptr<Config> const& config ) {
std::vector<std::string> reporters = config->getReporterNames();
if( reporters.empty() )
- reporters.push_back( "console" );
+ reporters.push_back( CATCH_CONFIG_DEFAULT_REPORTER );
Ptr<IStreamingReporter> reporter;
for( std::vector<std::string>::const_iterator it = reporters.begin(), itEnd = reporters.end();
@@ -6879,11 +7066,11 @@ namespace Catch {
if( lastSlash != std::string::npos )
filename = filename.substr( lastSlash+1 );
- std::string::size_type lastDot = filename.find_last_of( "." );
+ std::string::size_type lastDot = filename.find_last_of( '.' );
if( lastDot != std::string::npos )
filename = filename.substr( 0, lastDot );
- tags.insert( "#" + filename );
+ tags.insert( '#' + filename );
setTags( test, tags );
}
}
@@ -6909,7 +7096,7 @@ namespace Catch {
}
void showHelp( std::string const& processName ) {
- Catch::cout() << "\nCatch v" << libraryVersion << "\n";
+ Catch::cout() << "\nCatch v" << libraryVersion() << "\n";
m_cli.usage( Catch::cout(), processName );
Catch::cout() << "For more detail usage please see the project docs\n" << std::endl;
@@ -6950,6 +7137,32 @@ namespace Catch {
return returnCode;
}
+ #if defined(WIN32) && defined(UNICODE)
+ int run( int argc, wchar_t const* const* const argv ) {
+
+ char **utf8Argv = new char *[ argc ];
+
+ for ( int i = 0; i < argc; ++i ) {
+ int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL );
+
+ utf8Argv[ i ] = new char[ bufSize ];
+
+ WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, NULL, NULL );
+ }
+
+ int returnCode = applyCommandLine( argc, utf8Argv );
+ if( returnCode == 0 )
+ returnCode = run();
+
+ for ( int i = 0; i < argc; ++i )
+ delete [] utf8Argv[ i ];
+
+ delete [] utf8Argv;
+
+ return returnCode;
+ }
+ #endif
+
int run() {
if( m_configData.showHelp )
return 0;
@@ -7297,6 +7510,26 @@ namespace Catch {
};
}
+// #included from: catch_tag_alias_registry.h
+#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_H_INCLUDED
+
+#include <map>
+
+namespace Catch {
+
+ class TagAliasRegistry : public ITagAliasRegistry {
+ public:
+ virtual ~TagAliasRegistry();
+ virtual Option<TagAlias> find( std::string const& alias ) const;
+ virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const;
+ void add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo );
+
+ private:
+ std::map<std::string, TagAlias> m_registry;
+ };
+
+} // end namespace Catch
+
namespace Catch {
namespace {
@@ -7318,6 +7551,9 @@ namespace Catch {
virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() CATCH_OVERRIDE {
return m_exceptionTranslatorRegistry;
}
+ virtual ITagAliasRegistry const& getTagAliasRegistry() const CATCH_OVERRIDE {
+ return m_tagAliasRegistry;
+ }
public: // IMutableRegistryHub
virtual void registerReporter( std::string const& name, Ptr<IReporterFactory> const& factory ) CATCH_OVERRIDE {
@@ -7332,11 +7568,15 @@ namespace Catch {
virtual void registerTranslator( const IExceptionTranslator* translator ) CATCH_OVERRIDE {
m_exceptionTranslatorRegistry.registerTranslator( translator );
}
+ virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) CATCH_OVERRIDE {
+ m_tagAliasRegistry.add( alias, tag, lineInfo );
+ }
private:
TestRegistry m_testCaseRegistry;
ReporterRegistry m_reporterRegistry;
ExceptionTranslatorRegistry m_exceptionTranslatorRegistry;
+ TagAliasRegistry m_tagAliasRegistry;
};
// Single, global, instance
@@ -7482,6 +7722,9 @@ namespace Catch {
std::ostream& cerr() {
return std::cerr;
}
+ std::ostream& clog() {
+ return std::clog;
+ }
#endif
}
@@ -7581,6 +7824,23 @@ namespace Catch {
// #included from: catch_console_colour_impl.hpp
#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED
+// #included from: catch_errno_guard.hpp
+#define TWOBLUECUBES_CATCH_ERRNO_GUARD_HPP_INCLUDED
+
+#include <cerrno>
+
+namespace Catch {
+
+ class ErrnoGuard {
+ public:
+ ErrnoGuard():m_oldErrno(errno){}
+ ~ErrnoGuard() { errno = m_oldErrno; }
+ private:
+ int m_oldErrno;
+ };
+
+}
+
namespace Catch {
namespace {
@@ -7716,6 +7976,7 @@ namespace {
};
IColourImpl* platformColourInstance() {
+ ErrnoGuard guard;
Ptr<IConfig const> config = getCurrentContext().getConfig();
UseColour::YesOrNo colourMode = config
? config->useColour()
@@ -7834,14 +8095,18 @@ namespace Catch {
namespace Catch {
- AssertionInfo::AssertionInfo( std::string const& _macroName,
+ AssertionInfo::AssertionInfo():macroName(""), capturedExpression(""), resultDisposition(ResultDisposition::Normal), secondArg(""){}
+
+ AssertionInfo::AssertionInfo( char const * _macroName,
SourceLineInfo const& _lineInfo,
- std::string const& _capturedExpression,
- ResultDisposition::Flags _resultDisposition )
+ char const * _capturedExpression,
+ ResultDisposition::Flags _resultDisposition,
+ char const * _secondArg)
: macroName( _macroName ),
lineInfo( _lineInfo ),
capturedExpression( _capturedExpression ),
- resultDisposition( _resultDisposition )
+ resultDisposition( _resultDisposition ),
+ secondArg( _secondArg )
{}
AssertionResult::AssertionResult() {}
@@ -7868,24 +8133,30 @@ namespace Catch {
}
bool AssertionResult::hasExpression() const {
- return !m_info.capturedExpression.empty();
+ return m_info.capturedExpression[0] != 0;
}
bool AssertionResult::hasMessage() const {
return !m_resultData.message.empty();
}
+ std::string capturedExpressionWithSecondArgument( char const * capturedExpression, char const * secondArg ) {
+ return (secondArg[0] == 0 || secondArg[0] == '"' && secondArg[1] == '"')
+ ? capturedExpression
+ : std::string(capturedExpression) + ", " + secondArg;
+ }
+
std::string AssertionResult::getExpression() const {
if( isFalseTest( m_info.resultDisposition ) )
- return '!' + m_info.capturedExpression;
+ return '!' + capturedExpressionWithSecondArgument(m_info.capturedExpression, m_info.secondArg);
else
- return m_info.capturedExpression;
+ return capturedExpressionWithSecondArgument(m_info.capturedExpression, m_info.secondArg);
}
std::string AssertionResult::getExpressionInMacro() const {
- if( m_info.macroName.empty() )
- return m_info.capturedExpression;
+ if( m_info.macroName[0] == 0 )
+ return capturedExpressionWithSecondArgument(m_info.capturedExpression, m_info.secondArg);
else
- return m_info.macroName + "( " + m_info.capturedExpression + " )";
+ return std::string(m_info.macroName) + "( " + capturedExpressionWithSecondArgument(m_info.capturedExpression, m_info.secondArg) + " )";
}
bool AssertionResult::hasExpandedExpression() const {
@@ -7945,17 +8216,13 @@ namespace Catch {
}
inline void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) {
if( isReservedTag( tag ) ) {
- {
- Colour colourGuard( Colour::Red );
- Catch::cerr()
- << "Tag name [" << tag << "] not allowed.\n"
- << "Tag names starting with non alpha-numeric characters are reserved\n";
- }
- {
- Colour colourGuard( Colour::FileName );
- Catch::cerr() << _lineInfo << std::endl;
- }
- exit(1);
+ std::ostringstream ss;
+ ss << Colour(Colour::Red)
+ << "Tag name [" << tag << "] not allowed.\n"
+ << "Tag names starting with non alpha-numeric characters are reserved\n"
+ << Colour(Colour::FileName)
+ << _lineInfo << '\n';
+ throw std::runtime_error(ss.str());
}
}
@@ -8117,7 +8384,7 @@ namespace Catch {
( unsigned int _majorVersion,
unsigned int _minorVersion,
unsigned int _patchNumber,
- std::string const& _branchName,
+ char const * const _branchName,
unsigned int _buildNumber )
: majorVersion( _majorVersion ),
minorVersion( _minorVersion ),
@@ -8130,15 +8397,18 @@ namespace Catch {
os << version.majorVersion << '.'
<< version.minorVersion << '.'
<< version.patchNumber;
-
- if( !version.branchName.empty() ) {
- os << '-' << version.branchName
- << '.' << version.buildNumber;
+ // branchName is never null -> 0th char is \0 if it is empty
+ if (version.branchName[0]) {
+ os << '-' << version.branchName
+ << '.' << version.buildNumber;
}
return os;
}
- Version libraryVersion( 1, 8, 1, "", 0 );
+ inline Version libraryVersion() {
+ static Version version( 1, 9, 7, "", 0 );
+ return version;
+ }
}
@@ -8172,7 +8442,9 @@ namespace Catch {
{}
ScopedMessage::~ScopedMessage() {
- getResultCapture().popScopedMessage( m_info );
+ if ( !std::uncaught_exception() ){
+ getResultCapture().popScopedMessage(m_info);
+ }
}
} // end namespace Catch
@@ -8320,21 +8592,21 @@ namespace Catch {
namespace {
#ifdef CATCH_PLATFORM_WINDOWS
- uint64_t getCurrentTicks() {
- static uint64_t hz=0, hzo=0;
+ UInt64 getCurrentTicks() {
+ static UInt64 hz=0, hzo=0;
if (!hz) {
QueryPerformanceFrequency( reinterpret_cast<LARGE_INTEGER*>( &hz ) );
QueryPerformanceCounter( reinterpret_cast<LARGE_INTEGER*>( &hzo ) );
}
- uint64_t t;
+ UInt64 t;
QueryPerformanceCounter( reinterpret_cast<LARGE_INTEGER*>( &t ) );
return ((t-hzo)*1000000)/hz;
}
#else
- uint64_t getCurrentTicks() {
+ UInt64 getCurrentTicks() {
timeval t;
gettimeofday(&t,CATCH_NULL);
- return static_cast<uint64_t>( t.tv_sec ) * 1000000ull + static_cast<uint64_t>( t.tv_usec );
+ return static_cast<UInt64>( t.tv_sec ) * 1000000ull + static_cast<UInt64>( t.tv_usec );
}
#endif
}
@@ -8486,6 +8758,10 @@ namespace Catch {
m_timer.start();
}
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable:4996) // std::uncaught_exception is deprecated in C++17
+#endif
Section::~Section() {
if( m_sectionIncluded ) {
SectionEndInfo endInfo( m_info, m_assertions, m_timer.getElapsedSeconds() );
@@ -8495,6 +8771,9 @@ namespace Catch {
getResultCapture().sectionEnded( endInfo );
}
}
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
// This indicates whether the section should be executed or not
Section::operator bool() const {
@@ -8567,6 +8846,9 @@ namespace Catch {
// be strace, for example) in /proc/$PID/status, so just get it from
// there instead.
bool isDebuggerActive(){
+ // Libstdc++ has a bug, where std::ifstream sets errno to 0
+ // This way our users can properly assert over errno values
+ ErrnoGuard guard;
std::ifstream in("/proc/self/status");
for( std::string line; std::getline(in, line); ) {
static const int PREFIX_LEN = 11;
@@ -8807,7 +9089,7 @@ std::string toString( std::nullptr_t ) {
return "nil";
return "@" + toString([nsstring UTF8String]);
}
- std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ) {
+ std::string toString( NSString * CATCH_ARC_STRONG & nsstring ) {
if( !nsstring )
return "nil";
return "@" + toString([nsstring UTF8String]);
@@ -8824,21 +9106,28 @@ std::string toString( std::nullptr_t ) {
namespace Catch {
- std::string capturedExpressionWithSecondArgument( std::string const& capturedExpression, std::string const& secondArg ) {
- return secondArg.empty() || secondArg == "\"\""
- ? capturedExpression
- : capturedExpression + ", " + secondArg;
- }
ResultBuilder::ResultBuilder( char const* macroName,
SourceLineInfo const& lineInfo,
char const* capturedExpression,
ResultDisposition::Flags resultDisposition,
char const* secondArg )
- : m_assertionInfo( macroName, lineInfo, capturedExpressionWithSecondArgument( capturedExpression, secondArg ), resultDisposition ),
+ : m_assertionInfo( macroName, lineInfo, capturedExpression, resultDisposition, secondArg ),
m_shouldDebugBreak( false ),
- m_shouldThrow( false )
+ m_shouldThrow( false ),
+ m_guardException( false ),
+ m_usedStream( false )
{}
+ ResultBuilder::~ResultBuilder() {
+#if defined(CATCH_CONFIG_FAST_COMPILE)
+ if ( m_guardException ) {
+ stream().oss << "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE";
+ captureResult( ResultWas::ThrewException );
+ getCurrentContext().getResultCapture()->exceptionEarlyReported();
+ }
+#endif
+ }
+
ResultBuilder& ResultBuilder::setResultType( ResultWas::OfType result ) {
m_data.resultType = result;
return *this;
@@ -8849,13 +9138,25 @@ namespace Catch {
}
void ResultBuilder::endExpression( DecomposedExpression const& expr ) {
- AssertionResult result = build( expr );
- handleResult( result );
+ // Flip bool results if FalseTest flag is set
+ if( isFalseTest( m_assertionInfo.resultDisposition ) ) {
+ m_data.negate( expr.isBinaryExpression() );
+ }
+
+ getResultCapture().assertionRun();
+
+ if(getCurrentContext().getConfig()->includeSuccessfulResults() || m_data.resultType != ResultWas::Ok)
+ {
+ AssertionResult result = build( expr );
+ handleResult( result );
+ }
+ else
+ getResultCapture().assertionPassed();
}
void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) {
m_assertionInfo.resultDisposition = resultDisposition;
- m_stream.oss << Catch::translateActiveException();
+ stream().oss << Catch::translateActiveException();
captureResult( ResultWas::ThrewException );
}
@@ -8876,7 +9177,7 @@ namespace Catch {
assert( !isFalseTest( m_assertionInfo.resultDisposition ) );
AssertionResultData data = m_data;
data.resultType = ResultWas::Ok;
- data.reconstructedExpression = m_assertionInfo.capturedExpression;
+ data.reconstructedExpression = capturedExpressionWithSecondArgument(m_assertionInfo.capturedExpression, m_assertionInfo.secondArg);
std::string actualMessage = Catch::translateActiveException();
if( !matcher.match( actualMessage ) ) {
@@ -8937,18 +9238,21 @@ namespace Catch {
assert( m_data.resultType != ResultWas::Unknown );
AssertionResultData data = m_data;
- // Flip bool results if FalseTest flag is set
- if( isFalseTest( m_assertionInfo.resultDisposition ) ) {
- data.negate( expr.isBinaryExpression() );
- }
-
- data.message = m_stream.oss.str();
+ if(m_usedStream)
+ data.message = m_stream().oss.str();
data.decomposedExpression = &expr; // for lazy reconstruction
return AssertionResult( m_assertionInfo, data );
}
void ResultBuilder::reconstructExpression( std::string& dest ) const {
- dest = m_assertionInfo.capturedExpression;
+ dest = capturedExpressionWithSecondArgument(m_assertionInfo.capturedExpression, m_assertionInfo.secondArg);
+ }
+
+ void ResultBuilder::setExceptionGuard() {
+ m_guardException = true;
+ }
+ void ResultBuilder::unsetExceptionGuard() {
+ m_guardException = false;
}
} // end namespace Catch
@@ -8956,27 +9260,6 @@ namespace Catch {
// #included from: catch_tag_alias_registry.hpp
#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED
-// #included from: catch_tag_alias_registry.h
-#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_H_INCLUDED
-
-#include <map>
-
-namespace Catch {
-
- class TagAliasRegistry : public ITagAliasRegistry {
- public:
- virtual ~TagAliasRegistry();
- virtual Option<TagAlias> find( std::string const& alias ) const;
- virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const;
- void add( char const* alias, char const* tag, SourceLineInfo const& lineInfo );
- static TagAliasRegistry& get();
-
- private:
- std::map<std::string, TagAlias> m_registry;
- };
-
-} // end namespace Catch
-
namespace Catch {
TagAliasRegistry::~TagAliasRegistry() {}
@@ -9004,40 +9287,36 @@ namespace Catch {
return expandedTestSpec;
}
- void TagAliasRegistry::add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) {
+ void TagAliasRegistry::add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) {
if( !startsWith( alias, "[@" ) || !endsWith( alias, ']' ) ) {
std::ostringstream oss;
- oss << "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n" << lineInfo;
+ oss << Colour( Colour::Red )
+ << "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n"
+ << Colour( Colour::FileName )
+ << lineInfo << '\n';
throw std::domain_error( oss.str().c_str() );
}
if( !m_registry.insert( std::make_pair( alias, TagAlias( tag, lineInfo ) ) ).second ) {
std::ostringstream oss;
- oss << "error: tag alias, \"" << alias << "\" already registered.\n"
- << "\tFirst seen at " << find(alias)->lineInfo << '\n'
- << "\tRedefined at " << lineInfo;
+ oss << Colour( Colour::Red )
+ << "error: tag alias, \"" << alias << "\" already registered.\n"
+ << "\tFirst seen at "
+ << Colour( Colour::Red ) << find(alias)->lineInfo << '\n'
+ << Colour( Colour::Red ) << "\tRedefined at "
+ << Colour( Colour::FileName) << lineInfo << '\n';
throw std::domain_error( oss.str().c_str() );
}
}
- TagAliasRegistry& TagAliasRegistry::get() {
- static TagAliasRegistry instance;
- return instance;
+ ITagAliasRegistry::~ITagAliasRegistry() {}
+ ITagAliasRegistry const& ITagAliasRegistry::get() {
+ return getRegistryHub().getTagAliasRegistry();
}
- ITagAliasRegistry::~ITagAliasRegistry() {}
- ITagAliasRegistry const& ITagAliasRegistry::get() { return TagAliasRegistry::get(); }
-
RegistrarForTagAliases::RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) {
- try {
- TagAliasRegistry::get().add( alias, tag, lineInfo );
- }
- catch( std::exception& ex ) {
- Colour colourGuard( Colour::Red );
- Catch::cerr() << ex.what() << std::endl;
- exit(1);
- }
+ getMutableRegistryHub().registerTagAlias( alias, tag, lineInfo );
}
} // end namespace Catch
@@ -9064,7 +9343,7 @@ namespace Matchers {
: std::string();
}
- StringMatcherBase::StringMatcherBase( std::string operation, CasedString const& comparator )
+ StringMatcherBase::StringMatcherBase( std::string const& operation, CasedString const& comparator )
: m_comparator( comparator ),
m_operation( operation ) {
}
@@ -9265,10 +9544,34 @@ Ptr<IStreamingReporter> addReporter( Ptr<IStreamingReporter> const& existingRepo
#define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED
#include <cstring>
+#include <cfloat>
+#include <cstdio>
#include <assert.h>
namespace Catch {
+ namespace {
+ // Because formatting using c++ streams is stateful, drop down to C is required
+ // Alternatively we could use stringstream, but its performance is... not good.
+ std::string getFormattedDuration( double duration ) {
+ // Max exponent + 1 is required to represent the whole part
+ // + 1 for decimal point
+ // + 3 for the 3 decimal places
+ // + 1 for null terminator
+ const size_t maxDoubleSize = DBL_MAX_10_EXP + 1 + 1 + 3 + 1;
+ char buffer[maxDoubleSize];
+
+ // Save previous errno, to prevent sprintf from overwriting it
+ ErrnoGuard guard;
+#ifdef _MSC_VER
+ sprintf_s(buffer, "%.3f", duration);
+#else
+ sprintf(buffer, "%.3f", duration);
+#endif
+ return std::string(buffer);
+ }
+ }
+
struct StreamingReporterBase : SharedImpl<IStreamingReporter> {
StreamingReporterBase( ReporterConfig const& _config )
@@ -9365,7 +9668,8 @@ namespace Catch {
BySectionInfo( SectionInfo const& other ) : m_other( other ) {}
BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {}
bool operator() ( Ptr<SectionNode> const& node ) const {
- return node->stats.sectionInfo.lineInfo == m_other.lineInfo;
+ return ((node->stats.sectionInfo.name == m_other.name) &&
+ (node->stats.sectionInfo.lineInfo == m_other.lineInfo));
}
private:
void operator=( BySectionInfo const& );
@@ -9594,9 +9898,13 @@ namespace Catch {
#define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \
namespace{ Catch::ReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); }
+// Deprecated - use the form without INTERNAL_
#define INTERNAL_CATCH_REGISTER_LISTENER( listenerType ) \
namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; }
+#define CATCH_REGISTER_LISTENER( listenerType ) \
+ namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; }
+
// #included from: ../internal/catch_xmlwriter.hpp
#define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED
@@ -9829,20 +10137,6 @@ namespace Catch {
};
}
-// #included from: catch_reenable_warnings.h
-
-#define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED
-
-#ifdef __clang__
-# ifdef __ICC // icpc defines the __clang__ macro
-# pragma warning(pop)
-# else
-# pragma clang diagnostic pop
-# endif
-#elif defined __GNUC__
-# pragma GCC diagnostic pop
-#endif
-
namespace Catch {
class XmlReporter : public StreamingReporterBase {
@@ -9921,73 +10215,76 @@ namespace Catch {
virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { }
virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE {
- const AssertionResult& assertionResult = assertionStats.assertionResult;
- // Print any info messages in <Info> tags.
- if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) {
+ AssertionResult const& result = assertionStats.assertionResult;
+
+ bool includeResults = m_config->includeSuccessfulResults() || !result.isOk();
+
+ if( includeResults ) {
+ // Print any info messages in <Info> tags.
for( std::vector<MessageInfo>::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end();
- it != itEnd;
- ++it ) {
+ it != itEnd;
+ ++it ) {
if( it->type == ResultWas::Info ) {
m_xml.scopedElement( "Info" )
- .writeText( it->message );
+ .writeText( it->message );
} else if ( it->type == ResultWas::Warning ) {
m_xml.scopedElement( "Warning" )
- .writeText( it->message );
+ .writeText( it->message );
}
}
}
// Drop out if result was successful but we're not printing them.
- if( !m_config->includeSuccessfulResults() && isOk(assertionResult.getResultType()) )
+ if( !includeResults && result.getResultType() != ResultWas::Warning )
return true;
// Print the expression if there is one.
- if( assertionResult.hasExpression() ) {
+ if( result.hasExpression() ) {
m_xml.startElement( "Expression" )
- .writeAttribute( "success", assertionResult.succeeded() )
- .writeAttribute( "type", assertionResult.getTestMacroName() );
+ .writeAttribute( "success", result.succeeded() )
+ .writeAttribute( "type", result.getTestMacroName() );
- writeSourceInfo( assertionResult.getSourceInfo() );
+ writeSourceInfo( result.getSourceInfo() );
m_xml.scopedElement( "Original" )
- .writeText( assertionResult.getExpression() );
+ .writeText( result.getExpression() );
m_xml.scopedElement( "Expanded" )
- .writeText( assertionResult.getExpandedExpression() );
+ .writeText( result.getExpandedExpression() );
}
// And... Print a result applicable to each result type.
- switch( assertionResult.getResultType() ) {
+ switch( result.getResultType() ) {
case ResultWas::ThrewException:
m_xml.startElement( "Exception" );
- writeSourceInfo( assertionResult.getSourceInfo() );
- m_xml.writeText( assertionResult.getMessage() );
+ writeSourceInfo( result.getSourceInfo() );
+ m_xml.writeText( result.getMessage() );
m_xml.endElement();
break;
case ResultWas::FatalErrorCondition:
m_xml.startElement( "FatalErrorCondition" );
- writeSourceInfo( assertionResult.getSourceInfo() );
- m_xml.writeText( assertionResult.getMessage() );
+ writeSourceInfo( result.getSourceInfo() );
+ m_xml.writeText( result.getMessage() );
m_xml.endElement();
break;
case ResultWas::Info:
m_xml.scopedElement( "Info" )
- .writeText( assertionResult.getMessage() );
+ .writeText( result.getMessage() );
break;
case ResultWas::Warning:
// Warning will already have been written
break;
case ResultWas::ExplicitFailure:
m_xml.startElement( "Failure" );
- writeSourceInfo( assertionResult.getSourceInfo() );
- m_xml.writeText( assertionResult.getMessage() );
+ writeSourceInfo( result.getSourceInfo() );
+ m_xml.writeText( result.getMessage() );
m_xml.endElement();
break;
default:
break;
}
- if( assertionResult.hasExpression() )
+ if( result.hasExpression() )
m_xml.endElement();
return true;
@@ -10093,7 +10390,9 @@ namespace Catch {
public:
JunitReporter( ReporterConfig const& _config )
: CumulativeReporterBase( _config ),
- xml( _config.stream() )
+ xml( _config.stream() ),
+ unexpectedExceptions( 0 ),
+ m_okToFail( false )
{
m_reporterPrefs.shouldRedirectStdOut = true;
}
@@ -10119,8 +10418,11 @@ namespace Catch {
CumulativeReporterBase::testGroupStarting( groupInfo );
}
+ virtual void testCaseStarting( TestCaseInfo const& testCaseInfo ) CATCH_OVERRIDE {
+ m_okToFail = testCaseInfo.okToFail();
+ }
virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE {
- if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException )
+ if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException && !m_okToFail )
unexpectedExceptions++;
return CumulativeReporterBase::assertionEnded( assertionStats );
}
@@ -10285,6 +10587,7 @@ namespace Catch {
std::ostringstream stdOutForSuite;
std::ostringstream stdErrForSuite;
unsigned int unexpectedExceptions;
+ bool m_okToFail;
};
INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter )
@@ -10299,25 +10602,6 @@ namespace Catch {
namespace Catch {
- namespace {
- // Because formatting using c++ streams is stateful, drop down to C is required
- // Alternatively we could use stringstream, but its performance is... not good.
- std::string getFormattedDuration( double duration ) {
- // Max exponent + 1 is required to represent the whole part
- // + 1 for decimal point
- // + 3 for the 3 decimal places
- // + 1 for null terminator
- const size_t maxDoubleSize = DBL_MAX_10_EXP + 1 + 1 + 3 + 1;
- char buffer[maxDoubleSize];
-#ifdef _MSC_VER
- sprintf_s(buffer, "%.3f", duration);
-#else
- sprintf(buffer, "%.3f", duration);
-#endif
- return std::string(buffer);
- }
- }
-
struct ConsoleReporter : StreamingReporterBase {
ConsoleReporter( ReporterConfig const& _config )
: StreamingReporterBase( _config ),
@@ -10339,18 +10623,15 @@ namespace Catch {
virtual bool assertionEnded( AssertionStats const& _assertionStats ) CATCH_OVERRIDE {
AssertionResult const& result = _assertionStats.assertionResult;
- bool printInfoMessages = true;
+ bool includeResults = m_config->includeSuccessfulResults() || !result.isOk();
- // Drop out if result was successful and we're not printing those
- if( !m_config->includeSuccessfulResults() && result.isOk() ) {
- if( result.getResultType() != ResultWas::Warning )
- return false;
- printInfoMessages = false;
- }
+ // Drop out if result was successful but we're not printing them.
+ if( !includeResults && result.getResultType() != ResultWas::Warning )
+ return false;
lazyPrint();
- AssertionPrinter printer( stream, _assertionStats, printInfoMessages );
+ AssertionPrinter printer( stream, _assertionStats, includeResults );
printer.print();
stream << std::endl;
return true;
@@ -10440,7 +10721,11 @@ namespace Catch {
case ResultWas::ThrewException:
colour = Colour::Error;
passOrFail = "FAILED";
- messageLabel = "due to unexpected exception with message";
+ messageLabel = "due to unexpected exception with ";
+ if (_stats.infoMessages.size() == 1)
+ messageLabel += "message";
+ if (_stats.infoMessages.size() > 1)
+ messageLabel += "messages";
break;
case ResultWas::FatalErrorCondition:
colour = Colour::Error;
@@ -10556,7 +10841,7 @@ namespace Catch {
stream << '\n' << getLineOfChars<'~'>() << '\n';
Colour colour( Colour::SecondaryText );
stream << currentTestRunInfo->name
- << " is a Catch v" << libraryVersion << " host application.\n"
+ << " is a Catch v" << libraryVersion() << " host application.\n"
<< "Run with -? for options\n\n";
if( m_config->rngSeed() != 0 )
@@ -10769,8 +11054,7 @@ namespace Catch {
stream << "No test cases matched '" << spec << '\'' << std::endl;
}
- virtual void assertionStarting( AssertionInfo const& ) {
- }
+ virtual void assertionStarting( AssertionInfo const& ) {}
virtual bool assertionEnded( AssertionStats const& _assertionStats ) {
AssertionResult const& result = _assertionStats.assertionResult;
@@ -10791,6 +11075,12 @@ namespace Catch {
return true;
}
+ virtual void sectionEnded(SectionStats const& _sectionStats) CATCH_OVERRIDE {
+ if (m_config->showDurations() == ShowDurations::Always) {
+ stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl;
+ }
+ }
+
virtual void testRunEnded( TestRunStats const& _testRunStats ) {
printTotals( _testRunStats.totals );
stream << '\n' << std::endl;
@@ -10896,7 +11186,7 @@ namespace Catch {
stream << result.getSourceInfo() << ':';
}
- void printResultType( Colour::Code colour, std::string passOrFail ) const {
+ void printResultType( Colour::Code colour, std::string const& passOrFail ) const {
if( !passOrFail.empty() ) {
{
Colour colourGuard( colour );
@@ -10906,7 +11196,7 @@ namespace Catch {
}
}
- void printIssue( std::string issue ) const {
+ void printIssue( std::string const& issue ) const {
stream << ' ' << issue;
}
@@ -11077,6 +11367,7 @@ namespace Catch {
TestSpec::NamePattern::~NamePattern() {}
TestSpec::TagPattern::~TagPattern() {}
TestSpec::ExcludedPattern::~ExcludedPattern() {}
+ Matchers::Impl::MatcherUntypedBase::~MatcherUntypedBase() {}
void Config::dummy() {}
@@ -11100,9 +11391,15 @@ namespace Catch {
#ifndef __OBJC__
+#if defined(WIN32) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN)
+// Standard C/C++ Win32 Unicode wmain entry point
+extern "C" int wmain (int argc, wchar_t * argv[], wchar_t * []) {
+#else
// Standard C/C++ main entry point
int main (int argc, char * argv[]) {
- int result = Catch::Session().run( argc, argv );
+#endif
+
+ int result = Catch::Session().run( argc, argv );
return ( result < 0xff ? result : 0xff );
}
@@ -11137,33 +11434,43 @@ int main (int argc, char * const argv[]) {
// If this config identifier is defined then all CATCH macros are prefixed with CATCH_
#ifdef CATCH_CONFIG_PREFIX_ALL
-#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE" )
-#define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "CATCH_REQUIRE_FALSE" )
+#if defined(CATCH_CONFIG_FAST_COMPILE)
+#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, expr )
+#define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr )
+#else
+#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, expr )
+#define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr )
+#endif
-#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "", "CATCH_REQUIRE_THROWS" )
-#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS_AS" )
-#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, matcher, "CATCH_REQUIRE_THROWS_WITH" )
-#define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_NOTHROW" )
+#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, "", expr )
+#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr )
+#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr )
+#define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "CATCH_REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, expr )
-#define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK" )
-#define CATCH_CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CATCH_CHECK_FALSE" )
-#define CATCH_CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_IF" )
-#define CATCH_CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_ELSE" )
-#define CATCH_CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CATCH_CHECK_NOFAIL" )
+#define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( "CATCH_CHECK", Catch::ResultDisposition::ContinueOnFailure, expr )
+#define CATCH_CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( "CATCH_CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, expr )
+#define CATCH_CHECKED_IF( expr ) INTERNAL_CATCH_IF( "CATCH_CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, expr )
+#define CATCH_CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( "CATCH_CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, expr )
+#define CATCH_CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( "CATCH_CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, expr )
-#define CATCH_CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "", "CATCH_CHECK_THROWS" )
-#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS_AS" )
-#define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CATCH_CHECK_THROWS_WITH" )
-#define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_NOTHROW" )
+#define CATCH_CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, "", expr )
+#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr )
+#define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr )
+#define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "CATCH_CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, expr )
-#define CATCH_CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THAT" )
-#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THAT" )
+#define CATCH_CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg )
-#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" )
-#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "CATCH_WARN", msg )
-#define CATCH_SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" )
-#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" )
-#define CATCH_SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" )
+#if defined(CATCH_CONFIG_FAST_COMPILE)
+#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT_NO_TRY( "CATCH_REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg )
+#else
+#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg )
+#endif
+
+#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg )
+#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
+#define CATCH_SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg )
+#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CATCH_CAPTURE", #msg " := " << Catch::toString(msg) )
+#define CATCH_SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CATCH_CAPTURE", #msg " := " << Catch::toString(msg) )
#ifdef CATCH_CONFIG_VARIADIC_MACROS
#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
@@ -11171,16 +11478,18 @@ int main (int argc, char * const argv[]) {
#define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
#define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
#define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
- #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", __VA_ARGS__ )
- #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", __VA_ARGS__ )
+ #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ )
+ #define CATCH_FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+ #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
#else
#define CATCH_TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description )
#define CATCH_TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description )
#define CATCH_METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description )
#define CATCH_REGISTER_TEST_CASE( function, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( function, name, description )
#define CATCH_SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description )
- #define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", msg )
- #define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", msg )
+ #define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, msg )
+ #define CATCH_FAIL_CHECK( msg ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, msg )
+ #define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, msg )
#endif
#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" )
@@ -11206,50 +11515,63 @@ int main (int argc, char * const argv[]) {
// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required
#else
-#define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" )
-#define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "REQUIRE_FALSE" )
+#if defined(CATCH_CONFIG_FAST_COMPILE)
+#define REQUIRE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "REQUIRE", Catch::ResultDisposition::Normal, expr )
+#define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr )
+
+#else
+#define REQUIRE( expr ) INTERNAL_CATCH_TEST( "REQUIRE", Catch::ResultDisposition::Normal, expr )
+#define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr )
+#endif
+
+#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS", Catch::ResultDisposition::Normal, "", expr )
+#define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr )
+#define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr )
+#define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, expr )
-#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "", "REQUIRE_THROWS" )
-#define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "REQUIRE_THROWS_AS" )
-#define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, matcher, "REQUIRE_THROWS_WITH" )
-#define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "REQUIRE_NOTHROW" )
+#define CHECK( expr ) INTERNAL_CATCH_TEST( "CHECK", Catch::ResultDisposition::ContinueOnFailure, expr )
+#define CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( "CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, expr )
+#define CHECKED_IF( expr ) INTERNAL_CATCH_IF( "CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, expr )
+#define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( "CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, expr )
+#define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( "CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, expr )
-#define CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK" )
-#define CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CHECK_FALSE" )
-#define CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_IF" )
-#define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_ELSE" )
-#define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CHECK_NOFAIL" )
+#define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( "CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, "", expr )
+#define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr )
+#define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr )
+#define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, expr )
-#define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "", "CHECK_THROWS" )
-#define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS_AS" )
-#define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CHECK_THROWS_WITH" )
-#define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_NOTHROW" )
+#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg )
-#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THAT" )
-#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "REQUIRE_THAT" )
+#if defined(CATCH_CONFIG_FAST_COMPILE)
+#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT_NO_TRY( "REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg )
+#else
+#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg )
+#endif
-#define INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" )
-#define WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "WARN", msg )
-#define SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" )
-#define CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" )
-#define SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" )
+#define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg )
+#define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
+#define SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg )
+#define CAPTURE( msg ) INTERNAL_CATCH_INFO( "CAPTURE", #msg " := " << Catch::toString(msg) )
+#define SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CAPTURE", #msg " := " << Catch::toString(msg) )
#ifdef CATCH_CONFIG_VARIADIC_MACROS
- #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
- #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
- #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
- #define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
- #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
- #define FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", __VA_ARGS__ )
- #define SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", __VA_ARGS__ )
+#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
+#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
+#define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
+#define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
+#define FAIL( ... ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ )
+#define FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
+#define SUCCEED( ... ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
#else
- #define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description )
+#define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description )
#define TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description )
#define METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description )
#define REGISTER_TEST_CASE( method, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( method, name, description )
#define SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description )
- #define FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", msg )
- #define SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", msg )
+ #define FAIL( msg ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, msg )
+ #define FAIL_CHECK( msg ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, msg )
+ #define SUCCEED( msg ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, msg )
#endif
#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" )
@@ -11278,5 +11600,19 @@ int main (int argc, char * const argv[]) {
using Catch::Detail::Approx;
+// #included from: internal/catch_reenable_warnings.h
+
+#define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED
+
+#ifdef __clang__
+# ifdef __ICC // icpc defines the __clang__ macro
+# pragma warning(pop)
+# else
+# pragma clang diagnostic pop
+# endif
+#elif defined __GNUC__
+# pragma GCC diagnostic pop
+#endif
+
#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
diff --git a/test/t/area/test_node_ref_segment.cpp b/test/t/area/test_node_ref_segment.cpp
index 45e6f9d..3b47376 100644
--- a/test/t/area/test_node_ref_segment.cpp
+++ b/test/t/area/test_node_ref_segment.cpp
@@ -135,11 +135,11 @@ TEST_CASE("Ordering of NodeRefSegements") {
REQUIRE(node_ref1 < node_ref3);
REQUIRE(node_ref1 >= node_ref1);
- REQUIRE( osmium::location_less()(node_ref1, node_ref2));
- REQUIRE(!osmium::location_less()(node_ref2, node_ref3));
- REQUIRE( osmium::location_less()(node_ref1, node_ref3));
- REQUIRE( osmium::location_less()(node_ref3, node_ref4));
- REQUIRE(!osmium::location_less()(node_ref1, node_ref1));
+ REQUIRE( osmium::location_less()(node_ref1, node_ref2));
+ REQUIRE_FALSE(osmium::location_less()(node_ref2, node_ref3));
+ REQUIRE( osmium::location_less()(node_ref1, node_ref3));
+ REQUIRE( osmium::location_less()(node_ref3, node_ref4));
+ REQUIRE_FALSE(osmium::location_less()(node_ref1, node_ref1));
}
TEST_CASE("More ordering of NodeRefSegments") {
diff --git a/test/t/geom/test_geojson.cpp b/test/t/geom/test_geojson.cpp
index 5724936..400bb50 100644
--- a/test/t/geom/test_geojson.cpp
+++ b/test/t/geom/test_geojson.cpp
@@ -14,7 +14,7 @@ TEST_CASE("GeoJSON point geometry") {
}
SECTION("empty_point") {
- REQUIRE_THROWS_AS(factory.create_point(osmium::Location{}), osmium::invalid_location);
+ REQUIRE_THROWS_AS(factory.create_point(osmium::Location{}), const osmium::invalid_location&);
}
}
@@ -50,17 +50,17 @@ TEST_CASE("GeoJSON linestring geometry") {
SECTION("empty_linestring") {
const auto& wnl = create_test_wnl_empty(buffer);
- REQUIRE_THROWS_AS(factory.create_linestring(wnl), osmium::geometry_error);
- REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward), osmium::geometry_error);
- REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::all), osmium::geometry_error);
- REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward), osmium::geometry_error);
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl), const osmium::geometry_error&);
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward), const osmium::geometry_error&);
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::all), const osmium::geometry_error&);
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward), const osmium::geometry_error&);
}
SECTION("linestring with two same locations") {
const auto& wnl = create_test_wnl_same_location(buffer);
- REQUIRE_THROWS_AS(factory.create_linestring(wnl), osmium::geometry_error);
- REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward), osmium::geometry_error);
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl), const osmium::geometry_error&);
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward), const osmium::geometry_error&);
{
const std::string json{factory.create_linestring(wnl, osmium::geom::use_nodes::all)};
@@ -75,7 +75,7 @@ TEST_CASE("GeoJSON linestring geometry") {
SECTION("linestring with undefined location") {
const auto& wnl = create_test_wnl_undefined_location(buffer);
- REQUIRE_THROWS_AS(factory.create_linestring(wnl), osmium::invalid_location);
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl), const osmium::invalid_location&);
}
}
@@ -87,7 +87,7 @@ TEST_CASE("GeoJSON area geometry") {
SECTION("area_1outer_0inner") {
const osmium::Area& area = create_test_area_1outer_0inner(buffer);
- REQUIRE(!area.is_multipolygon());
+ REQUIRE_FALSE(area.is_multipolygon());
REQUIRE(std::distance(area.cbegin(), area.cend()) == 2);
REQUIRE(area.subitems<osmium::OuterRing>().size() == area.num_rings().first);
@@ -98,7 +98,7 @@ TEST_CASE("GeoJSON area geometry") {
SECTION("area_1outer_1inner") {
const osmium::Area& area = create_test_area_1outer_1inner(buffer);
- REQUIRE(!area.is_multipolygon());
+ REQUIRE_FALSE(area.is_multipolygon());
REQUIRE(std::distance(area.cbegin(), area.cend()) == 3);
REQUIRE(area.subitems<osmium::OuterRing>().size() == area.num_rings().first);
REQUIRE(area.subitems<osmium::InnerRing>().size() == area.num_rings().second);
diff --git a/test/t/geom/test_geos.cpp b/test/t/geom/test_geos.cpp
index 8e7fac4..f138616 100644
--- a/test/t/geom/test_geos.cpp
+++ b/test/t/geom/test_geos.cpp
@@ -41,7 +41,7 @@ TEST_CASE("GEOS geometry factory - create point with externally created GEOS fac
TEST_CASE("GEOS geometry factory - can not create from invalid location") {
osmium::geom::GEOSFactory<> factory;
- REQUIRE_THROWS_AS(factory.create_point(osmium::Location{}), osmium::invalid_location);
+ REQUIRE_THROWS_AS(factory.create_point(osmium::Location{}), const osmium::invalid_location&);
}
TEST_CASE("GEOS geometry factory - create linestring") {
diff --git a/test/t/geom/test_mercator.cpp b/test/t/geom/test_mercator.cpp
index cc16e55..4f8bf97 100644
--- a/test/t/geom/test_mercator.cpp
+++ b/test/t/geom/test_mercator.cpp
@@ -2,36 +2,33 @@
#include <osmium/geom/mercator_projection.hpp>
-TEST_CASE("Mercator") {
-
- SECTION("mercator_projection") {
- osmium::geom::MercatorProjection projection;
- REQUIRE(3857 == projection.epsg());
- REQUIRE("+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs" == projection.proj_string());
- }
-
- SECTION("low_level_mercator_functions") {
- osmium::geom::Coordinates c1(17.839, -3.249);
- osmium::geom::Coordinates r1 = osmium::geom::mercator_to_lonlat(osmium::geom::lonlat_to_mercator(c1));
- REQUIRE(r1.x == Approx(c1.x).epsilon(0.000001));
- REQUIRE(r1.y == Approx(c1.y).epsilon(0.000001));
-
- osmium::geom::Coordinates c2(-89.2, 15.915);
- osmium::geom::Coordinates r2 = osmium::geom::mercator_to_lonlat(osmium::geom::lonlat_to_mercator(c2));
- REQUIRE(r2.x == Approx(c2.x).epsilon(0.000001));
- REQUIRE(r2.y == Approx(c2.y).epsilon(0.000001));
-
- osmium::geom::Coordinates c3(180.0, 85.0);
- osmium::geom::Coordinates r3 = osmium::geom::mercator_to_lonlat(osmium::geom::lonlat_to_mercator(c3));
- REQUIRE(r3.x == Approx(c3.x).epsilon(0.000001));
- REQUIRE(r3.y == Approx(c3.y).epsilon(0.000001));
- }
+TEST_CASE("Mercator projection") {
+ const osmium::geom::MercatorProjection projection;
+ REQUIRE(3857 == projection.epsg());
+ REQUIRE("+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs" == projection.proj_string());
+}
- SECTION("mercator_bounds") {
- osmium::Location mmax(180.0, osmium::geom::MERCATOR_MAX_LAT);
- osmium::geom::Coordinates c = osmium::geom::lonlat_to_mercator(mmax);
- REQUIRE(c.x == Approx(c.y).epsilon(0.001));
- REQUIRE(osmium::geom::detail::y_to_lat(osmium::geom::detail::lon_to_x(180.0)) == Approx(osmium::geom::MERCATOR_MAX_LAT).epsilon(0.0000001));
- }
+TEST_CASE("Low level mercator functions") {
+ const osmium::geom::Coordinates c1{17.839, -3.249};
+ const osmium::geom::Coordinates r1 = osmium::geom::mercator_to_lonlat(osmium::geom::lonlat_to_mercator(c1));
+ REQUIRE(r1.x == Approx(c1.x).epsilon(0.000001));
+ REQUIRE(r1.y == Approx(c1.y).epsilon(0.000001));
+
+ const osmium::geom::Coordinates c2{-89.2, 15.915};
+ const osmium::geom::Coordinates r2 = osmium::geom::mercator_to_lonlat(osmium::geom::lonlat_to_mercator(c2));
+ REQUIRE(r2.x == Approx(c2.x).epsilon(0.000001));
+ REQUIRE(r2.y == Approx(c2.y).epsilon(0.000001));
+
+ const osmium::geom::Coordinates c3{180.0, 85.0};
+ const osmium::geom::Coordinates r3 = osmium::geom::mercator_to_lonlat(osmium::geom::lonlat_to_mercator(c3));
+ REQUIRE(r3.x == Approx(c3.x).epsilon(0.000001));
+ REQUIRE(r3.y == Approx(c3.y).epsilon(0.000001));
+}
+TEST_CASE("Mercator bounds") {
+ const osmium::Location mmax{180.0, osmium::geom::MERCATOR_MAX_LAT};
+ const osmium::geom::Coordinates c = osmium::geom::lonlat_to_mercator(mmax);
+ REQUIRE(c.x == Approx(c.y).epsilon(0.001));
+ REQUIRE(osmium::geom::detail::y_to_lat(osmium::geom::detail::lon_to_x(180.0)) == Approx(osmium::geom::MERCATOR_MAX_LAT).epsilon(0.0000001));
}
+
diff --git a/test/t/geom/test_ogr.cpp b/test/t/geom/test_ogr.cpp
index 5e03082..39f2b5c 100644
--- a/test/t/geom/test_ogr.cpp
+++ b/test/t/geom/test_ogr.cpp
@@ -15,7 +15,7 @@ TEST_CASE("OGR point geometry") {
}
SECTION("empty_point") {
- REQUIRE_THROWS_AS(factory.create_point(osmium::Location()), osmium::invalid_location);
+ REQUIRE_THROWS_AS(factory.create_point(osmium::Location()), const osmium::invalid_location&);
}
}
diff --git a/test/t/geom/test_projection.cpp b/test/t/geom/test_projection.cpp
index df5c095..bff568b 100644
--- a/test/t/geom/test_projection.cpp
+++ b/test/t/geom/test_projection.cpp
@@ -35,11 +35,11 @@ TEST_CASE("Projection 4326 from init string") {
}
TEST_CASE("Creating projection from unknown init string") {
- REQUIRE_THROWS_AS(osmium::geom::Projection{"abc"}, osmium::projection_error);
+ REQUIRE_THROWS_AS(osmium::geom::Projection{"abc"}, const osmium::projection_error&);
}
TEST_CASE("Creating projection from unknown EPSG code") {
- REQUIRE_THROWS_AS(osmium::geom::Projection{9999999}, osmium::projection_error);
+ REQUIRE_THROWS_AS(osmium::geom::Projection{9999999}, const osmium::projection_error&);
}
TEST_CASE("Projection 3857") {
diff --git a/test/t/geom/test_tile.cpp b/test/t/geom/test_tile.cpp
index 4218797..ca289f7 100644
--- a/test/t/geom/test_tile.cpp
+++ b/test/t/geom/test_tile.cpp
@@ -52,7 +52,7 @@ TEST_CASE("Tile from x0.0 y0.0 at zoom 4") {
osmium::geom::Tile t{4, l};
- auto n = 1 << (4-1);
+ const auto n = 1 << (4-1);
REQUIRE(t.x == n);
REQUIRE(t.y == n);
REQUIRE(t.z == 4);
@@ -115,3 +115,29 @@ TEST_CASE("Check a random list of tiles") {
}
}
+TEST_CASE("Invalid tiles") {
+ osmium::geom::Tile tile{0, 0, 0};
+
+ REQUIRE(tile.valid());
+
+ SECTION("Zoom level out of bounds") {
+ tile.z = 100;
+ }
+ SECTION("x out of bounds") {
+ tile.x = 1;
+ }
+ SECTION("y out of bounds") {
+ tile.y = 1;
+ }
+ SECTION("x out of bounds") {
+ tile.z = 4;
+ tile.x = 100;
+ }
+ SECTION("y out of bounds") {
+ tile.z = 4;
+ tile.y = 100;
+ }
+
+ REQUIRE_FALSE(tile.valid());
+}
+
diff --git a/test/t/geom/test_wkb.cpp b/test/t/geom/test_wkb.cpp
index 29b6d6b..a4f2d99 100644
--- a/test/t/geom/test_wkb.cpp
+++ b/test/t/geom/test_wkb.cpp
@@ -87,11 +87,11 @@ TEST_CASE("WKB geometry factory (byte-order-dependant)") {
const auto& wnl = create_test_wnl_same_location(buffer);
SECTION("unique forwards (default)") {
- REQUIRE_THROWS_AS(factory.create_linestring(wnl), osmium::geometry_error);
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl), const osmium::geometry_error&);
}
SECTION("unique backwards") {
- REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward), osmium::geometry_error);
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward), const osmium::geometry_error&);
}
SECTION("all forwards") {
@@ -110,7 +110,7 @@ TEST_CASE("WKB geometry factory (byte-order-dependant)") {
const auto& wnl = create_test_wnl_undefined_location(buffer);
- REQUIRE_THROWS_AS(factory.create_linestring(wnl), osmium::invalid_location);
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl), const osmium::invalid_location&);
}
}
@@ -122,17 +122,17 @@ TEST_CASE("WKB geometry (byte-order-independent)") {
osmium::geom::WKBFactory<> factory{osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex};
SECTION("empty point") {
- REQUIRE_THROWS_AS(factory.create_point(osmium::Location{}), osmium::invalid_location);
+ REQUIRE_THROWS_AS(factory.create_point(osmium::Location{}), const osmium::invalid_location&);
}
SECTION("empty linestring") {
osmium::memory::Buffer buffer{10000};
const auto& wnl = create_test_wnl_empty(buffer);
- REQUIRE_THROWS_AS(factory.create_linestring(wnl), osmium::geometry_error);
- REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward), osmium::geometry_error);
- REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::all), osmium::geometry_error);
- REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward), osmium::geometry_error);
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl), const osmium::geometry_error&);
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward), const osmium::geometry_error&);
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::all), const osmium::geometry_error&);
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward), const osmium::geometry_error&);
}
}
diff --git a/test/t/geom/test_wkt.cpp b/test/t/geom/test_wkt.cpp
index f6913c4..7f33868 100644
--- a/test/t/geom/test_wkt.cpp
+++ b/test/t/geom/test_wkt.cpp
@@ -7,29 +7,25 @@
#include "wnl_helper.hpp"
TEST_CASE("WKT geometry for point") {
+ const osmium::geom::WKTFactory<> factory;
+ const std::string wkt{factory.create_point(osmium::Location{3.2, 4.2})};
+ REQUIRE(wkt == "POINT(3.2 4.2)");
+}
- osmium::geom::WKTFactory<> factory;
-
- SECTION("point") {
- const std::string wkt{factory.create_point(osmium::Location{3.2, 4.2})};
- REQUIRE(wkt == "POINT(3.2 4.2)");
- }
-
- SECTION("empty point") {
- REQUIRE_THROWS_AS(factory.create_point(osmium::Location()), osmium::invalid_location);
- }
-
+TEST_CASE("WKT geometry for empty point") {
+ const osmium::geom::WKTFactory<> factory;
+ REQUIRE_THROWS_AS(factory.create_point(osmium::Location()), const osmium::invalid_location&);
}
TEST_CASE("WKT geometry for point in ekwt") {
- osmium::geom::WKTFactory<> factory(7, osmium::geom::wkt_type::ewkt);
+ const osmium::geom::WKTFactory<> factory{7, osmium::geom::wkt_type::ewkt};
const std::string wkt{factory.create_point(osmium::Location{3.2, 4.2})};
REQUIRE(wkt == "SRID=4326;POINT(3.2 4.2)");
}
TEST_CASE("WKT geometry for point in ekwt in web mercator") {
- osmium::geom::WKTFactory<osmium::geom::MercatorProjection> factory(2, osmium::geom::wkt_type::ewkt);
+ const osmium::geom::WKTFactory<osmium::geom::MercatorProjection> factory{2, osmium::geom::wkt_type::ewkt};
const std::string wkt{factory.create_point(osmium::Location{3.2, 4.2})};
REQUIRE(wkt == "SRID=3857;POINT(356222.37 467961.14)");
@@ -67,17 +63,17 @@ TEST_CASE("WKT geometry factory") {
SECTION("empty linestring") {
const auto& wnl = create_test_wnl_empty(buffer);
- REQUIRE_THROWS_AS(factory.create_linestring(wnl), osmium::geometry_error);
- REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward), osmium::geometry_error);
- REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::all), osmium::geometry_error);
- REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward), osmium::geometry_error);
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl), const osmium::geometry_error&);
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward), const osmium::geometry_error&);
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::all), const osmium::geometry_error&);
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward), const osmium::geometry_error&);
}
SECTION("linestring with two same locations") {
const auto& wnl = create_test_wnl_same_location(buffer);
SECTION("unique forwards") {
- REQUIRE_THROWS_AS(factory.create_linestring(wnl), osmium::geometry_error);
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl), const osmium::geometry_error&);
try {
factory.create_linestring(wnl);
@@ -88,7 +84,7 @@ TEST_CASE("WKT geometry factory") {
}
SECTION("unique backwards") {
- REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward), osmium::geometry_error);
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward), const osmium::geometry_error&);
}
SECTION("all forwards") {
@@ -105,7 +101,7 @@ TEST_CASE("WKT geometry factory") {
SECTION("linestring with undefined location") {
const auto& wnl = create_test_wnl_undefined_location(buffer);
- REQUIRE_THROWS_AS(factory.create_linestring(wnl), osmium::invalid_location);
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl), const osmium::invalid_location&);
}
SECTION("area with one outer and no inner rings") {
diff --git a/test/t/handler/test_check_order_handler.cpp b/test/t/handler/test_check_order_handler.cpp
new file mode 100644
index 0000000..e6b1600
--- /dev/null
+++ b/test/t/handler/test_check_order_handler.cpp
@@ -0,0 +1,128 @@
+#include "catch.hpp"
+
+#include <osmium/handler/check_order.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/opl.hpp>
+#include <osmium/visitor.hpp>
+
+TEST_CASE("CheckOrder handler if everything is in order") {
+ osmium::memory::Buffer buffer{1024};
+
+ REQUIRE(osmium::opl_parse("n-126", buffer));
+ REQUIRE(osmium::opl_parse("n123", buffer));
+ REQUIRE(osmium::opl_parse("n124", buffer));
+ REQUIRE(osmium::opl_parse("n128", buffer));
+ REQUIRE(osmium::opl_parse("w-100", buffer));
+ REQUIRE(osmium::opl_parse("w100", buffer));
+ REQUIRE(osmium::opl_parse("w102", buffer));
+ REQUIRE(osmium::opl_parse("r-200", buffer));
+ REQUIRE(osmium::opl_parse("r100", buffer));
+
+ osmium::handler::CheckOrder handler;
+ osmium::apply(buffer, handler);
+ REQUIRE(handler.max_node_id() == 128);
+ REQUIRE(handler.max_way_id() == 102);
+ REQUIRE(handler.max_relation_id() == 100);
+}
+
+TEST_CASE("CheckOrder handler: Nodes must be in order") {
+ osmium::memory::Buffer buffer{1024};
+
+ REQUIRE(osmium::opl_parse("n3", buffer));
+
+ SECTION("Positive ID") {
+ REQUIRE(osmium::opl_parse("n2", buffer));
+ }
+ SECTION("Negative ID") {
+ REQUIRE(osmium::opl_parse("n-2", buffer));
+ }
+
+ osmium::handler::CheckOrder handler;
+ REQUIRE_THROWS_AS(osmium::apply(buffer, handler), const osmium::out_of_order_error&);
+}
+
+TEST_CASE("CheckOrder handler: Ways must be in order") {
+ osmium::memory::Buffer buffer{1024};
+
+ REQUIRE(osmium::opl_parse("w3", buffer));
+ SECTION("Positive ID") {
+ REQUIRE(osmium::opl_parse("w2", buffer));
+ }
+ SECTION("Negative ID") {
+ REQUIRE(osmium::opl_parse("w-2", buffer));
+ }
+
+ osmium::handler::CheckOrder handler;
+ REQUIRE_THROWS_AS(osmium::apply(buffer, handler), const osmium::out_of_order_error&);
+}
+
+TEST_CASE("CheckOrder handler: Relations must be in order") {
+ osmium::memory::Buffer buffer{1024};
+
+ REQUIRE(osmium::opl_parse("r3", buffer));
+ SECTION("Positive ID") {
+ REQUIRE(osmium::opl_parse("r2", buffer));
+ }
+ SECTION("Negative ID") {
+ REQUIRE(osmium::opl_parse("r-2", buffer));
+ }
+
+ osmium::handler::CheckOrder handler;
+ REQUIRE_THROWS_AS(osmium::apply(buffer, handler), const osmium::out_of_order_error&);
+}
+
+TEST_CASE("CheckOrder handler: Same id twice is not allowed") {
+ osmium::memory::Buffer buffer{1024};
+
+ REQUIRE(osmium::opl_parse("n3", buffer));
+ REQUIRE(osmium::opl_parse("n3", buffer));
+
+ osmium::handler::CheckOrder handler;
+ REQUIRE_THROWS_AS(osmium::apply(buffer, handler), const osmium::out_of_order_error&);
+}
+
+TEST_CASE("CheckOrder handler: Nodes after ways") {
+ osmium::memory::Buffer buffer{1024};
+
+ REQUIRE(osmium::opl_parse("w50", buffer));
+ SECTION("Positive ID") {
+ REQUIRE(osmium::opl_parse("n30", buffer));
+ }
+ SECTION("Negative ID") {
+ REQUIRE(osmium::opl_parse("n-30", buffer));
+ }
+
+ osmium::handler::CheckOrder handler;
+ REQUIRE_THROWS_AS(osmium::apply(buffer, handler), const osmium::out_of_order_error&);
+}
+
+TEST_CASE("CheckOrder handler: Nodes after relations") {
+ osmium::memory::Buffer buffer{1024};
+
+ REQUIRE(osmium::opl_parse("r50", buffer));
+ SECTION("Positive ID") {
+ REQUIRE(osmium::opl_parse("n30", buffer));
+ }
+ SECTION("Negative ID") {
+ REQUIRE(osmium::opl_parse("n-30", buffer));
+ }
+
+ osmium::handler::CheckOrder handler;
+ REQUIRE_THROWS_AS(osmium::apply(buffer, handler), const osmium::out_of_order_error&);
+}
+
+TEST_CASE("CheckOrder handler: Ways after relations") {
+ osmium::memory::Buffer buffer{1024};
+
+ REQUIRE(osmium::opl_parse("r50", buffer));
+ SECTION("Positive ID") {
+ REQUIRE(osmium::opl_parse("w30", buffer));
+ }
+ SECTION("Negative ID") {
+ REQUIRE(osmium::opl_parse("w-30", buffer));
+ }
+
+ osmium::handler::CheckOrder handler;
+ REQUIRE_THROWS_AS(osmium::apply(buffer, handler), const osmium::out_of_order_error&);
+}
+
diff --git a/test/t/handler/test_dynamic_handler.cpp b/test/t/handler/test_dynamic_handler.cpp
new file mode 100644
index 0000000..7b20f12
--- /dev/null
+++ b/test/t/handler/test_dynamic_handler.cpp
@@ -0,0 +1,116 @@
+#include "catch.hpp"
+
+#include <osmium/dynamic_handler.hpp>
+#include <osmium/builder/attr.hpp>
+#include <osmium/visitor.hpp>
+
+struct Handler1 : public osmium::handler::Handler {
+
+ int& count;
+
+ explicit Handler1(int& c) :
+ count(c) {
+ }
+
+ void node(const osmium::Node&) noexcept {
+ ++count;
+ }
+
+ void way(const osmium::Way&) noexcept {
+ ++count;
+ }
+
+ void relation(const osmium::Relation&) noexcept {
+ ++count;
+ }
+
+ void area(const osmium::Area&) noexcept {
+ ++count;
+ }
+
+ void changeset(const osmium::Changeset&) noexcept {
+ ++count;
+ }
+
+ void flush() noexcept {
+ ++count;
+ }
+
+};
+
+struct Handler2 : public osmium::handler::Handler {
+
+ int& count;
+
+ explicit Handler2(int& c) :
+ count(c) {
+ }
+
+ void node(const osmium::Node&) noexcept {
+ count += 2;
+ }
+
+ void way(const osmium::Way&) noexcept {
+ count += 2;
+ }
+
+ void relation(const osmium::Relation&) noexcept {
+ count += 2;
+ }
+
+ void area(const osmium::Area&) noexcept {
+ count += 2;
+ }
+
+ void changeset(const osmium::Changeset&) noexcept {
+ count += 2;
+ }
+
+};
+
+osmium::memory::Buffer fill_buffer() {
+ using namespace osmium::builder::attr;
+ osmium::memory::Buffer buffer{1024 * 1024, osmium::memory::Buffer::auto_grow::yes};
+
+ osmium::builder::add_node(buffer, _id(1));
+ osmium::builder::add_way(buffer, _id(2));
+ osmium::builder::add_relation(buffer, _id(3));
+ osmium::builder::add_area(buffer, _id(4));
+ osmium::builder::add_changeset(buffer, _cid(5));
+
+ return buffer;
+}
+
+TEST_CASE("Base test: static handler") {
+ const auto buffer = fill_buffer();
+
+ int count = 0;
+ Handler1 h1{count};
+ osmium::apply(buffer, h1);
+ REQUIRE(count == 6);
+
+ count = 0;
+ Handler2 h2{count};
+ osmium::apply(buffer, h2);
+ REQUIRE(count == 10);
+}
+
+TEST_CASE("Dynamic handler") {
+ const auto buffer = fill_buffer();
+
+ osmium::handler::DynamicHandler handler;
+ int count = 0;
+
+ osmium::apply(buffer, handler);
+ REQUIRE(count == 0);
+
+ handler.set<Handler1>(count);
+ osmium::apply(buffer, handler);
+ REQUIRE(count == 6);
+
+ count = 0;
+ handler.set<Handler2>(count);
+ osmium::apply(buffer, handler);
+ REQUIRE(count == 10);
+}
+
diff --git a/test/t/index/test_file_based_index.cpp b/test/t/index/test_file_based_index.cpp
index 42cf574..278f43f 100644
--- a/test/t/index/test_file_based_index.cpp
+++ b/test/t/index/test_file_based_index.cpp
@@ -13,7 +13,7 @@
TEST_CASE("File based index") {
- int fd = osmium::detail::create_tmp_file();
+ const int fd = osmium::detail::create_tmp_file();
REQUIRE(osmium::util::file_size(fd) == 0);
@@ -27,17 +27,17 @@ TEST_CASE("File based index") {
constexpr const size_t S = sizeof(index_type::element_type);
{
- index_type index(fd);
+ index_type index{fd};
REQUIRE(index.size() == 0);
- REQUIRE_THROWS_AS(index.get( 0), osmium::not_found);
- REQUIRE_THROWS_AS(index.get( 1), osmium::not_found);
- REQUIRE_THROWS_AS(index.get( 3), osmium::not_found);
- REQUIRE_THROWS_AS(index.get( 5), osmium::not_found);
- REQUIRE_THROWS_AS(index.get( 6), osmium::not_found);
- REQUIRE_THROWS_AS(index.get( 7), osmium::not_found);
- REQUIRE_THROWS_AS(index.get(100), osmium::not_found);
+ REQUIRE_THROWS_AS(index.get( 0), const osmium::not_found&);
+ REQUIRE_THROWS_AS(index.get( 1), const osmium::not_found&);
+ REQUIRE_THROWS_AS(index.get( 3), const osmium::not_found&);
+ REQUIRE_THROWS_AS(index.get( 5), const osmium::not_found&);
+ REQUIRE_THROWS_AS(index.get( 6), const osmium::not_found&);
+ REQUIRE_THROWS_AS(index.get( 7), const osmium::not_found&);
+ REQUIRE_THROWS_AS(index.get(100), const osmium::not_found&);
index.set(id1, loc1);
REQUIRE(index.size() == 7);
@@ -50,11 +50,11 @@ TEST_CASE("File based index") {
REQUIRE(loc1 == index.get(id1));
REQUIRE(loc2 == index.get(id2));
- REQUIRE_THROWS_AS(index.get( 0), osmium::not_found);
- REQUIRE_THROWS_AS(index.get( 1), osmium::not_found);
- REQUIRE_THROWS_AS(index.get( 5), osmium::not_found);
- REQUIRE_THROWS_AS(index.get( 7), osmium::not_found);
- REQUIRE_THROWS_AS(index.get(100), osmium::not_found);
+ REQUIRE_THROWS_AS(index.get( 0), const osmium::not_found&);
+ REQUIRE_THROWS_AS(index.get( 1), const osmium::not_found&);
+ REQUIRE_THROWS_AS(index.get( 5), const osmium::not_found&);
+ REQUIRE_THROWS_AS(index.get( 7), const osmium::not_found&);
+ REQUIRE_THROWS_AS(index.get(100), const osmium::not_found&);
REQUIRE(index.size() == 7);
REQUIRE(std::distance(index.cbegin(), index.cend()) == 7);
@@ -63,7 +63,7 @@ TEST_CASE("File based index") {
}
{
- index_type index(fd);
+ index_type index{fd};
REQUIRE(osmium::util::file_size(fd) >= (6 * S));
REQUIRE(index.size() == 7);
@@ -71,11 +71,11 @@ TEST_CASE("File based index") {
REQUIRE(loc1 == index.get(id1));
REQUIRE(loc2 == index.get(id2));
- REQUIRE_THROWS_AS(index.get( 0), osmium::not_found);
- REQUIRE_THROWS_AS(index.get( 1), osmium::not_found);
- REQUIRE_THROWS_AS(index.get( 5), osmium::not_found);
- REQUIRE_THROWS_AS(index.get( 7), osmium::not_found);
- REQUIRE_THROWS_AS(index.get(100), osmium::not_found);
+ REQUIRE_THROWS_AS(index.get( 0), const osmium::not_found&);
+ REQUIRE_THROWS_AS(index.get( 1), const osmium::not_found&);
+ REQUIRE_THROWS_AS(index.get( 5), const osmium::not_found&);
+ REQUIRE_THROWS_AS(index.get( 7), const osmium::not_found&);
+ REQUIRE_THROWS_AS(index.get(100), const osmium::not_found&);
REQUIRE(index.size() == 7);
REQUIRE(std::distance(index.cbegin(), index.cend()) == 7);
@@ -97,17 +97,17 @@ TEST_CASE("File based index") {
constexpr const size_t S = sizeof(index_type::element_type);
{
- index_type index(fd);
+ index_type index{fd};
REQUIRE(index.size() == 0);
- REQUIRE_THROWS_AS(index.get( 0), osmium::not_found);
- REQUIRE_THROWS_AS(index.get( 1), osmium::not_found);
- REQUIRE_THROWS_AS(index.get( 3), osmium::not_found);
- REQUIRE_THROWS_AS(index.get( 5), osmium::not_found);
- REQUIRE_THROWS_AS(index.get( 6), osmium::not_found);
- REQUIRE_THROWS_AS(index.get( 7), osmium::not_found);
- REQUIRE_THROWS_AS(index.get(100), osmium::not_found);
+ REQUIRE_THROWS_AS(index.get( 0), const osmium::not_found&);
+ REQUIRE_THROWS_AS(index.get( 1), const osmium::not_found&);
+ REQUIRE_THROWS_AS(index.get( 3), const osmium::not_found&);
+ REQUIRE_THROWS_AS(index.get( 5), const osmium::not_found&);
+ REQUIRE_THROWS_AS(index.get( 6), const osmium::not_found&);
+ REQUIRE_THROWS_AS(index.get( 7), const osmium::not_found&);
+ REQUIRE_THROWS_AS(index.get(100), const osmium::not_found&);
index.set(id1, loc1);
REQUIRE(index.size() == 1);
@@ -120,11 +120,11 @@ TEST_CASE("File based index") {
REQUIRE(loc1 == index.get(id1));
REQUIRE(loc2 == index.get(id2));
- REQUIRE_THROWS_AS(index.get( 0), osmium::not_found);
- REQUIRE_THROWS_AS(index.get( 1), osmium::not_found);
- REQUIRE_THROWS_AS(index.get( 5), osmium::not_found);
- REQUIRE_THROWS_AS(index.get( 7), osmium::not_found);
- REQUIRE_THROWS_AS(index.get(100), osmium::not_found);
+ REQUIRE_THROWS_AS(index.get( 0), const osmium::not_found&);
+ REQUIRE_THROWS_AS(index.get( 1), const osmium::not_found&);
+ REQUIRE_THROWS_AS(index.get( 5), const osmium::not_found&);
+ REQUIRE_THROWS_AS(index.get( 7), const osmium::not_found&);
+ REQUIRE_THROWS_AS(index.get(100), const osmium::not_found&);
REQUIRE(index.size() == 2);
REQUIRE(std::distance(index.cbegin(), index.cend()) == 2);
@@ -133,7 +133,7 @@ TEST_CASE("File based index") {
}
{
- index_type index(fd);
+ index_type index{fd};
REQUIRE(osmium::util::file_size(fd) >= (2 * S));
REQUIRE(index.size() == 2);
@@ -141,11 +141,11 @@ TEST_CASE("File based index") {
REQUIRE(loc1 == index.get(id1));
REQUIRE(loc2 == index.get(id2));
- REQUIRE_THROWS_AS(index.get( 0), osmium::not_found);
- REQUIRE_THROWS_AS(index.get( 1), osmium::not_found);
- REQUIRE_THROWS_AS(index.get( 5), osmium::not_found);
- REQUIRE_THROWS_AS(index.get( 7), osmium::not_found);
- REQUIRE_THROWS_AS(index.get(100), osmium::not_found);
+ REQUIRE_THROWS_AS(index.get( 0), const osmium::not_found&);
+ REQUIRE_THROWS_AS(index.get( 1), const osmium::not_found&);
+ REQUIRE_THROWS_AS(index.get( 5), const osmium::not_found&);
+ REQUIRE_THROWS_AS(index.get( 7), const osmium::not_found&);
+ REQUIRE_THROWS_AS(index.get(100), const osmium::not_found&);
REQUIRE(index.size() == 2);
REQUIRE(std::distance(index.cbegin(), index.cend()) == 2);
diff --git a/test/t/index/test_id_to_location.cpp b/test/t/index/test_id_to_location.cpp
index 9e38d12..4b63314 100644
--- a/test/t/index/test_id_to_location.cpp
+++ b/test/t/index/test_id_to_location.cpp
@@ -7,6 +7,7 @@
#include <osmium/index/map/dense_mem_array.hpp>
#include <osmium/index/map/dense_mmap_array.hpp>
#include <osmium/index/map/dummy.hpp>
+#include <osmium/index/map/flex_mem.hpp>
#include <osmium/index/map/sparse_file_array.hpp>
#include <osmium/index/map/sparse_mem_array.hpp>
#include <osmium/index/map/sparse_mem_map.hpp>
@@ -24,17 +25,17 @@ void test_func_all(TIndex& index) {
const osmium::Location loc1{1.2, 4.5};
const osmium::Location loc2{3.5, -7.2};
- REQUIRE_THROWS_AS(index.get(id1), osmium::not_found);
+ REQUIRE_THROWS_AS(index.get(id1), const osmium::not_found&);
index.set(id1, loc1);
index.set(id2, loc2);
index.sort();
- REQUIRE_THROWS_AS(index.get(0), osmium::not_found);
- REQUIRE_THROWS_AS(index.get(1), osmium::not_found);
- REQUIRE_THROWS_AS(index.get(5), osmium::not_found);
- REQUIRE_THROWS_AS(index.get(100), osmium::not_found);
+ REQUIRE_THROWS_AS(index.get(0), const osmium::not_found&);
+ REQUIRE_THROWS_AS(index.get(1), const osmium::not_found&);
+ REQUIRE_THROWS_AS(index.get(5), const osmium::not_found&);
+ REQUIRE_THROWS_AS(index.get(100), const osmium::not_found&);
REQUIRE_THROWS_WITH(index.get(0), "id 0 not found");
REQUIRE_THROWS_WITH(index.get(1), "id 1 not found");
@@ -62,10 +63,10 @@ void test_func_real(TIndex& index) {
REQUIRE(loc1 == index.get_noexcept(id1));
REQUIRE(loc2 == index.get_noexcept(id2));
- REQUIRE_THROWS_AS(index.get(0), osmium::not_found);
- REQUIRE_THROWS_AS(index.get(1), osmium::not_found);
- REQUIRE_THROWS_AS(index.get(5), osmium::not_found);
- REQUIRE_THROWS_AS(index.get(100), osmium::not_found);
+ REQUIRE_THROWS_AS(index.get(0), const osmium::not_found&);
+ REQUIRE_THROWS_AS(index.get(1), const osmium::not_found&);
+ REQUIRE_THROWS_AS(index.get(5), const osmium::not_found&);
+ REQUIRE_THROWS_AS(index.get(100), const osmium::not_found&);
REQUIRE(index.get_noexcept(0) == osmium::Location{});
REQUIRE(index.get_noexcept(1) == osmium::Location{});
@@ -74,13 +75,13 @@ void test_func_real(TIndex& index) {
index.clear();
- REQUIRE_THROWS_AS(index.get(id1), osmium::not_found);
- REQUIRE_THROWS_AS(index.get(id2), osmium::not_found);
+ REQUIRE_THROWS_AS(index.get(id1), const osmium::not_found&);
+ REQUIRE_THROWS_AS(index.get(id2), const osmium::not_found&);
- REQUIRE_THROWS_AS(index.get(0), osmium::not_found);
- REQUIRE_THROWS_AS(index.get(1), osmium::not_found);
- REQUIRE_THROWS_AS(index.get(5), osmium::not_found);
- REQUIRE_THROWS_AS(index.get(100), osmium::not_found);
+ REQUIRE_THROWS_AS(index.get(0), const osmium::not_found&);
+ REQUIRE_THROWS_AS(index.get(1), const osmium::not_found&);
+ REQUIRE_THROWS_AS(index.get(5), const osmium::not_found&);
+ REQUIRE_THROWS_AS(index.get(100), const osmium::not_found&);
REQUIRE(index.get_noexcept(id1) == osmium::Location{});
REQUIRE(index.get_noexcept(id2) == osmium::Location{});
@@ -180,15 +181,67 @@ TEST_CASE("Map Id to location: SparseMemArray") {
test_func_real<index_type>(index2);
}
+TEST_CASE("Map Id to location: FlexMem sparse") {
+ using index_type = osmium::index::map::FlexMem<osmium::unsigned_object_id_type, osmium::Location>;
+
+ index_type index1;
+ test_func_all<index_type>(index1);
+
+ index_type index2;
+ test_func_real<index_type>(index2);
+}
+
+TEST_CASE("Map Id to location: FlexMem dense") {
+ using index_type = osmium::index::map::FlexMem<osmium::unsigned_object_id_type, osmium::Location>;
+
+ index_type index1{true};
+ test_func_all<index_type>(index1);
+
+ index_type index2{true};
+ test_func_real<index_type>(index2);
+}
+
+TEST_CASE("Map Id to location: FlexMem switch") {
+ using index_type = osmium::index::map::FlexMem<osmium::unsigned_object_id_type, osmium::Location>;
+
+ const osmium::Location loc1{1.1, 1.2};
+ const osmium::Location loc2{2.2, -9.4};
+
+ index_type index;
+
+ REQUIRE(index.size() == 0);
+
+ index.set(17, loc1);
+ index.set(99, loc2);
+
+ REQUIRE_FALSE(index.is_dense());
+ REQUIRE(index.size() == 2);
+ REQUIRE(index.get_noexcept(0) == osmium::Location{});
+ REQUIRE(index.get_noexcept(1) == osmium::Location{});
+ REQUIRE(index.get_noexcept(17) == loc1);
+ REQUIRE(index.get_noexcept(99) == loc2);
+ REQUIRE(index.get_noexcept(2000000000) == osmium::Location{});
+
+ index.switch_to_dense();
+
+ REQUIRE(index.is_dense());
+ REQUIRE(index.size() >= 2);
+ REQUIRE(index.get_noexcept(0) == osmium::Location{});
+ REQUIRE(index.get_noexcept(1) == osmium::Location{});
+ REQUIRE(index.get_noexcept(17) == loc1);
+ REQUIRE(index.get_noexcept(99) == loc2);
+ REQUIRE(index.get_noexcept(2000000000) == osmium::Location{});
+}
+
TEST_CASE("Map Id to location: Dynamic map choice") {
using map_type = osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>;
const auto& map_factory = osmium::index::MapFactory<osmium::unsigned_object_id_type, osmium::Location>::instance();
const std::vector<std::string> map_type_names = map_factory.map_types();
- REQUIRE(map_type_names.size() >= 5);
+ REQUIRE(map_type_names.size() >= 6);
- REQUIRE_THROWS_AS(map_factory.create_map(""), osmium::map_factory_error);
- REQUIRE_THROWS_AS(map_factory.create_map("does not exist"), osmium::map_factory_error);
+ REQUIRE_THROWS_AS(map_factory.create_map(""), const osmium::map_factory_error&);
+ REQUIRE_THROWS_AS(map_factory.create_map("does not exist"), const osmium::map_factory_error&);
REQUIRE_THROWS_WITH(map_factory.create_map(""), "Need non-empty map type name");
REQUIRE_THROWS_WITH(map_factory.create_map("does not exist"), "Support for map type 'does not exist' not compiled into this binary");
diff --git a/test/t/io/test_bzip2.cpp b/test/t/io/test_bzip2.cpp
index 2d1c0f3..3e3fe81 100644
--- a/test/t/io/test_bzip2.cpp
+++ b/test/t/io/test_bzip2.cpp
@@ -8,7 +8,7 @@
#include <osmium/io/bzip2_compression.hpp>
TEST_CASE("Read bzip2-compressed file") {
- std::string input_file = with_data_dir("t/io/data_bzip2.txt.bz2");
+ const std::string input_file = with_data_dir("t/io/data_bzip2.txt.bz2");
const int fd = ::open(input_file.c_str(), O_RDONLY);
REQUIRE(fd > 0);
diff --git a/test/t/io/test_compression_factory.cpp b/test/t/io/test_compression_factory.cpp
index 612d232..97cb153 100644
--- a/test/t/io/test_compression_factory.cpp
+++ b/test/t/io/test_compression_factory.cpp
@@ -3,22 +3,21 @@
#include <osmium/io/compression.hpp>
-TEST_CASE("Compression factory") {
+TEST_CASE("Create compressor using factory") {
const auto& factory = osmium::io::CompressionFactory::instance();
+ REQUIRE(factory.create_compressor(osmium::io::file_compression::none, -1, osmium::io::fsync::no));
+}
- SECTION("compressor") {
- REQUIRE(factory.create_compressor(osmium::io::file_compression::none, -1, osmium::io::fsync::no));
- }
-
- SECTION("decompressor") {
- REQUIRE(factory.create_decompressor(osmium::io::file_compression::none, nullptr, 0));
- }
+TEST_CASE("Create decompressor using factory") {
+ const auto& factory = osmium::io::CompressionFactory::instance();
+ REQUIRE(factory.create_decompressor(osmium::io::file_compression::none, nullptr, 0));
+}
- SECTION("fail on undefined compression") {
- REQUIRE_THROWS_AS(factory.create_compressor(osmium::io::file_compression::gzip, -1, osmium::io::fsync::no),
- osmium::unsupported_file_format_error);
- REQUIRE_THROWS_WITH(factory.create_compressor(osmium::io::file_compression::gzip, -1, osmium::io::fsync::no),
- "Support for compression 'gzip' not compiled into this binary");
- }
+TEST_CASE("Compression factory fails on undefined compression") {
+ const auto& factory = osmium::io::CompressionFactory::instance();
+ REQUIRE_THROWS_AS(factory.create_compressor(osmium::io::file_compression::gzip, -1, osmium::io::fsync::no),
+ const osmium::unsupported_file_format_error&);
+ REQUIRE_THROWS_WITH(factory.create_compressor(osmium::io::file_compression::gzip, -1, osmium::io::fsync::no),
+ "Support for compression 'gzip' not compiled into this binary");
}
diff --git a/test/t/io/test_file_formats.cpp b/test/t/io/test_file_formats.cpp
index 356e3d1..8b63f94 100644
--- a/test/t/io/test_file_formats.cpp
+++ b/test/t/io/test_file_formats.cpp
@@ -5,31 +5,31 @@
#include <osmium/io/file.hpp>
TEST_CASE("Default file format") {
- osmium::io::File f;
+ const osmium::io::File f;
REQUIRE(osmium::io::file_format::unknown == f.format());
REQUIRE(osmium::io::file_compression::none == f.compression());
REQUIRE(false == f.has_multiple_object_versions());
- REQUIRE_THROWS_AS(f.check(), std::runtime_error);
+ REQUIRE_THROWS_AS(f.check(), const std::runtime_error&);
}
TEST_CASE("File format when empty (stdin/stdout)") {
- osmium::io::File f{""};
+ const osmium::io::File f{""};
REQUIRE(osmium::io::file_format::unknown == f.format());
REQUIRE(osmium::io::file_compression::none == f.compression());
REQUIRE(false == f.has_multiple_object_versions());
- REQUIRE_THROWS_AS(f.check(), std::runtime_error);
+ REQUIRE_THROWS_AS(f.check(), const std::runtime_error&);
}
TEST_CASE("File format from dash (stdin/stdout)") {
- osmium::io::File f{"-"};
+ const osmium::io::File f{"-"};
REQUIRE(osmium::io::file_format::unknown == f.format());
REQUIRE(osmium::io::file_compression::none == f.compression());
REQUIRE(false == f.has_multiple_object_versions());
- REQUIRE_THROWS_AS(f.check(), std::runtime_error);
+ REQUIRE_THROWS_AS(f.check(), const std::runtime_error&);
}
TEST_CASE("File format from dash with osm.bz2") {
- osmium::io::File f{"-", "osm.bz2"};
+ const osmium::io::File f{"-", "osm.bz2"};
REQUIRE("" == f.filename());
REQUIRE(osmium::io::file_format::xml == f.format());
REQUIRE(osmium::io::file_compression::bzip2 == f.compression());
@@ -38,7 +38,7 @@ TEST_CASE("File format from dash with osm.bz2") {
}
TEST_CASE("Detect file format by suffix 'osm'") {
- osmium::io::File f{"test.osm"};
+ const osmium::io::File f{"test.osm"};
REQUIRE(osmium::io::file_format::xml == f.format());
REQUIRE(osmium::io::file_compression::none == f.compression());
REQUIRE(false == f.has_multiple_object_versions());
@@ -46,7 +46,7 @@ TEST_CASE("Detect file format by suffix 'osm'") {
}
TEST_CASE("Detect file format by suffix 'pbf'") {
- osmium::io::File f{"test.pbf"};
+ const osmium::io::File f{"test.pbf"};
REQUIRE(osmium::io::file_format::pbf == f.format());
REQUIRE(osmium::io::file_compression::none == f.compression());
REQUIRE(false == f.has_multiple_object_versions());
@@ -54,7 +54,7 @@ TEST_CASE("Detect file format by suffix 'pbf'") {
}
TEST_CASE("Detect file format by suffix 'osm.pbf'") {
- osmium::io::File f{"test.osm.pbf"};
+ const osmium::io::File f{"test.osm.pbf"};
REQUIRE(osmium::io::file_format::pbf == f.format());
REQUIRE(osmium::io::file_compression::none == f.compression());
REQUIRE(false == f.has_multiple_object_versions());
@@ -62,7 +62,7 @@ TEST_CASE("Detect file format by suffix 'osm.pbf'") {
}
TEST_CASE("Detect file format by suffix 'opl'") {
- osmium::io::File f{"test.opl"};
+ const osmium::io::File f{"test.opl"};
REQUIRE(osmium::io::file_format::opl == f.format());
REQUIRE(osmium::io::file_compression::none == f.compression());
REQUIRE(false == f.has_multiple_object_versions());
@@ -70,7 +70,7 @@ TEST_CASE("Detect file format by suffix 'opl'") {
}
TEST_CASE("Detect file format by suffix 'osm.opl'") {
- osmium::io::File f{"test.osm.opl"};
+ const osmium::io::File f{"test.osm.opl"};
REQUIRE(osmium::io::file_format::opl == f.format());
REQUIRE(osmium::io::file_compression::none == f.compression());
REQUIRE(false == f.has_multiple_object_versions());
@@ -78,7 +78,7 @@ TEST_CASE("Detect file format by suffix 'osm.opl'") {
}
TEST_CASE("Detect file format by suffix 'osm.gz'") {
- osmium::io::File f{"test.osm.gz"};
+ const osmium::io::File f{"test.osm.gz"};
REQUIRE(osmium::io::file_format::xml == f.format());
REQUIRE(osmium::io::file_compression::gzip == f.compression());
REQUIRE(false == f.has_multiple_object_versions());
@@ -86,7 +86,7 @@ TEST_CASE("Detect file format by suffix 'osm.gz'") {
}
TEST_CASE("Detect file format by suffix 'opl.bz2'") {
- osmium::io::File f{"test.osm.opl.bz2"};
+ const osmium::io::File f{"test.osm.opl.bz2"};
REQUIRE(osmium::io::file_format::opl == f.format());
REQUIRE(osmium::io::file_compression::bzip2 == f.compression());
REQUIRE(false == f.has_multiple_object_versions());
@@ -94,7 +94,7 @@ TEST_CASE("Detect file format by suffix 'opl.bz2'") {
}
TEST_CASE("Detect file format by suffix 'osc.gz'") {
- osmium::io::File f{"test.osc.gz"};
+ const osmium::io::File f{"test.osc.gz"};
REQUIRE(osmium::io::file_format::xml == f.format());
REQUIRE(osmium::io::file_compression::gzip == f.compression());
REQUIRE(true == f.has_multiple_object_versions());
@@ -102,7 +102,7 @@ TEST_CASE("Detect file format by suffix 'osc.gz'") {
}
TEST_CASE("Detect file format by suffix 'opl.gz'") {
- osmium::io::File f{"test.osh.opl.gz"};
+ const osmium::io::File f{"test.osh.opl.gz"};
REQUIRE(osmium::io::file_format::opl == f.format());
REQUIRE(osmium::io::file_compression::gzip == f.compression());
REQUIRE(true == f.has_multiple_object_versions());
@@ -110,7 +110,7 @@ TEST_CASE("Detect file format by suffix 'opl.gz'") {
}
TEST_CASE("Detect file format by suffix 'osh.pbf'") {
- osmium::io::File f{"test.osh.pbf"};
+ const osmium::io::File f{"test.osh.pbf"};
REQUIRE(osmium::io::file_format::pbf == f.format());
REQUIRE(osmium::io::file_compression::none == f.compression());
REQUIRE(true == f.has_multiple_object_versions());
@@ -118,7 +118,7 @@ TEST_CASE("Detect file format by suffix 'osh.pbf'") {
}
TEST_CASE("Override file format by suffix 'osm'") {
- osmium::io::File f{"test", "osm"};
+ const osmium::io::File f{"test", "osm"};
REQUIRE(osmium::io::file_format::xml == f.format());
REQUIRE(osmium::io::file_compression::none == f.compression());
REQUIRE(false == f.has_multiple_object_versions());
@@ -126,7 +126,7 @@ TEST_CASE("Override file format by suffix 'osm'") {
}
TEST_CASE("Override file format by suffix 'pbf'") {
- osmium::io::File f{"test", "pbf"};
+ const osmium::io::File f{"test", "pbf"};
REQUIRE(osmium::io::file_format::pbf == f.format());
REQUIRE(osmium::io::file_compression::none == f.compression());
REQUIRE(false == f.has_multiple_object_versions());
@@ -134,7 +134,7 @@ TEST_CASE("Override file format by suffix 'pbf'") {
}
TEST_CASE("Override file format by suffix 'osm.pbf'") {
- osmium::io::File f{"test", "osm.pbf"};
+ const osmium::io::File f{"test", "osm.pbf"};
REQUIRE(osmium::io::file_format::pbf == f.format());
REQUIRE(osmium::io::file_compression::none == f.compression());
REQUIRE(false == f.has_multiple_object_versions());
@@ -142,7 +142,7 @@ TEST_CASE("Override file format by suffix 'osm.pbf'") {
}
TEST_CASE("Override file format by suffix 'opl'") {
- osmium::io::File f{"test", "opl"};
+ const osmium::io::File f{"test", "opl"};
REQUIRE(osmium::io::file_format::opl == f.format());
REQUIRE(osmium::io::file_compression::none == f.compression());
REQUIRE(false == f.has_multiple_object_versions());
@@ -150,7 +150,7 @@ TEST_CASE("Override file format by suffix 'opl'") {
}
TEST_CASE("Override file format by suffix 'osm.opl'") {
- osmium::io::File f{"test", "osm.opl"};
+ const osmium::io::File f{"test", "osm.opl"};
REQUIRE(osmium::io::file_format::opl == f.format());
REQUIRE(osmium::io::file_compression::none == f.compression());
REQUIRE(false == f.has_multiple_object_versions());
@@ -158,7 +158,7 @@ TEST_CASE("Override file format by suffix 'osm.opl'") {
}
TEST_CASE("Override file format by suffix 'osm.gz'") {
- osmium::io::File f{"test", "osm.gz"};
+ const osmium::io::File f{"test", "osm.gz"};
REQUIRE(osmium::io::file_format::xml == f.format());
REQUIRE(osmium::io::file_compression::gzip == f.compression());
REQUIRE(false == f.has_multiple_object_versions());
@@ -166,7 +166,7 @@ TEST_CASE("Override file format by suffix 'osm.gz'") {
}
TEST_CASE("Override file format by suffix 'osm.opl.bz2'") {
- osmium::io::File f{"test", "osm.opl.bz2"};
+ const osmium::io::File f{"test", "osm.opl.bz2"};
REQUIRE(osmium::io::file_format::opl == f.format());
REQUIRE(osmium::io::file_compression::bzip2 == f.compression());
REQUIRE(false == f.has_multiple_object_versions());
@@ -174,7 +174,7 @@ TEST_CASE("Override file format by suffix 'osm.opl.bz2'") {
}
TEST_CASE("Override file format by suffix 'osc.gz'") {
- osmium::io::File f{"test", "osc.gz"};
+ const osmium::io::File f{"test", "osc.gz"};
REQUIRE(osmium::io::file_format::xml == f.format());
REQUIRE(osmium::io::file_compression::gzip == f.compression());
REQUIRE(true == f.has_multiple_object_versions());
@@ -182,7 +182,7 @@ TEST_CASE("Override file format by suffix 'osc.gz'") {
}
TEST_CASE("Override file format by suffix 'osh.opl.gz'") {
- osmium::io::File f{"test", "osh.opl.gz"};
+ const osmium::io::File f{"test", "osh.opl.gz"};
REQUIRE(osmium::io::file_format::opl == f.format());
REQUIRE(osmium::io::file_compression::gzip == f.compression());
REQUIRE(true == f.has_multiple_object_versions());
@@ -190,7 +190,7 @@ TEST_CASE("Override file format by suffix 'osh.opl.gz'") {
}
TEST_CASE("Override file format by suffix 'osh.pbf'") {
- osmium::io::File f{"test", "osh.pbf"};
+ const osmium::io::File f{"test", "osh.pbf"};
REQUIRE(osmium::io::file_format::pbf == f.format());
REQUIRE(osmium::io::file_compression::none == f.compression());
REQUIRE(true == f.has_multiple_object_versions());
@@ -198,7 +198,7 @@ TEST_CASE("Override file format by suffix 'osh.pbf'") {
}
TEST_CASE("Format option pbf history") {
- osmium::io::File f{"test", "pbf,history=true"};
+ const osmium::io::File f{"test", "pbf,history=true"};
REQUIRE(osmium::io::file_format::pbf == f.format());
REQUIRE(osmium::io::file_compression::none == f.compression());
REQUIRE(true == f.has_multiple_object_versions());
@@ -206,7 +206,7 @@ TEST_CASE("Format option pbf history") {
}
TEST_CASE("Format option pbf foo") {
- osmium::io::File f{"test.osm", "pbf,foo=bar"};
+ const osmium::io::File f{"test.osm", "pbf,foo=bar"};
REQUIRE(osmium::io::file_format::pbf == f.format());
REQUIRE(osmium::io::file_compression::none == f.compression());
REQUIRE("bar" == f.get("foo"));
@@ -214,7 +214,7 @@ TEST_CASE("Format option pbf foo") {
}
TEST_CASE("Format option xml abc something") {
- osmium::io::File f{"test.bla", "xml,abc,some=thing"};
+ const osmium::io::File f{"test.bla", "xml,abc,some=thing"};
REQUIRE(osmium::io::file_format::xml == f.format());
REQUIRE(osmium::io::file_compression::none == f.compression());
REQUIRE("true" == f.get("abc"));
@@ -224,29 +224,29 @@ TEST_CASE("Format option xml abc something") {
}
TEST_CASE("Unknown format 'foo.bar'") {
- osmium::io::File f{"test.foo.bar"};
+ const osmium::io::File f{"test.foo.bar"};
REQUIRE(osmium::io::file_format::unknown == f.format());
REQUIRE(osmium::io::file_compression::none == f.compression());
- REQUIRE_THROWS_AS(f.check(), std::runtime_error);
+ REQUIRE_THROWS_AS(f.check(), const std::runtime_error&);
}
TEST_CASE("Unknown format 'foo'") {
- osmium::io::File f{"test", "foo"};
- REQUIRE_THROWS_AS(f.check(), std::runtime_error);
+ const osmium::io::File f{"test", "foo"};
+ REQUIRE_THROWS_AS(f.check(), const std::runtime_error&);
}
TEST_CASE("Unknown format 'osm.foo'") {
- osmium::io::File f{"test", "osm.foo"};
- REQUIRE_THROWS_AS(f.check(), std::runtime_error);
+ const osmium::io::File f{"test", "osm.foo"};
+ REQUIRE_THROWS_AS(f.check(), const std::runtime_error&);
}
TEST_CASE("Unknown format 'bla=foo'") {
- osmium::io::File f{"test", "bla=foo"};
- REQUIRE_THROWS_AS(f.check(), std::runtime_error);
+ const osmium::io::File f{"test", "bla=foo"};
+ REQUIRE_THROWS_AS(f.check(), const std::runtime_error&);
}
TEST_CASE("URL without format") {
- osmium::io::File f{"http://www.example.com/api"};
+ const osmium::io::File f{"http://www.example.com/api"};
REQUIRE(osmium::io::file_format::xml == f.format());
REQUIRE(osmium::io::file_compression::none == f.compression());
REQUIRE(false == f.has_multiple_object_versions());
@@ -254,7 +254,7 @@ TEST_CASE("URL without format") {
}
TEST_CASE("URL without format and filename") {
- osmium::io::File f{"http://planet.osm.org/pbf/planet-latest.osm.pbf"};
+ const osmium::io::File f{"http://planet.osm.org/pbf/planet-latest.osm.pbf"};
REQUIRE(osmium::io::file_format::pbf == f.format());
REQUIRE(osmium::io::file_compression::none == f.compression());
REQUIRE(false == f.has_multiple_object_versions());
@@ -262,7 +262,7 @@ TEST_CASE("URL without format and filename") {
}
TEST_CASE("URL with format") {
- osmium::io::File f{"http://www.example.com/api", "osh"};
+ const osmium::io::File f{"http://www.example.com/api", "osh"};
REQUIRE(osmium::io::file_format::xml == f.format());
REQUIRE(osmium::io::file_compression::none == f.compression());
REQUIRE(true == f.has_multiple_object_versions());
diff --git a/test/t/io/test_opl_parser.cpp b/test/t/io/test_opl_parser.cpp
index 8e2cdb7..7ecf2b8 100644
--- a/test/t/io/test_opl_parser.cpp
+++ b/test/t/io/test_opl_parser.cpp
@@ -12,7 +12,7 @@
namespace oid = osmium::io::detail;
TEST_CASE("Parse OPL: base exception") {
- osmium::opl_error e{"foo"};
+ const osmium::opl_error e{"foo"};
REQUIRE(e.data == nullptr);
REQUIRE(e.line == 0);
REQUIRE(e.column == 0);
@@ -32,16 +32,16 @@ TEST_CASE("Parse OPL: exception with line and column") {
}
TEST_CASE("Parse OPL: space") {
- std::string d{"a b \t c"};
+ const std::string d{"a b \t c"};
const char* s = d.data();
- REQUIRE_THROWS_AS(oid::opl_parse_space(&s), osmium::opl_error);
+ REQUIRE_THROWS_AS(oid::opl_parse_space(&s), const osmium::opl_error&);
s = d.data() + 1;
oid::opl_parse_space(&s);
REQUIRE(*s == 'b');
- REQUIRE_THROWS_AS(oid::opl_parse_space(&s), osmium::opl_error);
+ REQUIRE_THROWS_AS(oid::opl_parse_space(&s), const osmium::opl_error&);
++s;
oid::opl_parse_space(&s);
@@ -58,7 +58,7 @@ TEST_CASE("Parse OPL: check for space") {
}
TEST_CASE("Parse OPL: skip section") {
- std::string d{"abcd efgh"};
+ const std::string d{"abcd efgh"};
const char* skip1 = d.data() + 4;
const char* skip2 = d.data() + 9;
const char* s = d.data();
@@ -245,7 +245,7 @@ TEST_CASE("Parse OPL: parse string") {
template <typename T = int64_t>
T test_parse_int(const char* s) {
- auto r = oid::opl_parse_int<T>(&s);
+ const auto r = oid::opl_parse_int<T>(&s);
REQUIRE(*s == 'x');
return r;
}
@@ -916,28 +916,28 @@ TEST_CASE("Parse line") {
SECTION("Node") {
REQUIRE(oid::opl_parse_line(0, "n12 v3", buffer));
REQUIRE(buffer.written() > 0);
- auto& item = buffer.get<osmium::memory::Item>(0);
+ const auto& item = buffer.get<osmium::memory::Item>(0);
REQUIRE(item.type() == osmium::item_type::node);
}
SECTION("Way") {
REQUIRE(oid::opl_parse_line(0, "w12 v3", buffer));
REQUIRE(buffer.written() > 0);
- auto& item = buffer.get<osmium::memory::Item>(0);
+ const auto& item = buffer.get<osmium::memory::Item>(0);
REQUIRE(item.type() == osmium::item_type::way);
}
SECTION("Relation") {
REQUIRE(oid::opl_parse_line(0, "r12 v3", buffer));
REQUIRE(buffer.written() > 0);
- auto& item = buffer.get<osmium::memory::Item>(0);
+ const auto& item = buffer.get<osmium::memory::Item>(0);
REQUIRE(item.type() == osmium::item_type::relation);
}
SECTION("Changeset") {
REQUIRE(oid::opl_parse_line(0, "c12", buffer));
REQUIRE(buffer.written() > 0);
- auto& item = buffer.get<osmium::memory::Item>(0);
+ const auto& item = buffer.get<osmium::memory::Item>(0);
REQUIRE(item.type() == osmium::item_type::changeset);
}
diff --git a/test/t/io/test_output_iterator.cpp b/test/t/io/test_output_iterator.cpp
index f554da2..df032a8 100644
--- a/test/t/io/test_output_iterator.cpp
+++ b/test/t/io/test_output_iterator.cpp
@@ -4,33 +4,30 @@
#include <osmium/io/output_iterator.hpp>
#include <osmium/io/writer.hpp>
-TEST_CASE("output iterator") {
+TEST_CASE("Output iterator should be copy constructable") {
+ const osmium::io::Header header;
+ osmium::io::Writer writer{"test.osm", header, osmium::io::overwrite::allow};
- osmium::io::Header header;
-
- SECTION("should be copy constructable") {
- osmium::io::Writer writer{"test.osm", header, osmium::io::overwrite::allow};
- osmium::io::OutputIterator<osmium::io::Writer> out1{writer};
-
- osmium::io::OutputIterator<osmium::io::Writer> out2{out1};
- }
-
- SECTION("should be copy assignable") {
- osmium::io::Writer writer1{"test1.osm", header, osmium::io::overwrite::allow};
- osmium::io::Writer writer2{"test2.osm", header, osmium::io::overwrite::allow};
+ osmium::io::OutputIterator<osmium::io::Writer> out1{writer};
+ osmium::io::OutputIterator<osmium::io::Writer> out2{out1};
+}
- osmium::io::OutputIterator<osmium::io::Writer> out1{writer1};
- osmium::io::OutputIterator<osmium::io::Writer> out2{writer2};
+TEST_CASE("Output iterator should be copy assignable") {
+ const osmium::io::Header header;
+ osmium::io::Writer writer1{"test1.osm", header, osmium::io::overwrite::allow};
+ osmium::io::Writer writer2{"test2.osm", header, osmium::io::overwrite::allow};
- out2 = out1;
- }
+ osmium::io::OutputIterator<osmium::io::Writer> out1{writer1};
+ osmium::io::OutputIterator<osmium::io::Writer> out2{writer2};
- SECTION("should be incrementable") {
- osmium::io::Writer writer{"test.osm", header, osmium::io::overwrite::allow};
- osmium::io::OutputIterator<osmium::io::Writer> out{writer};
+ out2 = out1;
+}
- ++out;
- }
+TEST_CASE("Output iterator should be incrementable") {
+ const osmium::io::Header header;
+ osmium::io::Writer writer{"test.osm", header, osmium::io::overwrite::allow};
+ osmium::io::OutputIterator<osmium::io::Writer> out{writer};
+ ++out;
}
diff --git a/test/t/io/test_reader.cpp b/test/t/io/test_reader.cpp
index 45c087d..10cc3b1 100644
--- a/test/t/io/test_reader.cpp
+++ b/test/t/io/test_reader.cpp
@@ -54,6 +54,15 @@ TEST_CASE("Reader can be initialized with string") {
osmium::apply(reader, handler);
}
+TEST_CASE("Reader can be initialized with user-provided pool") {
+ osmium::thread::Pool pool{4};
+ osmium::io::File file{with_data_dir("t/io/data.osm")};
+ osmium::io::Reader reader{file, pool};
+ osmium::handler::Handler handler;
+
+ osmium::apply(reader, handler);
+}
+
TEST_CASE("Reader should throw after eof") {
osmium::io::File file{with_data_dir("t/io/data.osm")};
osmium::io::Reader reader{file};
@@ -71,7 +80,7 @@ TEST_CASE("Reader should throw after eof") {
REQUIRE(reader.eof());
- REQUIRE_THROWS_AS(reader.read(), osmium::io_error);
+ REQUIRE_THROWS_AS(reader.read(), const osmium::io_error&);
reader.close();
REQUIRE(reader.eof());
@@ -83,7 +92,7 @@ TEST_CASE("Reader should not hang when apply() is called twice on reader") {
osmium::handler::Handler handler;
osmium::apply(reader, handler);
- REQUIRE_THROWS_AS(osmium::apply(reader, handler), osmium::io_error);
+ REQUIRE_THROWS_AS(osmium::apply(reader, handler), const osmium::io_error&);
}
TEST_CASE("Reader should work with a buffer with uncompressed data") {
@@ -183,7 +192,7 @@ TEST_CASE("Reader should fail with nonexistent file (pbf)") {
TEST_CASE("Reader should work when there is an exception in main thread before getting header") {
try {
osmium::io::Reader reader{with_data_dir("t/io/data.osm")};
- REQUIRE(!reader.eof());
+ REQUIRE_FALSE(reader.eof());
throw std::runtime_error{"foo"};
} catch (...) {
}
@@ -192,7 +201,7 @@ TEST_CASE("Reader should work when there is an exception in main thread before g
TEST_CASE("Reader should work when there is an exception in main thread while reading") {
try {
osmium::io::Reader reader{with_data_dir("t/io/data.osm")};
- REQUIRE(!reader.eof());
+ REQUIRE_FALSE(reader.eof());
auto header = reader.header();
throw std::runtime_error{"foo"};
} catch (...) {
@@ -219,7 +228,7 @@ TEST_CASE("Can call read() exactly once on Reader with entity_bits nothing") {
osmium::memory::Buffer buffer = reader.read();
REQUIRE_FALSE(buffer);
REQUIRE(reader.eof());
- REQUIRE_THROWS_AS(reader.read(), osmium::io_error);
+ REQUIRE_THROWS_AS(reader.read(), const osmium::io_error&);
reader.close();
REQUIRE(reader.eof());
@@ -243,6 +252,6 @@ TEST_CASE("Can not read after close") {
reader.close();
REQUIRE(reader.eof());
- REQUIRE_THROWS_AS(reader.read(), osmium::io_error);
+ REQUIRE_THROWS_AS(reader.read(), const osmium::io_error&);
}
diff --git a/test/t/io/test_reader_fileformat.cpp b/test/t/io/test_reader_fileformat.cpp
index a64932e..83b4a0d 100644
--- a/test/t/io/test_reader_fileformat.cpp
+++ b/test/t/io/test_reader_fileformat.cpp
@@ -5,6 +5,6 @@
#include <osmium/io/reader.hpp>
TEST_CASE("Reader throws on unsupported file format") {
- REQUIRE_THROWS_AS(osmium::io::Reader{with_data_dir("t/io/data.osm")}, osmium::unsupported_file_format_error);
+ REQUIRE_THROWS_AS(osmium::io::Reader{with_data_dir("t/io/data.osm")}, const osmium::unsupported_file_format_error&);
}
diff --git a/test/t/io/test_reader_with_mock_parser.cpp b/test/t/io/test_reader_with_mock_parser.cpp
index 4076964..f0aef07 100644
--- a/test/t/io/test_reader_with_mock_parser.cpp
+++ b/test/t/io/test_reader_with_mock_parser.cpp
@@ -62,7 +62,7 @@ TEST_CASE("Test Reader using MockParser") {
osmium::io::Reader reader{with_data_dir("t/io/data.osm")};
auto header = reader.header();
REQUIRE(reader.read());
- REQUIRE(!reader.read());
+ REQUIRE_FALSE(reader.read());
REQUIRE(reader.eof());
reader.close();
}
@@ -99,7 +99,7 @@ TEST_CASE("Test Reader using MockParser") {
REQUIRE(std::string{e.what()} == "error in user code");
}
REQUIRE(reader.read());
- REQUIRE(!reader.read());
+ REQUIRE_FALSE(reader.read());
REQUIRE(reader.eof());
reader.close();
}
diff --git a/test/t/io/test_string_table.cpp b/test/t/io/test_string_table.cpp
index 38418a0..6b7ccba 100644
--- a/test/t/io/test_string_table.cpp
+++ b/test/t/io/test_string_table.cpp
@@ -2,119 +2,125 @@
#include <osmium/io/detail/string_table.hpp>
-TEST_CASE("String store") {
+TEST_CASE("Empty StringStore") {
+ const osmium::io::detail::StringStore ss{100};
+
+ REQUIRE(ss.begin() == ss.end());
+ REQUIRE(ss.get_chunk_size() == 100);
+ REQUIRE(ss.get_chunk_count() == 1);
+}
+
+TEST_CASE("Add zero-length string to StringStore") {
osmium::io::detail::StringStore ss{100};
- SECTION("empty") {
- REQUIRE(ss.begin() == ss.end());
- REQUIRE(ss.get_chunk_size() == 100);
- REQUIRE(ss.get_chunk_count() == 1);
- }
+ const char* s1 = ss.add("");
+ REQUIRE(std::string(s1) == "");
- SECTION("add zero-length string") {
- const char* s1 = ss.add("");
- REQUIRE(std::string(s1) == "");
+ auto it = ss.begin();
+ REQUIRE(s1 == *it);
+ REQUIRE(std::string(*it) == "");
+ REQUIRE(++it == ss.end());
- auto it = ss.begin();
- REQUIRE(s1 == *it);
- REQUIRE(std::string(*it) == "");
- REQUIRE(++it == ss.end());
+ REQUIRE(ss.get_chunk_count() == 1);
+}
- REQUIRE(ss.get_chunk_count() == 1);
- }
+TEST_CASE("Add strings to StringStore") {
+ osmium::io::detail::StringStore ss{100};
- SECTION("add strings") {
- const char* s1 = ss.add("foo");
- const char* s2 = ss.add("bar");
- REQUIRE(s1 != s2);
- REQUIRE(std::string(s1) == "foo");
- REQUIRE(std::string(s2) == "bar");
+ const char* s1 = ss.add("foo");
+ const char* s2 = ss.add("bar");
+ REQUIRE(s1 != s2);
+ REQUIRE(std::string(s1) == "foo");
+ REQUIRE(std::string(s2) == "bar");
- auto it = ss.begin();
- REQUIRE(s1 == *it++);
- REQUIRE(s2 == *it++);
- REQUIRE(it == ss.end());
+ auto it = ss.begin();
+ REQUIRE(s1 == *it++);
+ REQUIRE(s2 == *it++);
+ REQUIRE(it == ss.end());
- ss.clear();
- REQUIRE(ss.begin() == ss.end());
- }
+ ss.clear();
+ REQUIRE(ss.begin() == ss.end());
+}
- SECTION("add zero-length string and longer strings") {
- ss.add("");
- ss.add("xxx");
- ss.add("yyyyy");
+TEST_CASE("Add zero-length string and longer strings to StringStore") {
+ osmium::io::detail::StringStore ss{100};
- auto it = ss.begin();
- REQUIRE(std::string(*it++) == "");
- REQUIRE(std::string(*it++) == "xxx");
- REQUIRE(std::string(*it++) == "yyyyy");
- REQUIRE(it == ss.end());
- }
+ ss.add("");
+ ss.add("xxx");
+ ss.add("yyyyy");
+
+ auto it = ss.begin();
+ REQUIRE(std::string(*it++) == "");
+ REQUIRE(std::string(*it++) == "xxx");
+ REQUIRE(std::string(*it++) == "yyyyy");
+ REQUIRE(it == ss.end());
+}
+
+TEST_CASE("Add many strings to StringStore") {
+ osmium::io::detail::StringStore ss{100};
- SECTION("add many strings") {
- for (const char* teststring : {"", "a", "abc", "abcd", "abcde"}) {
- int i = 0;
- for (; i < 200; ++i) {
- ss.add(teststring);
- }
-
- for (const char* s : ss) {
- REQUIRE(std::string(s) == teststring);
- --i;
- }
-
- REQUIRE(i == 0);
- REQUIRE(ss.get_chunk_count() > 1);
- ss.clear();
- REQUIRE(ss.get_chunk_count() == 1);
+ for (const char* teststring : {"", "a", "abc", "abcd", "abcde"}) {
+ int i = 0;
+ for (; i < 200; ++i) {
+ ss.add(teststring);
}
+
+ for (const char* s : ss) {
+ REQUIRE(std::string(s) == teststring);
+ --i;
+ }
+
+ REQUIRE(i == 0);
+ REQUIRE(ss.get_chunk_count() > 1);
+ ss.clear();
+ REQUIRE(ss.get_chunk_count() == 1);
}
+}
+
+TEST_CASE("Empty StringTable") {
+ const osmium::io::detail::StringTable st;
+ REQUIRE(st.size() == 1);
+ REQUIRE(std::next(st.begin()) == st.end());
}
-TEST_CASE("String table") {
+TEST_CASE("Add strings to StringTable") {
osmium::io::detail::StringTable st;
- SECTION("empty") {
- REQUIRE(st.size() == 1);
- REQUIRE(std::next(st.begin()) == st.end());
- }
+ REQUIRE(st.add("foo") == 1);
+ REQUIRE(st.add("bar") == 2);
+ REQUIRE(st.add("bar") == 2);
+ REQUIRE(st.add("baz") == 3);
+ REQUIRE(st.add("foo") == 1);
+ REQUIRE(st.size() == 4);
- SECTION("add strings") {
- REQUIRE(st.add("foo") == 1);
- REQUIRE(st.add("bar") == 2);
- REQUIRE(st.add("bar") == 2);
- REQUIRE(st.add("baz") == 3);
- REQUIRE(st.add("foo") == 1);
- REQUIRE(st.size() == 4);
-
- auto it = st.begin();
- REQUIRE(std::string("") == *it++);
- REQUIRE(std::string("foo") == *it++);
- REQUIRE(std::string("bar") == *it++);
- REQUIRE(std::string("baz") == *it++);
- REQUIRE(it == st.end());
-
- st.clear();
- REQUIRE(st.size() == 1);
- }
+ auto it = st.begin();
+ REQUIRE(std::string("") == *it++);
+ REQUIRE(std::string("foo") == *it++);
+ REQUIRE(std::string("bar") == *it++);
+ REQUIRE(std::string("baz") == *it++);
+ REQUIRE(it == st.end());
- SECTION("add empty string") {
- REQUIRE(st.add("") == 1);
- REQUIRE(st.size() == 2);
- REQUIRE(st.add("") == 1);
- REQUIRE(st.size() == 2);
- }
+ st.clear();
+ REQUIRE(st.size() == 1);
+}
+
+TEST_CASE("Add empty string to StringTable") {
+ osmium::io::detail::StringTable st;
+ REQUIRE(st.add("") == 1);
+ REQUIRE(st.size() == 2);
+ REQUIRE(st.add("") == 1);
+ REQUIRE(st.size() == 2);
}
-TEST_CASE("lots of strings in string table so chunk overflows") {
+TEST_CASE("Lots of strings in string table so chunk overflows") {
osmium::io::detail::StringTable st{100};
REQUIRE(st.size() == 1);
const int n = 1000;
for (int i = 0; i < n; ++i) {
- auto s = std::to_string(i);
+ const auto s = std::to_string(i);
st.add(s.c_str());
}
@@ -123,7 +129,7 @@ TEST_CASE("lots of strings in string table so chunk overflows") {
auto it = st.begin();
REQUIRE(std::string{} == *it++);
for (int i = 0; i < n; ++i) {
- REQUIRE(atoi(*it++) == i);
+ REQUIRE(std::atoi(*it++) == i);
}
REQUIRE(it == st.end());
}
diff --git a/test/t/io/test_writer.cpp b/test/t/io/test_writer.cpp
index 38ec6ad..9f47b77 100644
--- a/test/t/io/test_writer.cpp
+++ b/test/t/io/test_writer.cpp
@@ -43,10 +43,10 @@ TEST_CASE("Writer") {
osmium::io::Reader reader_check{filename};
osmium::memory::Buffer buffer_check = reader_check.read();
- REQUIRE(!buffer_check);
+ REQUIRE_FALSE(buffer_check);
}
- SECTION("Successfull writes") {
+ SECTION("Successful writes") {
SECTION("Writer buffer") {
filename = "test-writer-out-buffer.osm";
@@ -54,7 +54,7 @@ TEST_CASE("Writer") {
writer(std::move(buffer));
writer.close();
- REQUIRE_THROWS_AS(writer(osmium::memory::Buffer{}), osmium::io_error);
+ REQUIRE_THROWS_AS(writer(osmium::memory::Buffer{}), const osmium::io_error&);
}
SECTION("Writer item") {
@@ -75,7 +75,7 @@ TEST_CASE("Writer") {
}
osmium::io::Reader reader_check{filename};
- osmium::memory::Buffer buffer_check = reader_check.read();
+ const osmium::memory::Buffer buffer_check = reader_check.read();
REQUIRE(buffer_check);
REQUIRE(buffer_check.committed() > 0);
REQUIRE(buffer_check.select<osmium::OSMObject>().size() == num);
@@ -111,3 +111,40 @@ TEST_CASE("Writer") {
}
+TEST_CASE("Writer with user-provided pool") {
+ osmium::io::Header header;
+ header.set("generator", "test_writer.cpp");
+
+ osmium::io::Reader reader{with_data_dir("t/io/data.osm")};
+ osmium::memory::Buffer buffer = reader.read();
+ REQUIRE(buffer);
+ REQUIRE(buffer.committed() > 0);
+
+ SECTION("with default number of threads") {
+ osmium::thread::Pool pool;
+ osmium::io::Writer writer{"test-writer-pool-with-default-threads.osm", pool, header, osmium::io::overwrite::allow};
+ writer(std::move(buffer));
+ writer.close();
+ }
+
+ SECTION("with negative number of threads") {
+ osmium::thread::Pool pool{-2};
+ osmium::io::Writer writer{"test-writer-pool-with-negative-threads.osm", header, pool, osmium::io::overwrite::allow};
+ writer(std::move(buffer));
+ writer.close();
+ }
+
+ SECTION("with outlier negative number of threads") {
+ osmium::thread::Pool pool{-1000};
+ osmium::io::Writer writer{"test-writer-pool-with-outlier-negative-threads.osm", header, osmium::io::overwrite::allow, pool};
+ writer(std::move(buffer));
+ writer.close();
+ }
+
+ SECTION("with outlier positive number of threads") {
+ osmium::thread::Pool pool{1000};
+ osmium::io::Writer writer{"test-writer-pool-with-outlier-positive-threads.osm", header, osmium::io::overwrite::allow, pool};
+ writer(std::move(buffer));
+ writer.close();
+ }
+}
diff --git a/test/t/io/test_writer_with_mock_compression.cpp b/test/t/io/test_writer_with_mock_compression.cpp
index a4f9de2..c297462 100644
--- a/test/t/io/test_writer_with_mock_compression.cpp
+++ b/test/t/io/test_writer_with_mock_compression.cpp
@@ -66,7 +66,7 @@ TEST_CASE("Write with mock compressor") {
osmium::io::Writer writer("test-writer-mock-fail-on-construction.osm.gz", header, osmium::io::overwrite::allow);
writer(std::move(buffer));
writer.close();
- }(), std::logic_error);
+ }(), const std::logic_error&);
}
@@ -78,7 +78,7 @@ TEST_CASE("Write with mock compressor") {
osmium::io::Writer writer("test-writer-mock-fail-on-write.osm.gz", header, osmium::io::overwrite::allow);
writer(std::move(buffer));
writer.close();
- }(), std::logic_error);
+ }(), const std::logic_error&);
}
@@ -90,7 +90,7 @@ TEST_CASE("Write with mock compressor") {
osmium::io::Writer writer("test-writer-mock-fail-on-close.osm.gz", header, osmium::io::overwrite::allow);
writer(std::move(buffer));
writer.close();
- }(), std::logic_error);
+ }(), const std::logic_error&);
}
diff --git a/test/t/io/test_writer_with_mock_encoder.cpp b/test/t/io/test_writer_with_mock_encoder.cpp
index 8a0de76..f57ddbd 100644
--- a/test/t/io/test_writer_with_mock_encoder.cpp
+++ b/test/t/io/test_writer_with_mock_encoder.cpp
@@ -17,8 +17,8 @@ class MockOutputFormat : public osmium::io::detail::OutputFormat {
public:
- MockOutputFormat(const osmium::io::File&, osmium::io::detail::future_string_queue_type& output_queue, const std::string& fail_in) :
- OutputFormat(output_queue),
+ MockOutputFormat(osmium::thread::Pool& pool, const osmium::io::File&, osmium::io::detail::future_string_queue_type& output_queue, const std::string& fail_in) :
+ OutputFormat(pool, output_queue),
m_fail_in(fail_in) {
}
@@ -51,8 +51,8 @@ TEST_CASE("Test Writer with MockOutputFormat") {
osmium::io::detail::OutputFormatFactory::instance().register_output_format(
osmium::io::file_format::xml,
- [&](const osmium::io::File& file, osmium::io::detail::future_string_queue_type& output_queue) {
- return new MockOutputFormat{file, output_queue, fail_in};
+ [&](osmium::thread::Pool& pool, const osmium::io::File& file, osmium::io::detail::future_string_queue_type& output_queue) {
+ return new MockOutputFormat{pool, file, output_queue, fail_in};
});
osmium::io::Header header;
@@ -72,7 +72,7 @@ TEST_CASE("Test Writer with MockOutputFormat") {
osmium::io::Writer writer("test-writer-mock-fail-on-construction.osm", header, osmium::io::overwrite::allow);
writer(std::move(buffer));
writer.close();
- }(), std::logic_error);
+ }(), const std::logic_error&);
}
@@ -84,7 +84,7 @@ TEST_CASE("Test Writer with MockOutputFormat") {
osmium::io::Writer writer("test-writer-mock-fail-on-construction.osm", header, osmium::io::overwrite::allow);
writer(std::move(buffer));
writer.close();
- }(), std::logic_error);
+ }(), const std::logic_error&);
}
@@ -96,7 +96,7 @@ TEST_CASE("Test Writer with MockOutputFormat") {
osmium::io::Writer writer("test-writer-mock-fail-on-construction.osm", header, osmium::io::overwrite::allow);
writer(std::move(buffer));
writer.close();
- }(), std::logic_error);
+ }(), const std::logic_error&);
}
diff --git a/test/t/memory/test_buffer_basics.cpp b/test/t/memory/test_buffer_basics.cpp
index 9e230de..87c4d46 100644
--- a/test/t/memory/test_buffer_basics.cpp
+++ b/test/t/memory/test_buffer_basics.cpp
@@ -1,16 +1,18 @@
#include "catch.hpp"
+#include <array>
+#include <stdexcept>
+
#include <osmium/memory/buffer.hpp>
TEST_CASE("Buffer basics") {
-
osmium::memory::Buffer invalid_buffer1;
osmium::memory::Buffer invalid_buffer2;
osmium::memory::Buffer empty_buffer1{1024};
osmium::memory::Buffer empty_buffer2{2048};
- REQUIRE(!invalid_buffer1);
- REQUIRE(!invalid_buffer2);
+ REQUIRE_FALSE(invalid_buffer1);
+ REQUIRE_FALSE(invalid_buffer2);
REQUIRE(empty_buffer1);
REQUIRE(empty_buffer2);
@@ -21,15 +23,19 @@ TEST_CASE("Buffer basics") {
REQUIRE(invalid_buffer1.capacity() == 0);
REQUIRE(invalid_buffer1.written() == 0);
REQUIRE(invalid_buffer1.committed() == 0);
+ REQUIRE(invalid_buffer1.clear() == 0);
REQUIRE(empty_buffer1.capacity() == 1024);
REQUIRE(empty_buffer1.written() == 0);
REQUIRE(empty_buffer1.committed() == 0);
+ REQUIRE(empty_buffer1.is_aligned());
+ REQUIRE(empty_buffer1.clear() == 0);
REQUIRE(empty_buffer2.capacity() == 2048);
REQUIRE(empty_buffer2.written() == 0);
REQUIRE(empty_buffer2.committed() == 0);
-
+ REQUIRE(empty_buffer2.is_aligned());
+ REQUIRE(empty_buffer2.clear() == 0);
}
TEST_CASE("Buffer with zero size") {
@@ -52,3 +58,74 @@ TEST_CASE("Buffer with non-aligned size") {
REQUIRE(buffer.capacity() > 65);
}
+TEST_CASE("Grow a buffer") {
+ osmium::memory::Buffer buffer{128};
+ REQUIRE(buffer.capacity() == 128);
+ buffer.grow(256);
+ REQUIRE(buffer.capacity() == 256);
+ buffer.grow(257);
+ REQUIRE(buffer.capacity() > 256);
+ REQUIRE(buffer.committed() == 0);
+ REQUIRE(buffer.written() == 0);
+ REQUIRE(buffer.is_aligned());
+}
+
+TEST_CASE("Reserve space in a non-growing buffer") {
+ osmium::memory::Buffer buffer{128, osmium::memory::Buffer::auto_grow::no};
+
+ REQUIRE(buffer.reserve_space(20) != nullptr);
+ REQUIRE(buffer.written() == 20);
+ REQUIRE_THROWS_AS(buffer.reserve_space(1000), const osmium::buffer_is_full&);
+}
+
+TEST_CASE("Reserve space in a growing buffer") {
+ osmium::memory::Buffer buffer{128, osmium::memory::Buffer::auto_grow::yes};
+
+ REQUIRE(buffer.reserve_space(20) != nullptr);
+ REQUIRE(buffer.written() == 20);
+ REQUIRE(buffer.reserve_space(1000) != nullptr);
+ REQUIRE(buffer.written() == 1020);
+}
+
+TEST_CASE("Create buffer from existing data with good alignment works") {
+ std::array<unsigned char, 128> data;
+
+ osmium::memory::Buffer buffer{data.data(), data.size()};
+ REQUIRE(buffer.capacity() == 128);
+ REQUIRE(buffer.committed() == 128);
+}
+
+TEST_CASE("Create buffer from existing data with good alignment and committed value works") {
+ std::array<unsigned char, 128> data;
+
+ osmium::memory::Buffer buffer{data.data(), data.size(), 32};
+ REQUIRE(buffer.capacity() == 128);
+ REQUIRE(buffer.committed() == 32);
+ REQUIRE(buffer.written() == 32);
+}
+
+TEST_CASE("Create buffer from existing data with bad alignment fails") {
+ std::array<unsigned char, 128> data;
+
+ const auto l1 = [&](){
+ osmium::memory::Buffer buffer{data.data(), 127};
+ };
+
+ const auto l2 = [&](){
+ osmium::memory::Buffer buffer{data.data(), 127, 120};
+ };
+
+ const auto l3 = [&](){
+ osmium::memory::Buffer buffer{data.data(), 128, 127};
+ };
+
+ const auto l4 = [&](){
+ osmium::memory::Buffer buffer{data.data(), 32, 128};
+ };
+
+ REQUIRE_THROWS_AS(l1(), const std::invalid_argument&);
+ REQUIRE_THROWS_AS(l2(), const std::invalid_argument&);
+ REQUIRE_THROWS_AS(l3(), const std::invalid_argument&);
+ REQUIRE_THROWS_AS(l4(), const std::invalid_argument&);
+}
+
diff --git a/test/t/memory/test_buffer_node.cpp b/test/t/memory/test_buffer_node.cpp
index 040cbb8..19718e7 100644
--- a/test/t/memory/test_buffer_node.cpp
+++ b/test/t/memory/test_buffer_node.cpp
@@ -36,7 +36,7 @@ void check_node_2(const osmium::Node& node) {
REQUIRE(osmium::item_type::tag_list == item.type());
}
- REQUIRE(!node.tags().empty());
+ REQUIRE_FALSE(node.tags().empty());
REQUIRE(2 == std::distance(node.tags().begin(), node.tags().end()));
int n = 0;
diff --git a/test/t/memory/test_callback_buffer.cpp b/test/t/memory/test_callback_buffer.cpp
new file mode 100644
index 0000000..3e94a40
--- /dev/null
+++ b/test/t/memory/test_callback_buffer.cpp
@@ -0,0 +1,101 @@
+#include "catch.hpp"
+
+#include <iterator>
+
+#include <osmium/builder/attr.hpp>
+#include <osmium/memory/callback_buffer.hpp>
+
+using namespace osmium::builder::attr;
+
+TEST_CASE("Callback buffer") {
+ osmium::memory::CallbackBuffer cb;
+
+ REQUIRE(cb.buffer().committed() == 0);
+
+ osmium::builder::add_node(cb.buffer(), _id(1));
+ osmium::builder::add_node(cb.buffer(), _id(2));
+ osmium::builder::add_node(cb.buffer(), _id(3));
+
+ auto c = cb.buffer().committed();
+ REQUIRE(c > 0);
+
+ REQUIRE(std::distance(cb.buffer().begin(), cb.buffer().end()) == 3);
+ auto buffer = cb.read();
+
+ REQUIRE(cb.buffer().committed() == 0);
+ REQUIRE(buffer.committed() == c);
+ REQUIRE(std::distance(cb.buffer().begin(), cb.buffer().end()) == 0);
+
+ // no callback defined, so nothing will happen
+ cb.flush();
+}
+
+TEST_CASE("Callback buffer with callback triggering every time") {
+ int run = 0;
+
+ osmium::memory::CallbackBuffer cb{[&](osmium::memory::Buffer&& buffer){
+ REQUIRE(buffer.committed() > 0);
+ REQUIRE(std::distance(buffer.begin(), buffer.end()) == 1);
+ ++run;
+ }, 1000, 10};
+
+ osmium::builder::add_node(cb.buffer(), _id(1));
+ REQUIRE(cb.buffer().committed() > 10);
+ cb.possibly_flush();
+ osmium::builder::add_node(cb.buffer(), _id(2));
+ REQUIRE(cb.buffer().committed() > 10);
+ cb.possibly_flush();
+ osmium::builder::add_node(cb.buffer(), _id(3));
+ REQUIRE(cb.buffer().committed() > 10);
+ cb.possibly_flush();
+
+ REQUIRE(run == 3);
+ REQUIRE(std::distance(cb.buffer().begin(), cb.buffer().end()) == 0);
+}
+
+TEST_CASE("Callback buffer with callback triggering sometimes") {
+ int run = 0;
+
+ osmium::memory::CallbackBuffer cb{[&](osmium::memory::Buffer&& buffer){
+ REQUIRE(buffer.committed() > 0);
+ ++run;
+ }, 1000, 100};
+
+ osmium::builder::add_node(cb.buffer(), _id(1));
+ REQUIRE(cb.buffer().committed() < 100);
+ cb.possibly_flush();
+ osmium::builder::add_node(cb.buffer(), _id(2));
+ cb.possibly_flush();
+ osmium::builder::add_node(cb.buffer(), _id(3));
+ cb.possibly_flush();
+
+ REQUIRE(run < 3);
+}
+
+TEST_CASE("Callback buffer with callback set later") {
+ int run = 0;
+
+ osmium::memory::CallbackBuffer cb{1000, 10};
+
+ osmium::builder::add_node(cb.buffer(), _id(1));
+ cb.possibly_flush();
+ osmium::builder::add_node(cb.buffer(), _id(2));
+ cb.possibly_flush();
+ osmium::builder::add_node(cb.buffer(), _id(3));
+
+ cb.set_callback([&](osmium::memory::Buffer&& buffer){
+ REQUIRE(buffer.committed() > 0);
+ REQUIRE(std::distance(buffer.begin(), buffer.end()) == 3);
+ ++run;
+ });
+
+ REQUIRE(std::distance(cb.buffer().begin(), cb.buffer().end()) == 3);
+
+ cb.possibly_flush();
+
+ REQUIRE(std::distance(cb.buffer().begin(), cb.buffer().end()) == 0);
+
+ REQUIRE(run == 1);
+}
+
+
diff --git a/test/t/memory/test_item.cpp b/test/t/memory/test_item.cpp
new file mode 100644
index 0000000..a81003d
--- /dev/null
+++ b/test/t/memory/test_item.cpp
@@ -0,0 +1,25 @@
+#include "catch.hpp"
+
+#include <osmium/memory/item.hpp>
+
+TEST_CASE("padded length") {
+ REQUIRE(osmium::memory::padded_length(0) == 0);
+ REQUIRE(osmium::memory::padded_length(1) == 8);
+ REQUIRE(osmium::memory::padded_length(2) == 8);
+ REQUIRE(osmium::memory::padded_length(7) == 8);
+ REQUIRE(osmium::memory::padded_length(8) == 8);
+ REQUIRE(osmium::memory::padded_length(9) == 16);
+
+ REQUIRE(osmium::memory::padded_length(2147483647) == 2147483648);
+ REQUIRE(osmium::memory::padded_length(2147483648) == 2147483648);
+ REQUIRE(osmium::memory::padded_length(2147483650) == 2147483656);
+
+ REQUIRE(osmium::memory::padded_length(4294967295) == 4294967296);
+ REQUIRE(osmium::memory::padded_length(4294967296) == 4294967296);
+ REQUIRE(osmium::memory::padded_length(4294967297) == 4294967304);
+
+ REQUIRE(osmium::memory::padded_length(7999999999) == 8000000000);
+ REQUIRE(osmium::memory::padded_length(8000000000) == 8000000000);
+ REQUIRE(osmium::memory::padded_length(8000000001) == 8000000008);
+}
+
diff --git a/test/t/osm/test_area.cpp b/test/t/osm/test_area.cpp
index c964dbb..4451477 100644
--- a/test/t/osm/test_area.cpp
+++ b/test/t/osm/test_area.cpp
@@ -75,7 +75,7 @@ TEST_CASE("Build area") {
crc32.update(area);
REQUIRE(crc32().checksum() == 0x2b2b7fa0);
- osmium::Box envelope = area.envelope();
+ const osmium::Box envelope = area.envelope();
REQUIRE(envelope.bottom_left().lon() == Approx(3.2));
REQUIRE(envelope.bottom_left().lat() == Approx(4.2));
REQUIRE(envelope.top_right().lon() == Approx(3.6));
diff --git a/test/t/osm/test_box.cpp b/test/t/osm/test_box.cpp
index 2b7fb3d..179ae09 100644
--- a/test/t/osm/test_box.cpp
+++ b/test/t/osm/test_box.cpp
@@ -8,127 +8,165 @@
#include <osmium/osm/crc.hpp>
#include <osmium/geom/relations.hpp>
-TEST_CASE("Starting with default constructed box") {
+TEST_CASE("Default constructor creates invalid box") {
+ const osmium::Box b;
+ REQUIRE_FALSE(b);
+ REQUIRE_FALSE(b.bottom_left());
+ REQUIRE_FALSE(b.top_right());
+ REQUIRE_THROWS_AS(b.size(), const osmium::invalid_location&);
+}
+
+TEST_CASE("Extend box with undefined") {
+ osmium::Box b;
+
+ REQUIRE_FALSE(b);
+ b.extend(osmium::Location{});
+ REQUIRE_FALSE(b);
+ REQUIRE_FALSE(b.bottom_left());
+ REQUIRE_FALSE(b.top_right());
+}
+
+TEST_CASE("Extend box with invalid") {
osmium::Box b;
- SECTION("default constructor creates invalid box") {
- REQUIRE(!b);
- REQUIRE(!b.bottom_left());
- REQUIRE(!b.top_right());
- REQUIRE_THROWS_AS(b.size(), osmium::invalid_location);
- }
-
- SECTION("extend with undefined") {
- REQUIRE(!b);
- b.extend(osmium::Location{});
- REQUIRE(!b);
- REQUIRE(!b.bottom_left());
- REQUIRE(!b.top_right());
- }
-
- SECTION("extend with invalid") {
- REQUIRE(!b);
- b.extend(osmium::Location{200.0, 100.0});
- REQUIRE(!b);
- REQUIRE(!b.bottom_left());
- REQUIRE(!b.top_right());
- }
-
- SECTION("extend with valid") {
- osmium::Location loc1 { 1.2, 3.4 };
- b.extend(loc1);
- REQUIRE(!!b);
- REQUIRE(!!b.bottom_left());
- REQUIRE(!!b.top_right());
- REQUIRE(b.contains(loc1));
-
- osmium::Location loc2 { 3.4, 4.5 };
- osmium::Location loc3 { 5.6, 7.8 };
-
- b.extend(loc2);
- b.extend(loc3);
- REQUIRE(b.bottom_left() == osmium::Location(1.2, 3.4));
- REQUIRE(b.top_right() == osmium::Location(5.6, 7.8));
-
- // extend with undefined doesn't change anything
- b.extend(osmium::Location());
- REQUIRE(b.bottom_left() == osmium::Location(1.2, 3.4));
- REQUIRE(b.top_right() == osmium::Location(5.6, 7.8));
-
- REQUIRE(b.contains(loc1));
- REQUIRE(b.contains(loc2));
- REQUIRE(b.contains(loc3));
-
- osmium::CRC<boost::crc_32_type> crc32;
- crc32.update(b);
- REQUIRE(crc32().checksum() == 0xd381a838);
- }
-
- SECTION("output defined") {
- b.extend(osmium::Location(1.2, 3.4));
- b.extend(osmium::Location(5.6, 7.8));
- std::stringstream out;
- out << b;
- REQUIRE(out.str() == "(1.2,3.4,5.6,7.8)");
- REQUIRE(b.size() == Approx(19.36).epsilon(0.000001));
- }
-
- SECTION("output undefined") {
- std::stringstream out;
- out << b;
- REQUIRE(out.str() == "(undefined)");
- }
-
- SECTION("output undefined bottom left") {
- b.top_right() = osmium::Location(1.2, 3.4);
- std::stringstream out;
- out << b;
- REQUIRE(out.str() == "(undefined)");
- }
-
- SECTION("output undefined top right") {
- b.bottom_left() = osmium::Location(1.2, 3.4);
- std::stringstream out;
- out << b;
- REQUIRE(out.str() == "(undefined)");
- }
+ REQUIRE_FALSE(b);
+ b.extend(osmium::Location{200.0, 100.0});
+ REQUIRE_FALSE(b);
+ REQUIRE_FALSE(b.bottom_left());
+ REQUIRE_FALSE(b.top_right());
+}
+TEST_CASE("Extend box with valid") {
+ osmium::Box b;
+
+ const osmium::Location loc1{1.2, 3.4};
+ b.extend(loc1);
+ REQUIRE(!!b);
+ REQUIRE(!!b.bottom_left());
+ REQUIRE(!!b.top_right());
+ REQUIRE(b.contains(loc1));
+
+ const osmium::Location loc2{3.4, 4.5};
+ const osmium::Location loc3{5.6, 7.8};
+
+ b.extend(loc2);
+ b.extend(loc3);
+ REQUIRE(b.bottom_left() == osmium::Location(1.2, 3.4));
+ REQUIRE(b.top_right() == osmium::Location(5.6, 7.8));
+
+ // extend with undefined doesn't change anything
+ b.extend(osmium::Location{});
+ REQUIRE(b.bottom_left() == osmium::Location(1.2, 3.4));
+ REQUIRE(b.top_right() == osmium::Location(5.6, 7.8));
+
+ REQUIRE(b.contains(loc1));
+ REQUIRE(b.contains(loc2));
+ REQUIRE(b.contains(loc3));
+
+ osmium::CRC<boost::crc_32_type> crc32;
+ crc32.update(b);
+ REQUIRE(crc32().checksum() == 0xd381a838);
+}
+
+TEST_CASE("Output of defined Box") {
+ osmium::Box b;
+
+ b.extend(osmium::Location{1.2, 3.4});
+ b.extend(osmium::Location{5.6, 7.8});
+
+ std::stringstream out;
+ out << b;
+
+ REQUIRE(out.str() == "(1.2,3.4,5.6,7.8)");
+ REQUIRE(b.size() == Approx(19.36).epsilon(0.000001));
+}
+
+TEST_CASE("Output of undefined Box") {
+ const osmium::Box b;
+
+ std::stringstream out;
+ out << b;
+
+ REQUIRE(out.str() == "(undefined)");
+}
+
+TEST_CASE("Output of undefined Box (bottom left)") {
+ osmium::Box b;
+
+ b.top_right() = osmium::Location(1.2, 3.4);
+ std::stringstream out;
+ out << b;
+ REQUIRE(out.str() == "(undefined)");
+}
+
+TEST_CASE("Output of undefined Box (top right)") {
+ osmium::Box b;
+
+ b.bottom_left() = osmium::Location(1.2, 3.4);
+ std::stringstream out;
+ out << b;
+ REQUIRE(out.str() == "(undefined)");
}
TEST_CASE("Create box from locations") {
- osmium::Box b{osmium::Location{1.23, 2.34}, osmium::Location{3.45, 4.56}};
+ const osmium::Box b{osmium::Location{1.23, 2.34}, osmium::Location{3.45, 4.56}};
REQUIRE(!!b);
REQUIRE(b.bottom_left() == (osmium::Location{1.23, 2.34}));
REQUIRE(b.top_right() == (osmium::Location{3.45, 4.56}));
}
TEST_CASE("Create box from doubles") {
- osmium::Box b{1.23, 2.34, 3.45, 4.56};
+ const osmium::Box b{1.23, 2.34, 3.45, 4.56};
REQUIRE(!!b);
REQUIRE(b.bottom_left() == (osmium::Location{1.23, 2.34}));
REQUIRE(b.top_right() == (osmium::Location{3.45, 4.56}));
}
-TEST_CASE("Relationship between boxes") {
+TEST_CASE("Relationship between boxes: contains") {
+ osmium::Box outer;
+ outer.extend(osmium::Location{1, 1});
+ outer.extend(osmium::Location{10, 10});
+
+ osmium::Box inner;
+ inner.extend(osmium::Location{2, 2});
+ inner.extend(osmium::Location{4, 4});
+
+ osmium::Box overlap;
+ overlap.extend(osmium::Location{3, 3});
+ overlap.extend(osmium::Location{5, 5});
+ REQUIRE( osmium::geom::contains(inner, outer));
+ REQUIRE_FALSE(osmium::geom::contains(outer, inner));
+
+ REQUIRE_FALSE(osmium::geom::contains(overlap, inner));
+ REQUIRE_FALSE(osmium::geom::contains(inner, overlap));
+}
+
+TEST_CASE("Relationship between boxes: overlaps") {
osmium::Box outer;
- outer.extend(osmium::Location(1, 1));
- outer.extend(osmium::Location(10, 10));
+ outer.extend(osmium::Location{1, 1});
+ outer.extend(osmium::Location{10, 10});
osmium::Box inner;
- inner.extend(osmium::Location(2, 2));
- inner.extend(osmium::Location(4, 4));
+ inner.extend(osmium::Location{2, 2});
+ inner.extend(osmium::Location{4, 4});
osmium::Box overlap;
- overlap.extend(osmium::Location(3, 3));
- overlap.extend(osmium::Location(5, 5));
+ overlap.extend(osmium::Location{3, 3});
+ overlap.extend(osmium::Location{5, 5});
+
+ osmium::Box outside;
+ overlap.extend(osmium::Location{30, 30});
+ overlap.extend(osmium::Location{50, 50});
- REQUIRE( osmium::geom::contains(inner, outer));
- REQUIRE(!osmium::geom::contains(outer, inner));
+ REQUIRE(osmium::geom::overlaps(inner, outer));
+ REQUIRE(osmium::geom::overlaps(outer, inner));
- REQUIRE(!osmium::geom::contains(overlap, inner));
- REQUIRE(!osmium::geom::contains(inner, overlap));
+ REQUIRE(osmium::geom::overlaps(overlap, inner));
+ REQUIRE(osmium::geom::overlaps(inner, overlap));
+ REQUIRE_FALSE(osmium::geom::overlaps(outside, inner));
+ REQUIRE_FALSE(osmium::geom::overlaps(inner, outside));
}
diff --git a/test/t/osm/test_changeset.cpp b/test/t/osm/test_changeset.cpp
index 9be8fbb..0c1fc42 100644
--- a/test/t/osm/test_changeset.cpp
+++ b/test/t/osm/test_changeset.cpp
@@ -38,7 +38,7 @@ TEST_CASE("Build changeset") {
crc32.update(cs1);
REQUIRE(crc32().checksum() == 0x502e8c0e);
- auto pos = osmium::builder::add_changeset(buffer,
+ const auto pos = osmium::builder::add_changeset(buffer,
_cid(43),
_created_at(time_t(120)),
_num_changes(21),
diff --git a/test/t/osm/test_crc.cpp b/test/t/osm/test_crc.cpp
index 253c217..97c3c4c 100644
--- a/test/t/osm/test_crc.cpp
+++ b/test/t/osm/test_crc.cpp
@@ -4,65 +4,75 @@
#include <osmium/osm/crc.hpp>
-TEST_CASE("CRC of basic datatypes") {
+TEST_CASE("CRC of bool") {
+ osmium::CRC<boost::crc_32_type> crc32;
+
+ crc32.update_bool(true);
+ crc32.update_bool(false);
+ REQUIRE(crc32().checksum() == 0x58c223be);
+}
+
+TEST_CASE("CRC of char") {
osmium::CRC<boost::crc_32_type> crc32;
- SECTION("Bool") {
- crc32.update_bool(true);
- crc32.update_bool(false);
+ crc32.update_int8('x');
+ crc32.update_int8('y');
- REQUIRE(crc32().checksum() == 0x58c223be);
- }
+ REQUIRE(crc32().checksum() == 0x8fe62899);
+}
- SECTION("Char") {
- crc32.update_int8('x');
- crc32.update_int8('y');
+TEST_CASE("CRC of int16") {
+ osmium::CRC<boost::crc_32_type> crc32;
- REQUIRE(crc32().checksum() == 0x8fe62899);
- }
+ crc32.update_int16(0x0123U);
+ crc32.update_int16(0x1234U);
- SECTION("Int16") {
- crc32.update_int16(0x0123U);
- crc32.update_int16(0x1234U);
+ REQUIRE(crc32().checksum() == 0xda923744);
+}
- REQUIRE(crc32().checksum() == 0xda923744);
- }
+TEST_CASE("CRC of int32") {
+ osmium::CRC<boost::crc_32_type> crc32;
- SECTION("Int32") {
- crc32.update_int32(0x01234567UL);
- crc32.update_int32(0x12345678UL);
+ crc32.update_int32(0x01234567UL);
+ crc32.update_int32(0x12345678UL);
- REQUIRE(crc32().checksum() == 0x9b4e2af3);
- }
+ REQUIRE(crc32().checksum() == 0x9b4e2af3);
+}
- SECTION("Int64") {
- crc32.update_int64(0x0123456789abcdefULL);
- crc32.update_int64(0x123456789abcdef0ULL);
+TEST_CASE("CRC of int64") {
+ osmium::CRC<boost::crc_32_type> crc32;
- REQUIRE(crc32().checksum() == 0x6d8b7267);
- }
+ crc32.update_int64(0x0123456789abcdefULL);
+ crc32.update_int64(0x123456789abcdef0ULL);
- SECTION("String") {
- const char* str = "foobar";
- crc32.update_string(str);
+ REQUIRE(crc32().checksum() == 0x6d8b7267);
+}
- REQUIRE(crc32().checksum() == 0x9ef61f95);
- }
+TEST_CASE("CRC of string") {
+ osmium::CRC<boost::crc_32_type> crc32;
- SECTION("Timestamp") {
- osmium::Timestamp t("2015-07-12T13:10:46Z");
- crc32.update(t);
+ const char* str = "foobar";
+ crc32.update_string(str);
- REQUIRE(crc32().checksum() == 0x58a29d7);
- }
+ REQUIRE(crc32().checksum() == 0x9ef61f95);
+}
+
+TEST_CASE("CRC of Timestamp") {
+ osmium::CRC<boost::crc_32_type> crc32;
- SECTION("Location") {
- osmium::Location loc { 3.46, 2.001 };
- crc32.update(loc);
+ const osmium::Timestamp t{"2015-07-12T13:10:46Z"};
+ crc32.update(t);
+
+ REQUIRE(crc32().checksum() == 0x58a29d7);
+}
+
+TEST_CASE("CRC of Location") {
+ osmium::CRC<boost::crc_32_type> crc32;
- REQUIRE(crc32().checksum() == 0xddee042c);
- }
+ const osmium::Location loc{3.46, 2.001};
+ crc32.update(loc);
+ REQUIRE(crc32().checksum() == 0xddee042c);
}
diff --git a/test/t/osm/test_location.cpp b/test/t/osm/test_location.cpp
index 0adfc95..28cf16e 100644
--- a/test/t/osm/test_location.cpp
+++ b/test/t/osm/test_location.cpp
@@ -1,155 +1,156 @@
#include "catch.hpp"
+#include <limits>
#include <sstream>
#include <type_traits>
#include <osmium/osm/location.hpp>
-TEST_CASE("Location") {
-
// fails on MSVC and doesn't really matter
// static_assert(std::is_literal_type<osmium::Location>::value, "osmium::Location not literal type");
- SECTION("instantiation_with_default_parameters") {
- osmium::Location loc;
- REQUIRE(!loc);
- REQUIRE_THROWS_AS(loc.lon(), osmium::invalid_location);
- REQUIRE_THROWS_AS(loc.lat(), osmium::invalid_location);
- }
-
- SECTION("instantiation_with_double_parameters") {
- osmium::Location loc1(1.2, 4.5);
- REQUIRE(!!loc1);
- REQUIRE(12000000 == loc1.x());
- REQUIRE(45000000 == loc1.y());
- REQUIRE(1.2 == loc1.lon());
- REQUIRE(4.5 == loc1.lat());
-
- osmium::Location loc2(loc1);
- REQUIRE(4.5 == loc2.lat());
-
- osmium::Location loc3 = loc1;
- REQUIRE(4.5 == loc3.lat());
- }
+TEST_CASE("Location instantiation with default parameters") {
+ const osmium::Location loc;
+ REQUIRE_FALSE(loc);
+ REQUIRE_FALSE(loc.is_defined());
+ REQUIRE(loc.is_undefined());
+ REQUIRE_THROWS_AS(loc.lon(), const osmium::invalid_location&);
+ REQUIRE_THROWS_AS(loc.lat(), const osmium::invalid_location&);
+}
- SECTION("instantiation_with_double_parameters_constructor_with_universal_initializer") {
- osmium::Location loc { 2.2, 3.3 };
- REQUIRE(2.2 == loc.lon());
- REQUIRE(3.3 == loc.lat());
- }
+TEST_CASE("Location instantiation with double parameters") {
+ const osmium::Location loc1{1.2, 4.5};
+ REQUIRE(bool(loc1));
+ REQUIRE(loc1.is_defined());
+ REQUIRE_FALSE(loc1.is_undefined());
+ REQUIRE(12000000 == loc1.x());
+ REQUIRE(45000000 == loc1.y());
+ REQUIRE(1.2 == loc1.lon());
+ REQUIRE(4.5 == loc1.lat());
+
+ const osmium::Location loc2{loc1};
+ REQUIRE(4.5 == loc2.lat());
+
+ const osmium::Location loc3 = loc1;
+ REQUIRE(4.5 == loc3.lat());
+}
- SECTION("instantiation_with_double_parameters_constructor_with_initializer_list") {
- osmium::Location loc({ 4.4, 5.5 });
- REQUIRE(4.4 == loc.lon());
- REQUIRE(5.5 == loc.lat());
- }
+TEST_CASE("Location instantiation with double parameters constructor with universal initializer") {
+ const osmium::Location loc{2.2, 3.3};
+ REQUIRE(2.2 == loc.lon());
+ REQUIRE(3.3 == loc.lat());
+}
- SECTION("instantiation_with_double_parameters_operator_equal") {
- osmium::Location loc = { 5.5, 6.6 };
- REQUIRE(5.5 == loc.lon());
- REQUIRE(6.6 == loc.lat());
- }
+TEST_CASE("Location instantiation with double parameters constructor with initializer list") {
+ const osmium::Location loc({4.4, 5.5});
+ REQUIRE(4.4 == loc.lon());
+ REQUIRE(5.5 == loc.lat());
+}
- SECTION("equality") {
- osmium::Location loc1(1.2, 4.5);
- osmium::Location loc2(1.2, 4.5);
- osmium::Location loc3(1.5, 1.5);
- REQUIRE(loc1 == loc2);
- REQUIRE(loc1 != loc3);
- }
+TEST_CASE("Location instantiation with double parameters operator equal") {
+ const osmium::Location loc = {5.5, 6.6};
+ REQUIRE(5.5 == loc.lon());
+ REQUIRE(6.6 == loc.lat());
+}
- SECTION("order") {
- REQUIRE(osmium::Location(-1.2, 10.0) < osmium::Location(1.2, 10.0));
- REQUIRE(osmium::Location(1.2, 10.0) > osmium::Location(-1.2, 10.0));
+TEST_CASE("Location equality") {
+ const osmium::Location loc1{1.2, 4.5};
+ const osmium::Location loc2{1.2, 4.5};
+ const osmium::Location loc3{1.5, 1.5};
+ REQUIRE(loc1 == loc2);
+ REQUIRE(loc1 != loc3);
+}
- REQUIRE(osmium::Location(10.2, 20.0) < osmium::Location(11.2, 20.2));
- REQUIRE(osmium::Location(10.2, 20.2) < osmium::Location(11.2, 20.0));
- REQUIRE(osmium::Location(11.2, 20.2) > osmium::Location(10.2, 20.0));
- }
+TEST_CASE("Location order") {
+ REQUIRE(osmium::Location(-1.2, 10.0) < osmium::Location(1.2, 10.0));
+ REQUIRE(osmium::Location(1.2, 10.0) > osmium::Location(-1.2, 10.0));
- SECTION("validity") {
- REQUIRE(osmium::Location(0.0, 0.0).valid());
- REQUIRE(osmium::Location(1.2, 4.5).valid());
- REQUIRE(osmium::Location(-1.2, 4.5).valid());
- REQUIRE(osmium::Location(-180.0, -90.0).valid());
- REQUIRE(osmium::Location(180.0, -90.0).valid());
- REQUIRE(osmium::Location(-180.0, 90.0).valid());
- REQUIRE(osmium::Location(180.0, 90.0).valid());
-
- REQUIRE(!osmium::Location(200.0, 4.5).valid());
- REQUIRE(!osmium::Location(-1.2, -100.0).valid());
- REQUIRE(!osmium::Location(-180.0, 90.005).valid());
- }
+ REQUIRE(osmium::Location(10.2, 20.0) < osmium::Location(11.2, 20.2));
+ REQUIRE(osmium::Location(10.2, 20.2) < osmium::Location(11.2, 20.0));
+ REQUIRE(osmium::Location(11.2, 20.2) > osmium::Location(10.2, 20.0));
+}
+TEST_CASE("Location validity") {
+ REQUIRE(osmium::Location(0.0, 0.0).valid());
+ REQUIRE(osmium::Location(1.2, 4.5).valid());
+ REQUIRE(osmium::Location(-1.2, 4.5).valid());
+ REQUIRE(osmium::Location(-180.0, -90.0).valid());
+ REQUIRE(osmium::Location(180.0, -90.0).valid());
+ REQUIRE(osmium::Location(-180.0, 90.0).valid());
+ REQUIRE(osmium::Location(180.0, 90.0).valid());
+
+ REQUIRE_FALSE(osmium::Location(200.0, 4.5).valid());
+ REQUIRE_FALSE(osmium::Location(-1.2, -100.0).valid());
+ REQUIRE_FALSE(osmium::Location(-180.0, 90.005).valid());
+}
- SECTION("output_to_iterator_comma_separator") {
- char buffer[100];
- osmium::Location loc(-3.2, 47.3);
- *loc.as_string(buffer, ',') = 0;
- REQUIRE(std::string("-3.2,47.3") == buffer);
- }
- SECTION("output_to_iterator_space_separator") {
- char buffer[100];
- osmium::Location loc(0.0, 7.0);
- *loc.as_string(buffer, ' ') = 0;
- REQUIRE(std::string("0 7") == buffer);
- }
+TEST_CASE("Location output to iterator comma separator") {
+ char buffer[100];
+ const osmium::Location loc{-3.2, 47.3};
+ *loc.as_string(buffer, ',') = 0;
+ REQUIRE(std::string("-3.2,47.3") == buffer);
+}
- SECTION("output_to_iterator_check_precision") {
- char buffer[100];
- osmium::Location loc(-179.9999999, -90.0);
- *loc.as_string(buffer, ' ') = 0;
- REQUIRE(std::string("-179.9999999 -90") == buffer);
- }
+TEST_CASE("Location output to iterator space separator") {
+ char buffer[100];
+ const osmium::Location loc{0.0, 7.0};
+ *loc.as_string(buffer, ' ') = 0;
+ REQUIRE(std::string("0 7") == buffer);
+}
- SECTION("output_to_iterator_undefined_location") {
- char buffer[100];
- osmium::Location loc;
- REQUIRE_THROWS_AS(loc.as_string(buffer, ','), osmium::invalid_location);
- }
+TEST_CASE("Location output to iterator check precision") {
+ char buffer[100];
+ const osmium::Location loc{-179.9999999, -90.0};
+ *loc.as_string(buffer, ' ') = 0;
+ REQUIRE(std::string("-179.9999999 -90") == buffer);
+}
- SECTION("output_to_string_comman_separator") {
- std::string s;
- osmium::Location loc(-3.2, 47.3);
- loc.as_string(std::back_inserter(s), ',');
- REQUIRE(s == "-3.2,47.3");
- }
+TEST_CASE("Location output to iterator undefined location") {
+ char buffer[100];
+ const osmium::Location loc;
+ REQUIRE_THROWS_AS(loc.as_string(buffer, ','), const osmium::invalid_location&);
+}
- SECTION("output_to_string_space_separator") {
- std::string s;
- osmium::Location loc(0.0, 7.0);
- loc.as_string(std::back_inserter(s), ' ');
- REQUIRE(s == "0 7");
- }
+TEST_CASE("Location output to string comman separator") {
+ std::string s;
+ const osmium::Location loc{-3.2, 47.3};
+ loc.as_string(std::back_inserter(s), ',');
+ REQUIRE(s == "-3.2,47.3");
+}
- SECTION("output_to_string_check_precision") {
- std::string s;
- osmium::Location loc(-179.9999999, -90.0);
- loc.as_string(std::back_inserter(s), ' ');
- REQUIRE(s == "-179.9999999 -90");
- }
+TEST_CASE("Location output to string space separator") {
+ std::string s;
+ const osmium::Location loc{0.0, 7.0};
+ loc.as_string(std::back_inserter(s), ' ');
+ REQUIRE(s == "0 7");
+}
- SECTION("output_to_string_undefined_location") {
- std::string s;
- osmium::Location loc;
- REQUIRE_THROWS_AS(loc.as_string(std::back_inserter(s), ','), osmium::invalid_location);
- }
+TEST_CASE("Location output to string check precision") {
+ std::string s;
+ const osmium::Location loc{-179.9999999, -90.0};
+ loc.as_string(std::back_inserter(s), ' ');
+ REQUIRE(s == "-179.9999999 -90");
+}
- SECTION("output_defined") {
- osmium::Location p(-3.20, 47.30);
- std::stringstream out;
- out << p;
- REQUIRE(out.str() == "(-3.2,47.3)");
- }
+TEST_CASE("Location output to string undefined location") {
+ std::string s;
+ const osmium::Location loc;
+ REQUIRE_THROWS_AS(loc.as_string(std::back_inserter(s), ','), const osmium::invalid_location&);
+}
- SECTION("output_undefined") {
- osmium::Location p;
- std::stringstream out;
- out << p;
- REQUIRE(out.str() == "(undefined,undefined)");
- }
+TEST_CASE("Location output defined") {
+ const osmium::Location loc{-3.20, 47.30};
+ std::stringstream out;
+ out << loc;
+ REQUIRE(out.str() == "(-3.2,47.3)");
+}
+TEST_CASE("Location output undefined") {
+ const osmium::Location loc;
+ std::stringstream out;
+ out << loc;
+ REQUIRE(out.str() == "(undefined,undefined)");
}
TEST_CASE("Location hash") {
@@ -188,10 +189,10 @@ void F(const char* s) {
strm += s;
const char* x = strm.c_str();
const char** data = &x;
- REQUIRE_THROWS_AS(osmium::detail::string_to_location_coordinate(data), osmium::invalid_location);
+ REQUIRE_THROWS_AS(osmium::detail::string_to_location_coordinate(data), const osmium::invalid_location&);
++x;
data = &x;
- REQUIRE_THROWS_AS(osmium::detail::string_to_location_coordinate(data), osmium::invalid_location);
+ REQUIRE_THROWS_AS(osmium::detail::string_to_location_coordinate(data), const osmium::invalid_location&);
}
TEST_CASE("Parsing coordinates from strings") {
@@ -260,6 +261,7 @@ TEST_CASE("Parsing coordinates from strings") {
C("179.9999999", 1799999999);
C("179.99999999", 1800000000);
C("200.123", 2001230000);
+ C("214.7483647", 2147483647);
C("8.109E-4" , 8109);
C("8.1090E-4" , 8109);
@@ -332,6 +334,12 @@ TEST_CASE("Parsing coordinates from strings") {
C("1.1e2:", 1100000000, ":");
}
+TEST_CASE("Parsing min coordinate from string") {
+ const char* minval = "-214.7483648";
+ const char** data = &minval;
+ REQUIRE(osmium::detail::string_to_location_coordinate(data) == std::numeric_limits<int32_t>::min());
+}
+
TEST_CASE("Writing zero coordinate into string") {
std::string buffer;
osmium::detail::append_location_coordinate_to_string(std::back_inserter(buffer), 0);
@@ -369,20 +377,41 @@ TEST_CASE("Writing coordinate into string") {
CW( 40101010, "4.010101");
CW( 494561234, "49.4561234");
CW(1799999999, "179.9999999");
+
+ CW(2147483647, "214.7483647");
+}
+
+TEST_CASE("Writing min coordinate into string") {
+ std::string buffer;
+
+ osmium::detail::append_location_coordinate_to_string(std::back_inserter(buffer), std::numeric_limits<int32_t>::min());
+ REQUIRE(buffer == "-214.7483648");
}
TEST_CASE("set lon/lat from string") {
osmium::Location loc;
+ REQUIRE(loc.is_undefined());
+ REQUIRE_FALSE(loc.is_defined());
+ REQUIRE_FALSE(loc.valid());
+
loc.set_lon("1.2");
+ REQUIRE_FALSE(loc.is_undefined());
+ REQUIRE(loc.is_defined());
+ REQUIRE_FALSE(loc.valid());
+
loc.set_lat("3.4");
+ REQUIRE_FALSE(loc.is_undefined());
+ REQUIRE(loc.is_defined());
+ REQUIRE(loc.valid());
+
REQUIRE(loc.lon() == Approx(1.2));
REQUIRE(loc.lat() == Approx(3.4));
}
TEST_CASE("set lon/lat from string with trailing characters") {
osmium::Location loc;
- REQUIRE_THROWS_AS(loc.set_lon("1.2x"), osmium::invalid_location);
- REQUIRE_THROWS_AS(loc.set_lat("3.4e1 "), osmium::invalid_location);
+ REQUIRE_THROWS_AS(loc.set_lon("1.2x"), const osmium::invalid_location&);
+ REQUIRE_THROWS_AS(loc.set_lat("3.4e1 "), const osmium::invalid_location&);
}
TEST_CASE("set lon/lat from string with trailing characters using partial") {
diff --git a/test/t/osm/test_node.cpp b/test/t/osm/test_node.cpp
index e5dbe8a..752e6af 100644
--- a/test/t/osm/test_node.cpp
+++ b/test/t/osm/test_node.cpp
@@ -133,7 +133,7 @@ TEST_CASE("Setting attributes from bad data on strings should fail") {
TEST_CASE("set large id") {
osmium::memory::Buffer buffer{10000};
- int64_t id = 3000000000l;
+ const int64_t id = 3000000000l;
osmium::builder::add_node(buffer, _id(id));
osmium::Node& node = buffer.get<osmium::Node>(0);
@@ -164,3 +164,26 @@ TEST_CASE("set tags on node") {
REQUIRE(std::string{"pub"} == node.get_value_by_key("amenity", "default"));
}
+TEST_CASE("Setting diff flags on node") {
+ osmium::memory::Buffer buffer{1000};
+
+ osmium::builder::add_node(buffer, _id(17));
+
+ osmium::Node& node = buffer.get<osmium::Node>(0);
+
+ REQUIRE(node.diff() == osmium::diff_indicator_type::none);
+ REQUIRE(node.diff_as_char() == '*');
+
+ node.set_diff(osmium::diff_indicator_type::left);
+ REQUIRE(node.diff() == osmium::diff_indicator_type::left);
+ REQUIRE(node.diff_as_char() == '-');
+
+ node.set_diff(osmium::diff_indicator_type::right);
+ REQUIRE(node.diff() == osmium::diff_indicator_type::right);
+ REQUIRE(node.diff_as_char() == '+');
+
+ node.set_diff(osmium::diff_indicator_type::both);
+ REQUIRE(node.diff() == osmium::diff_indicator_type::both);
+ REQUIRE(node.diff_as_char() == ' ');
+}
+
diff --git a/test/t/osm/test_node_ref.cpp b/test/t/osm/test_node_ref.cpp
index 28a28a5..3494d2a 100644
--- a/test/t/osm/test_node_ref.cpp
+++ b/test/t/osm/test_node_ref.cpp
@@ -6,30 +6,30 @@
#include <osmium/osm/node_ref_list.hpp>
TEST_CASE("Default construct a NodeRef") {
- osmium::NodeRef node_ref;
+ const osmium::NodeRef node_ref;
REQUIRE(node_ref.ref() == 0);
REQUIRE(node_ref.location() == osmium::Location{});
}
TEST_CASE("Construct a NodeRef with an id") {
- osmium::NodeRef node_ref{7};
+ const osmium::NodeRef node_ref{7};
REQUIRE(node_ref.ref() == 7);
}
TEST_CASE("Equality comparison fo NodeRefs") {
- osmium::NodeRef node_ref1{7, {1.2, 3.4}};
- osmium::NodeRef node_ref2{7, {1.4, 3.1}};
- osmium::NodeRef node_ref3{9, {1.2, 3.4}};
+ const osmium::NodeRef node_ref1{7, {1.2, 3.4}};
+ const osmium::NodeRef node_ref2{7, {1.4, 3.1}};
+ const osmium::NodeRef node_ref3{9, {1.2, 3.4}};
REQUIRE(node_ref1 == node_ref2);
REQUIRE(node_ref1 != node_ref3);
- REQUIRE(!osmium::location_equal()(node_ref1, node_ref2));
- REQUIRE(!osmium::location_equal()(node_ref2, node_ref3));
- REQUIRE(osmium::location_equal()(node_ref1, node_ref3));
+ REQUIRE_FALSE(osmium::location_equal()(node_ref1, node_ref2));
+ REQUIRE_FALSE(osmium::location_equal()(node_ref2, node_ref3));
+ REQUIRE( osmium::location_equal()(node_ref1, node_ref3));
}
TEST_CASE("Set location on a NodeRef") {
osmium::NodeRef node_ref{7};
- REQUIRE(!node_ref.location().valid());
+ REQUIRE_FALSE(node_ref.location().valid());
REQUIRE(node_ref.location() == osmium::Location());
node_ref.set_location(osmium::Location(13.5, -7.2));
REQUIRE(node_ref.location().lon() == 13.5);
@@ -37,10 +37,10 @@ TEST_CASE("Set location on a NodeRef") {
}
TEST_CASE("Ordering of NodeRefs") {
- osmium::NodeRef node_ref1{1, {1.0, 3.0}};
- osmium::NodeRef node_ref2{2, {1.4, 2.9}};
- osmium::NodeRef node_ref3{3, {1.2, 3.0}};
- osmium::NodeRef node_ref4{4, {1.2, 3.3}};
+ const osmium::NodeRef node_ref1{1, {1.0, 3.0}};
+ const osmium::NodeRef node_ref2{2, {1.4, 2.9}};
+ const osmium::NodeRef node_ref3{3, {1.2, 3.0}};
+ const osmium::NodeRef node_ref4{4, {1.2, 3.3}};
REQUIRE(node_ref1 < node_ref2);
REQUIRE(node_ref2 < node_ref3);
@@ -48,10 +48,10 @@ TEST_CASE("Ordering of NodeRefs") {
REQUIRE(node_ref1 >= node_ref1);
REQUIRE(osmium::location_less()(node_ref1, node_ref2));
- REQUIRE(!osmium::location_less()(node_ref2, node_ref3));
+ REQUIRE_FALSE(osmium::location_less()(node_ref2, node_ref3));
REQUIRE(osmium::location_less()(node_ref1, node_ref3));
REQUIRE(osmium::location_less()(node_ref3, node_ref4));
- REQUIRE(!osmium::location_less()(node_ref1, node_ref1));
+ REQUIRE_FALSE(osmium::location_less()(node_ref1, node_ref1));
}
TEST_CASE("WayNodeList") {
@@ -80,7 +80,7 @@ TEST_CASE("WayNodeList") {
REQUIRE(nrl.size() == 3);
REQUIRE(nrl[1].location() == osmium::Location(0.0, 1.0));
- nrl[1].set_location(osmium::Location(13.5, -7.2));
+ nrl[1].set_location(osmium::Location{13.5, -7.2});
REQUIRE(nrl[1].location() == osmium::Location(13.5, -7.2));
}
@@ -100,7 +100,7 @@ TEST_CASE("WayNodeList") {
REQUIRE(nrl.ends_have_same_id());
REQUIRE(nrl.ends_have_same_location());
- osmium::Box envelope = nrl.envelope();
+ const osmium::Box envelope = nrl.envelope();
REQUIRE(envelope.bottom_left().lon() == Approx(0));
REQUIRE(envelope.bottom_left().lat() == Approx(0));
REQUIRE(envelope.top_right().lon() == Approx(1));
diff --git a/test/t/osm/test_object_comparisons.cpp b/test/t/osm/test_object_comparisons.cpp
index 42bcbff..27ded91 100644
--- a/test/t/osm/test_object_comparisons.cpp
+++ b/test/t/osm/test_object_comparisons.cpp
@@ -11,6 +11,72 @@
using namespace osmium::builder::attr;
+TEST_CASE("Object ID comparisons") {
+ osmium::object_id_type a = 0;
+ osmium::object_id_type b = -1;
+ osmium::object_id_type c = -10;
+ osmium::object_id_type d = -11;
+ osmium::object_id_type e = 1;
+ osmium::object_id_type f = 11;
+ osmium::object_id_type g = 12;
+
+ REQUIRE_FALSE(osmium::id_order{}(a, a));
+ REQUIRE(osmium::id_order{}(a, b));
+ REQUIRE(osmium::id_order{}(a, c));
+ REQUIRE(osmium::id_order{}(a, d));
+ REQUIRE(osmium::id_order{}(a, e));
+ REQUIRE(osmium::id_order{}(a, f));
+ REQUIRE(osmium::id_order{}(a, g));
+
+ REQUIRE_FALSE(osmium::id_order{}(b, a));
+ REQUIRE_FALSE(osmium::id_order{}(b, b));
+ REQUIRE(osmium::id_order{}(b, c));
+ REQUIRE(osmium::id_order{}(b, d));
+ REQUIRE(osmium::id_order{}(b, e));
+ REQUIRE(osmium::id_order{}(b, f));
+ REQUIRE(osmium::id_order{}(b, g));
+
+ REQUIRE_FALSE(osmium::id_order{}(c, a));
+ REQUIRE_FALSE(osmium::id_order{}(c, b));
+ REQUIRE_FALSE(osmium::id_order{}(c, c));
+ REQUIRE(osmium::id_order{}(c, d));
+ REQUIRE(osmium::id_order{}(c, e));
+ REQUIRE(osmium::id_order{}(c, f));
+ REQUIRE(osmium::id_order{}(c, g));
+
+ REQUIRE_FALSE(osmium::id_order{}(d, a));
+ REQUIRE_FALSE(osmium::id_order{}(d, b));
+ REQUIRE_FALSE(osmium::id_order{}(d, c));
+ REQUIRE_FALSE(osmium::id_order{}(d, d));
+ REQUIRE(osmium::id_order{}(d, e));
+ REQUIRE(osmium::id_order{}(d, f));
+ REQUIRE(osmium::id_order{}(d, g));
+
+ REQUIRE_FALSE(osmium::id_order{}(e, a));
+ REQUIRE_FALSE(osmium::id_order{}(e, b));
+ REQUIRE_FALSE(osmium::id_order{}(e, c));
+ REQUIRE_FALSE(osmium::id_order{}(e, d));
+ REQUIRE_FALSE(osmium::id_order{}(e, e));
+ REQUIRE(osmium::id_order{}(e, f));
+ REQUIRE(osmium::id_order{}(e, g));
+
+ REQUIRE_FALSE(osmium::id_order{}(f, a));
+ REQUIRE_FALSE(osmium::id_order{}(f, b));
+ REQUIRE_FALSE(osmium::id_order{}(f, c));
+ REQUIRE_FALSE(osmium::id_order{}(f, d));
+ REQUIRE_FALSE(osmium::id_order{}(f, e));
+ REQUIRE_FALSE(osmium::id_order{}(f, f));
+ REQUIRE(osmium::id_order{}(f, g));
+
+ REQUIRE_FALSE(osmium::id_order{}(g, a));
+ REQUIRE_FALSE(osmium::id_order{}(g, b));
+ REQUIRE_FALSE(osmium::id_order{}(g, c));
+ REQUIRE_FALSE(osmium::id_order{}(g, d));
+ REQUIRE_FALSE(osmium::id_order{}(g, e));
+ REQUIRE_FALSE(osmium::id_order{}(g, f));
+ REQUIRE_FALSE(osmium::id_order{}(g, g));
+}
+
TEST_CASE("Node comparisons") {
osmium::memory::Buffer buffer(10 * 1000);
@@ -38,12 +104,12 @@ TEST_CASE("Node comparisons") {
REQUIRE_FALSE(nodes[0] > nodes[1]);
}
- SECTION("IDs are ordered by absolute value") {
+ SECTION("IDs are ordered by sign and then absolute value") {
nodes.emplace_back(buffer.get<osmium::Node>(osmium::builder::add_node(buffer, _id( 0))));
- nodes.emplace_back(buffer.get<osmium::Node>(osmium::builder::add_node(buffer, _id( 1))));
nodes.emplace_back(buffer.get<osmium::Node>(osmium::builder::add_node(buffer, _id( -1))));
- nodes.emplace_back(buffer.get<osmium::Node>(osmium::builder::add_node(buffer, _id( 10))));
nodes.emplace_back(buffer.get<osmium::Node>(osmium::builder::add_node(buffer, _id(-10))));
+ nodes.emplace_back(buffer.get<osmium::Node>(osmium::builder::add_node(buffer, _id( 1))));
+ nodes.emplace_back(buffer.get<osmium::Node>(osmium::builder::add_node(buffer, _id( 10))));
REQUIRE(std::is_sorted(nodes.cbegin(), nodes.cend()));
}
diff --git a/test/t/osm/test_timestamp.cpp b/test/t/osm/test_timestamp.cpp
index 561a705..12d8501 100644
--- a/test/t/osm/test_timestamp.cpp
+++ b/test/t/osm/test_timestamp.cpp
@@ -1,79 +1,77 @@
#include "catch.hpp"
#include <sstream>
+#include <string>
+#include <vector>
#include <osmium/osm/timestamp.hpp>
-TEST_CASE("Timestamp") {
-
- SECTION("can be default initialized to invalid value") {
- osmium::Timestamp t;
- REQUIRE(0 == uint32_t(t));
- REQUIRE("" == t.to_iso());
- REQUIRE_FALSE(t.valid());
- }
-
- SECTION("invalid value is zero") {
- osmium::Timestamp t(static_cast<time_t>(0));
- REQUIRE(0 == uint32_t(t));
- REQUIRE("" == t.to_iso());
- REQUIRE_FALSE(t.valid());
- }
+TEST_CASE("Timestamp can be default initialized to invalid value") {
+ const osmium::Timestamp t;
+ REQUIRE(0 == uint32_t(t));
+ REQUIRE("" == t.to_iso());
+ REQUIRE_FALSE(t.valid());
+}
- SECTION("can be initialized from time_t") {
- osmium::Timestamp t(static_cast<time_t>(1));
- REQUIRE(1 == uint32_t(t));
- REQUIRE("1970-01-01T00:00:01Z" == t.to_iso());
- REQUIRE(t.valid());
- }
+TEST_CASE("Timestamp invalid value is zero") {
+ const osmium::Timestamp t{static_cast<time_t>(0)};
+ REQUIRE(0 == uint32_t(t));
+ REQUIRE("" == t.to_iso());
+ REQUIRE_FALSE(t.valid());
+}
- SECTION("can be initialized from const char*") {
- osmium::Timestamp t("2000-01-01T00:00:00Z");
- REQUIRE("2000-01-01T00:00:00Z" == t.to_iso());
- REQUIRE(t.valid());
- }
+TEST_CASE("Timestamp can be initialized from time_t") {
+ const osmium::Timestamp t{static_cast<time_t>(1)};
+ REQUIRE(1 == uint32_t(t));
+ REQUIRE("1970-01-01T00:00:01Z" == t.to_iso());
+ REQUIRE(t.valid());
+}
- SECTION("can be initialized from string") {
- std::string s = "2000-01-01T00:00:00Z";
- osmium::Timestamp t(s);
- REQUIRE("2000-01-01T00:00:00Z" == t.to_iso());
- REQUIRE(t.valid());
- }
+TEST_CASE("Timestamp can be initialized from const char*") {
+ const osmium::Timestamp t{"2000-01-01T00:00:00Z"};
+ REQUIRE("2000-01-01T00:00:00Z" == t.to_iso());
+ REQUIRE(t.valid());
+}
- SECTION("throws if initialized from bad string") {
- REQUIRE_THROWS_AS(osmium::Timestamp("x"), std::invalid_argument);
- }
+TEST_CASE("Timestamp can be initialized from string") {
+ const std::string s = "2000-01-01T00:00:00Z";
+ const osmium::Timestamp t{s};
+ REQUIRE("2000-01-01T00:00:00Z" == t.to_iso());
+ REQUIRE(t.valid());
+}
- SECTION("can be explicitly cast to time_t") {
- osmium::Timestamp t(4242);
- time_t x = t.seconds_since_epoch();
- REQUIRE(x == 4242);
- }
+TEST_CASE("Timestamp throws if initialized from bad string") {
+ REQUIRE_THROWS_AS(osmium::Timestamp("x"), const std::invalid_argument&);
+}
- SECTION("uint32_t can be initialized from Timestamp") {
- osmium::Timestamp t(4242);
- uint32_t x { t };
+TEST_CASE("Timestamp can be explicitly cast to time_t") {
+ const osmium::Timestamp t{4242};
+ const time_t x = t.seconds_since_epoch();
+ REQUIRE(x == 4242);
+}
- REQUIRE(x == 4242);
- }
+TEST_CASE("Timestamp uint32_t can be initialized from Timestamp") {
+ const osmium::Timestamp t{4242};
+ const uint32_t x { t };
- SECTION("can be compared") {
- osmium::Timestamp t1(10);
- osmium::Timestamp t2(50);
- REQUIRE(t1 < t2);
- REQUIRE(t1 > osmium::start_of_time());
- REQUIRE(t2 > osmium::start_of_time());
- REQUIRE(t1 < osmium::end_of_time());
- REQUIRE(t2 < osmium::end_of_time());
- }
+ REQUIRE(x == 4242);
+}
- SECTION("can be written to stream") {
- std::stringstream ss;
- osmium::Timestamp t(1);
- ss << t;
- REQUIRE("1970-01-01T00:00:01Z" == ss.str());
- }
+TEST_CASE("Timestamps can be compared") {
+ const osmium::Timestamp t1{10};
+ const osmium::Timestamp t2{50};
+ REQUIRE(t1 < t2);
+ REQUIRE(t1 > osmium::start_of_time());
+ REQUIRE(t2 > osmium::start_of_time());
+ REQUIRE(t1 < osmium::end_of_time());
+ REQUIRE(t2 < osmium::end_of_time());
+}
+TEST_CASE("Timestamp can be written to stream") {
+ const osmium::Timestamp t{1};
+ std::stringstream ss;
+ ss << t;
+ REQUIRE("1970-01-01T00:00:01Z" == ss.str());
}
TEST_CASE("Valid timestamps") {
@@ -88,34 +86,34 @@ TEST_CASE("Valid timestamps") {
};
for (const auto& tc : test_cases) {
- osmium::Timestamp t{tc};
+ const osmium::Timestamp t{tc};
REQUIRE(tc == t.to_iso());
}
}
TEST_CASE("Invalid timestamps") {
- REQUIRE_THROWS_AS(osmium::Timestamp{""}, std::invalid_argument);
- REQUIRE_THROWS_AS(osmium::Timestamp{"x"}, std::invalid_argument);
- REQUIRE_THROWS_AS(osmium::Timestamp{"xxxxxxxxxxxxxxxxxxxx"}, std::invalid_argument);
-
- REQUIRE_THROWS_AS(osmium::Timestamp{"2000-01-01x00:00:00Z"}, std::invalid_argument);
- REQUIRE_THROWS_AS(osmium::Timestamp{"2000-01-01T00:00:00x"}, std::invalid_argument);
-
- REQUIRE_THROWS_AS(osmium::Timestamp{"2000x01-01T00:00:00Z"}, std::invalid_argument);
- REQUIRE_THROWS_AS(osmium::Timestamp{"2000-01x01T00:00:00Z"}, std::invalid_argument);
- REQUIRE_THROWS_AS(osmium::Timestamp{"2000-01-01T00x00:00Z"}, std::invalid_argument);
- REQUIRE_THROWS_AS(osmium::Timestamp{"2000-01-01T00:00x00Z"}, std::invalid_argument);
-
- REQUIRE_THROWS_AS(osmium::Timestamp{"0000-00-01T00:00:00Z"}, std::invalid_argument);
- REQUIRE_THROWS_AS(osmium::Timestamp{"2000-00-01T00:00:00Z"}, std::invalid_argument);
- REQUIRE_THROWS_AS(osmium::Timestamp{"2000-01-00T00:00:00Z"}, std::invalid_argument);
- REQUIRE_THROWS_AS(osmium::Timestamp{"2000-01-01T24:00:00Z"}, std::invalid_argument);
- REQUIRE_THROWS_AS(osmium::Timestamp{"2000-01-01T00:60:00Z"}, std::invalid_argument);
- REQUIRE_THROWS_AS(osmium::Timestamp{"2000-01-01T00:00:61Z"}, std::invalid_argument);
-
- REQUIRE_THROWS_AS(osmium::Timestamp{"2000-01-32T00:00:00Z"}, std::invalid_argument);
- REQUIRE_THROWS_AS(osmium::Timestamp{"2000-02-30T00:00:00Z"}, std::invalid_argument);
- REQUIRE_THROWS_AS(osmium::Timestamp{"2000-03-32T00:00:00Z"}, std::invalid_argument);
+ REQUIRE_THROWS_AS(osmium::Timestamp{""}, const std::invalid_argument&);
+ REQUIRE_THROWS_AS(osmium::Timestamp{"x"}, const std::invalid_argument&);
+ REQUIRE_THROWS_AS(osmium::Timestamp{"xxxxxxxxxxxxxxxxxxxx"}, const std::invalid_argument&);
+
+ REQUIRE_THROWS_AS(osmium::Timestamp{"2000-01-01x00:00:00Z"}, const std::invalid_argument&);
+ REQUIRE_THROWS_AS(osmium::Timestamp{"2000-01-01T00:00:00x"}, const std::invalid_argument&);
+
+ REQUIRE_THROWS_AS(osmium::Timestamp{"2000x01-01T00:00:00Z"}, const std::invalid_argument&);
+ REQUIRE_THROWS_AS(osmium::Timestamp{"2000-01x01T00:00:00Z"}, const std::invalid_argument&);
+ REQUIRE_THROWS_AS(osmium::Timestamp{"2000-01-01T00x00:00Z"}, const std::invalid_argument&);
+ REQUIRE_THROWS_AS(osmium::Timestamp{"2000-01-01T00:00x00Z"}, const std::invalid_argument&);
+
+ REQUIRE_THROWS_AS(osmium::Timestamp{"0000-00-01T00:00:00Z"}, const std::invalid_argument&);
+ REQUIRE_THROWS_AS(osmium::Timestamp{"2000-00-01T00:00:00Z"}, const std::invalid_argument&);
+ REQUIRE_THROWS_AS(osmium::Timestamp{"2000-01-00T00:00:00Z"}, const std::invalid_argument&);
+ REQUIRE_THROWS_AS(osmium::Timestamp{"2000-01-01T24:00:00Z"}, const std::invalid_argument&);
+ REQUIRE_THROWS_AS(osmium::Timestamp{"2000-01-01T00:60:00Z"}, const std::invalid_argument&);
+ REQUIRE_THROWS_AS(osmium::Timestamp{"2000-01-01T00:00:61Z"}, const std::invalid_argument&);
+
+ REQUIRE_THROWS_AS(osmium::Timestamp{"2000-01-32T00:00:00Z"}, const std::invalid_argument&);
+ REQUIRE_THROWS_AS(osmium::Timestamp{"2000-02-30T00:00:00Z"}, const std::invalid_argument&);
+ REQUIRE_THROWS_AS(osmium::Timestamp{"2000-03-32T00:00:00Z"}, const std::invalid_argument&);
}
diff --git a/test/t/osm/test_types_from_string.cpp b/test/t/osm/test_types_from_string.cpp
index 2866b8f..0ea566e 100644
--- a/test/t/osm/test_types_from_string.cpp
+++ b/test/t/osm/test_types_from_string.cpp
@@ -9,68 +9,68 @@ TEST_CASE("set ID from string") {
REQUIRE(osmium::string_to_object_id("-17") == -17);
REQUIRE(osmium::string_to_object_id("01") == 1);
- REQUIRE_THROWS_AS(osmium::string_to_object_id(""), std::range_error);
- REQUIRE_THROWS_AS(osmium::string_to_object_id(" "), std::range_error);
- REQUIRE_THROWS_AS(osmium::string_to_object_id(" 22"), std::range_error);
- REQUIRE_THROWS_AS(osmium::string_to_object_id("x"), std::range_error);
- REQUIRE_THROWS_AS(osmium::string_to_object_id("0x1"), std::range_error);
- REQUIRE_THROWS_AS(osmium::string_to_object_id("12a"), std::range_error);
- REQUIRE_THROWS_AS(osmium::string_to_object_id("12345678901234567890"), std::range_error);
+ REQUIRE_THROWS_AS(osmium::string_to_object_id(""), const std::range_error&);
+ REQUIRE_THROWS_AS(osmium::string_to_object_id(" "), const std::range_error&);
+ REQUIRE_THROWS_AS(osmium::string_to_object_id(" 22"), const std::range_error&);
+ REQUIRE_THROWS_AS(osmium::string_to_object_id("x"), const std::range_error&);
+ REQUIRE_THROWS_AS(osmium::string_to_object_id("0x1"), const std::range_error&);
+ REQUIRE_THROWS_AS(osmium::string_to_object_id("12a"), const std::range_error&);
+ REQUIRE_THROWS_AS(osmium::string_to_object_id("12345678901234567890"), const std::range_error&);
}
TEST_CASE("set type and ID from string") {
- auto n17 = osmium::string_to_object_id("n17", osmium::osm_entity_bits::nwr);
+ const auto n17 = osmium::string_to_object_id("n17", osmium::osm_entity_bits::nwr);
REQUIRE(n17.first == osmium::item_type::node);
REQUIRE(n17.second == 17);
- auto w42 = osmium::string_to_object_id("w42", osmium::osm_entity_bits::nwr);
+ const auto w42 = osmium::string_to_object_id("w42", osmium::osm_entity_bits::nwr);
REQUIRE(w42.first == osmium::item_type::way);
REQUIRE(w42.second == 42);
- auto r_2 = osmium::string_to_object_id("r-2", osmium::osm_entity_bits::nwr);
+ const auto r_2 = osmium::string_to_object_id("r-2", osmium::osm_entity_bits::nwr);
REQUIRE(r_2.first == osmium::item_type::relation);
REQUIRE(r_2.second == -2);
- auto d3 = osmium::string_to_object_id("3", osmium::osm_entity_bits::nwr);
+ const auto d3 = osmium::string_to_object_id("3", osmium::osm_entity_bits::nwr);
REQUIRE(d3.first == osmium::item_type::undefined);
REQUIRE(d3.second == 3);
- auto u3 = osmium::string_to_object_id("3", osmium::osm_entity_bits::nwr, osmium::item_type::undefined);
+ const auto u3 = osmium::string_to_object_id("3", osmium::osm_entity_bits::nwr, osmium::item_type::undefined);
REQUIRE(u3.first == osmium::item_type::undefined);
REQUIRE(u3.second == 3);
- auto n3 = osmium::string_to_object_id("3", osmium::osm_entity_bits::nwr, osmium::item_type::node);
+ const auto n3 = osmium::string_to_object_id("3", osmium::osm_entity_bits::nwr, osmium::item_type::node);
REQUIRE(n3.first == osmium::item_type::node);
REQUIRE(n3.second == 3);
- REQUIRE_THROWS_AS(osmium::string_to_object_id("", osmium::osm_entity_bits::nwr), std::range_error);
- REQUIRE_THROWS_AS(osmium::string_to_object_id("n", osmium::osm_entity_bits::nwr), std::range_error);
- REQUIRE_THROWS_AS(osmium::string_to_object_id("x3", osmium::osm_entity_bits::nwr), std::range_error);
- REQUIRE_THROWS_AS(osmium::string_to_object_id("nx3", osmium::osm_entity_bits::nwr), std::range_error);
- REQUIRE_THROWS_AS(osmium::string_to_object_id("n3", osmium::osm_entity_bits::way), std::range_error);
- REQUIRE_THROWS_AS(osmium::string_to_object_id("n3a", osmium::osm_entity_bits::nwr), std::range_error);
+ REQUIRE_THROWS_AS(osmium::string_to_object_id("", osmium::osm_entity_bits::nwr), const std::range_error&);
+ REQUIRE_THROWS_AS(osmium::string_to_object_id("n", osmium::osm_entity_bits::nwr), const std::range_error&);
+ REQUIRE_THROWS_AS(osmium::string_to_object_id("x3", osmium::osm_entity_bits::nwr), const std::range_error&);
+ REQUIRE_THROWS_AS(osmium::string_to_object_id("nx3", osmium::osm_entity_bits::nwr), const std::range_error&);
+ REQUIRE_THROWS_AS(osmium::string_to_object_id("n3", osmium::osm_entity_bits::way), const std::range_error&);
+ REQUIRE_THROWS_AS(osmium::string_to_object_id("n3a", osmium::osm_entity_bits::nwr), const std::range_error&);
}
TEST_CASE("set object version from string") {
REQUIRE(osmium::string_to_object_version("0") == 0);
REQUIRE(osmium::string_to_object_version("1") == 1);
- REQUIRE_THROWS_AS(osmium::string_to_object_version("-1"), std::range_error);
- REQUIRE_THROWS_AS(osmium::string_to_object_version(""), std::range_error);
- REQUIRE_THROWS_AS(osmium::string_to_object_version(" "), std::range_error);
- REQUIRE_THROWS_AS(osmium::string_to_object_version(" 22"), std::range_error);
- REQUIRE_THROWS_AS(osmium::string_to_object_version("x"), std::range_error);
+ REQUIRE_THROWS_AS(osmium::string_to_object_version("-1"), const std::range_error&);
+ REQUIRE_THROWS_AS(osmium::string_to_object_version(""), const std::range_error&);
+ REQUIRE_THROWS_AS(osmium::string_to_object_version(" "), const std::range_error&);
+ REQUIRE_THROWS_AS(osmium::string_to_object_version(" 22"), const std::range_error&);
+ REQUIRE_THROWS_AS(osmium::string_to_object_version("x"), const std::range_error&);
}
TEST_CASE("set changeset id from string") {
REQUIRE(osmium::string_to_changeset_id("0") == 0);
REQUIRE(osmium::string_to_changeset_id("1") == 1);
- REQUIRE_THROWS_AS(osmium::string_to_changeset_id("-1"), std::range_error);
- REQUIRE_THROWS_AS(osmium::string_to_changeset_id(""), std::range_error);
- REQUIRE_THROWS_AS(osmium::string_to_changeset_id(" "), std::range_error);
- REQUIRE_THROWS_AS(osmium::string_to_changeset_id(" 22"), std::range_error);
- REQUIRE_THROWS_AS(osmium::string_to_changeset_id("x"), std::range_error);
+ REQUIRE_THROWS_AS(osmium::string_to_changeset_id("-1"), const std::range_error&);
+ REQUIRE_THROWS_AS(osmium::string_to_changeset_id(""), const std::range_error&);
+ REQUIRE_THROWS_AS(osmium::string_to_changeset_id(" "), const std::range_error&);
+ REQUIRE_THROWS_AS(osmium::string_to_changeset_id(" 22"), const std::range_error&);
+ REQUIRE_THROWS_AS(osmium::string_to_changeset_id("x"), const std::range_error&);
}
TEST_CASE("set user id from string") {
@@ -78,21 +78,21 @@ TEST_CASE("set user id from string") {
REQUIRE(osmium::string_to_user_id("1") == 1);
REQUIRE(osmium::string_to_user_id("-1") == -1);
- REQUIRE_THROWS_AS(osmium::string_to_user_id("-2"), std::range_error);
- REQUIRE_THROWS_AS(osmium::string_to_user_id(""), std::range_error);
- REQUIRE_THROWS_AS(osmium::string_to_user_id(" "), std::range_error);
- REQUIRE_THROWS_AS(osmium::string_to_user_id(" 22"), std::range_error);
- REQUIRE_THROWS_AS(osmium::string_to_user_id("x"), std::range_error);
+ REQUIRE_THROWS_AS(osmium::string_to_user_id("-2"), const std::range_error&);
+ REQUIRE_THROWS_AS(osmium::string_to_user_id(""), const std::range_error&);
+ REQUIRE_THROWS_AS(osmium::string_to_user_id(" "), const std::range_error&);
+ REQUIRE_THROWS_AS(osmium::string_to_user_id(" 22"), const std::range_error&);
+ REQUIRE_THROWS_AS(osmium::string_to_user_id("x"), const std::range_error&);
}
TEST_CASE("set num changes from string") {
REQUIRE(osmium::string_to_num_changes("0") == 0);
REQUIRE(osmium::string_to_num_changes("1") == 1);
- REQUIRE_THROWS_AS(osmium::string_to_num_changes("-1"), std::range_error);
- REQUIRE_THROWS_AS(osmium::string_to_num_changes(""), std::range_error);
- REQUIRE_THROWS_AS(osmium::string_to_num_changes(" "), std::range_error);
- REQUIRE_THROWS_AS(osmium::string_to_num_changes(" 22"), std::range_error);
- REQUIRE_THROWS_AS(osmium::string_to_num_changes("x"), std::range_error);
+ REQUIRE_THROWS_AS(osmium::string_to_num_changes("-1"), const std::range_error&);
+ REQUIRE_THROWS_AS(osmium::string_to_num_changes(""), const std::range_error&);
+ REQUIRE_THROWS_AS(osmium::string_to_num_changes(" "), const std::range_error&);
+ REQUIRE_THROWS_AS(osmium::string_to_num_changes(" 22"), const std::range_error&);
+ REQUIRE_THROWS_AS(osmium::string_to_num_changes("x"), const std::range_error&);
}
diff --git a/test/t/osm/test_way.cpp b/test/t/osm/test_way.cpp
index 699abe1..bbfcfc9 100644
--- a/test/t/osm/test_way.cpp
+++ b/test/t/osm/test_way.cpp
@@ -42,7 +42,7 @@ TEST_CASE("Build way") {
REQUIRE(1 == way.nodes()[0].ref());
REQUIRE(3 == way.nodes()[1].ref());
REQUIRE(2 == way.nodes()[2].ref());
- REQUIRE(! way.is_closed());
+ REQUIRE_FALSE(way.is_closed());
osmium::CRC<boost::crc_32_type> crc32;
crc32.update(way);
@@ -92,7 +92,7 @@ TEST_CASE("build way with helpers") {
REQUIRE(22 == way.nodes()[0].ref());
REQUIRE(4.1 == Approx(way.nodes()[1].location().lon()));
- osmium::Box envelope = way.envelope();
+ const osmium::Box envelope = way.envelope();
REQUIRE(envelope.bottom_left().lon() == Approx(3.5));
REQUIRE(envelope.bottom_left().lat() == Approx(2.2));
REQUIRE(envelope.top_right().lon() == Approx(4.1));
diff --git a/test/t/relations/data.osm b/test/t/relations/data.osm
new file mode 100644
index 0000000..796b986
--- /dev/null
+++ b/test/t/relations/data.osm
@@ -0,0 +1,32 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+ <node id="10" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lat="1.0" lon="1.0"/>
+ <node id="11" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lat="1.0" lon="1.1"/>
+ <node id="12" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lat="1.0" lon="1.2"/>
+ <node id="13" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lat="1.0" lon="1.3"/>
+ <node id="14" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lat="1.0" lon="1.4"/>
+ <way id="20" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+ <tag k="highway" v="primary"/>
+ <nd ref="10"/>
+ <nd ref="11"/>
+ </way>
+ <way id="21" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+ <tag k="highway" v="residential"/>
+ <nd ref="11"/>
+ <nd ref="12"/>
+ </way>
+ <relation id="30" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+ <tag k="type" v="test"/>
+ <member type="node" ref="10" role="none"/>
+ </relation>
+ <relation id="31" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+ <tag k="type" v="restriction"/>
+ <member type="way" ref="20" role="from"/>
+ <member type="node" ref="11" role="via"/>
+ <member type="way" ref="22" role="to"/>
+ </relation>
+ <relation id="32" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+ <tag k="test" v="relinrel"/>
+ <member type="relation" ref="30" role="none"/>
+ </relation>
+</osm>
diff --git a/test/t/relations/dupl_member.osm b/test/t/relations/dupl_member.osm
new file mode 100644
index 0000000..58683bc
--- /dev/null
+++ b/test/t/relations/dupl_member.osm
@@ -0,0 +1,17 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+ <node id="10" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lat="1.0" lon="1.0"/>
+ <node id="11" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lat="1.0" lon="1.1"/>
+ <node id="12" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lat="1.0" lon="1.1"/>
+ <relation id="30" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+ <tag k="type" v="test"/>
+ <member type="node" ref="10" role="none"/>
+ <member type="node" ref="10" role="none"/>
+ <member type="node" ref="11" role="none"/>
+ </relation>
+ <relation id="31" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+ <tag k="type" v="test"/>
+ <member type="node" ref="10" role="none"/>
+ <member type="node" ref="12" role="none"/>
+ </relation>
+</osm>
diff --git a/test/t/relations/test_members_database.cpp b/test/t/relations/test_members_database.cpp
new file mode 100644
index 0000000..f2a4691
--- /dev/null
+++ b/test/t/relations/test_members_database.cpp
@@ -0,0 +1,194 @@
+#include "catch.hpp"
+
+#include <osmium/builder/attr.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/relations/members_database.hpp>
+#include <osmium/relations/relations_database.hpp>
+#include <osmium/storage/item_stash.hpp>
+
+osmium::memory::Buffer fill_buffer() {
+ using namespace osmium::builder::attr;
+ osmium::memory::Buffer buffer{1024 * 1024, osmium::memory::Buffer::auto_grow::yes};
+
+ osmium::builder::add_relation(buffer,
+ _id(20),
+ _member(osmium::item_type::way, 10, "outer")
+ );
+
+ osmium::builder::add_relation(buffer,
+ _id(21),
+ _member(osmium::item_type::way, 11, "outer"),
+ _member(osmium::item_type::way, 12, "outer")
+ );
+
+ osmium::builder::add_relation(buffer,
+ _id(22),
+ _member(osmium::item_type::way, 13, "outer"),
+ _member(osmium::item_type::way, 10, "inner"),
+ _member(osmium::item_type::way, 14, "inner")
+ );
+
+ osmium::builder::add_way(buffer, _id(10));
+ osmium::builder::add_way(buffer, _id(11));
+ osmium::builder::add_way(buffer, _id(12));
+ osmium::builder::add_way(buffer, _id(13));
+ osmium::builder::add_way(buffer, _id(14));
+ osmium::builder::add_way(buffer, _id(15));
+
+ return buffer;
+}
+
+TEST_CASE("Fill member database") {
+ const auto buffer = fill_buffer();
+
+ osmium::ItemStash stash;
+ osmium::relations::RelationsDatabase rdb{stash};
+ osmium::relations::MembersDatabase<osmium::Way> mdb{stash, rdb};
+
+ REQUIRE(mdb.used_memory() < 100);
+
+ for (const auto& relation : buffer.select<osmium::Relation>()) {
+ auto handle = rdb.add(relation);
+ int n = 0;
+ for (const auto& member : relation.members()) {
+ mdb.track(handle, member.ref(), n);
+ ++n;
+ }
+ }
+
+ mdb.prepare_for_lookup();
+
+ int n = 0;
+ int match = 0;
+ for (const auto& way : buffer.select<osmium::Way>()) {
+ bool added = mdb.add(way, [&](osmium::relations::RelationHandle& rel_handle) {
+ ++match;
+ switch (n) {
+ case 0: // added w10
+ REQUIRE(rel_handle->id() == 20);
+ break;
+ case 2: // added w11 and w12
+ REQUIRE(rel_handle->id() == 21);
+ break;
+ case 4: // added w13 and w14
+ REQUIRE(rel_handle->id() == 22);
+ break;
+ default:
+ REQUIRE(false);
+ break;
+ }
+ });
+
+ REQUIRE(added == (way.id() != 15));
+
+ if (way.id() == 11) {
+ const auto* way_ptr = mdb.get(way.id());
+ REQUIRE(way_ptr);
+ REQUIRE(*way_ptr == way);
+ const auto* object = mdb.get_object(way.id());
+ REQUIRE(object);
+ REQUIRE(object->id() == way.id());
+ }
+
+ ++n;
+ }
+
+ REQUIRE(match == 3);
+ REQUIRE(mdb.used_memory() > 100);
+}
+
+TEST_CASE("Member database with duplicate member in relation") {
+ using namespace osmium::builder::attr;
+ osmium::memory::Buffer buffer{1024 * 1024, osmium::memory::Buffer::auto_grow::yes};
+
+ osmium::builder::add_relation(buffer,
+ _id(20),
+ _member(osmium::item_type::way, 10, "outer"),
+ _member(osmium::item_type::way, 11, "inner"),
+ _member(osmium::item_type::way, 12, "inner"),
+ _member(osmium::item_type::way, 11, "inner")
+ );
+
+ osmium::builder::add_way(buffer, _id(10));
+ osmium::builder::add_way(buffer, _id(11));
+ osmium::builder::add_way(buffer, _id(12));
+
+ osmium::ItemStash stash;
+ osmium::relations::RelationsDatabase rdb{stash};
+ osmium::relations::MembersDatabase<osmium::Way> mdb{stash, rdb};
+
+ for (const auto& relation : buffer.select<osmium::Relation>()) {
+ auto handle = rdb.add(relation);
+ int n = 0;
+ for (const auto& member : relation.members()) {
+ mdb.track(handle, member.ref(), n);
+ ++n;
+ }
+ }
+
+ mdb.prepare_for_lookup();
+
+ REQUIRE(mdb.size() == 4);
+ {
+ const auto counts = mdb.count();
+ REQUIRE(counts.tracked == 4);
+ REQUIRE(counts.available == 0);
+ REQUIRE(counts.removed == 0);
+ }
+
+ int n = 0;
+ for (const auto& way : buffer.select<osmium::Way>()) {
+ mdb.add(way, [&](osmium::relations::RelationHandle& rel_handle) {
+ ++n;
+ REQUIRE(rel_handle->id() == 20);
+ {
+ const auto counts = mdb.count();
+ REQUIRE(counts.tracked == 0);
+ REQUIRE(counts.available == 4);
+ REQUIRE(counts.removed == 0);
+ }
+
+ // relation is complete here, normal code would handle it here
+
+ for (const auto& member : rel_handle->members()) {
+ mdb.remove(member.ref(), rel_handle->id());
+ }
+ rel_handle.remove();
+ });
+ }
+
+ REQUIRE(n == 1);
+
+ REQUIRE(rdb.size() == 1);
+ REQUIRE(rdb.count_relations() == 0);
+
+ REQUIRE(mdb.size() == 4);
+ {
+ const auto counts = mdb.count();
+ REQUIRE(counts.tracked == 0);
+ REQUIRE(counts.available == 0);
+ REQUIRE(counts.removed == 4);
+ }
+}
+
+TEST_CASE("Remove non-existing object from members database doesn't do anything") {
+ const auto buffer = fill_buffer();
+
+ osmium::ItemStash stash;
+ osmium::relations::RelationsDatabase rdb{stash};
+ osmium::relations::MembersDatabase<osmium::Way> mdb{stash, rdb};
+
+ for (const auto& relation : buffer.select<osmium::Relation>()) {
+ auto handle = rdb.add(relation);
+ int n = 0;
+ for (const auto& member : relation.members()) {
+ mdb.track(handle, member.ref(), n);
+ ++n;
+ }
+ }
+
+ REQUIRE(mdb.size() == 6);
+ mdb.remove(100, 100);
+ REQUIRE(mdb.size() == 6);
+}
+
diff --git a/test/t/relations/test_read_relations.cpp b/test/t/relations/test_read_relations.cpp
new file mode 100644
index 0000000..5e79133
--- /dev/null
+++ b/test/t/relations/test_read_relations.cpp
@@ -0,0 +1,77 @@
+#include "catch.hpp"
+#include "utils.hpp"
+
+#include <osmium/handler.hpp>
+#include <osmium/io/xml_input.hpp>
+#include <osmium/relations/manager_util.hpp>
+#include <osmium/util/progress_bar.hpp>
+
+class TestHandler : public osmium::handler::Handler {
+
+public:
+
+ int count = 0;
+ bool prep = false;
+
+ void relation(const osmium::Relation&) noexcept {
+ ++count;
+ }
+
+ void prepare_for_lookup() noexcept {
+ prep = true;
+ }
+
+}; // class TestHandler
+
+TEST_CASE("Read relations with one handler") {
+ osmium::io::File file{with_data_dir("t/relations/data.osm")};
+
+ TestHandler handler;
+
+ osmium::relations::read_relations(file, handler);
+
+ REQUIRE(handler.count == 3);
+ REQUIRE(handler.prep);
+}
+
+TEST_CASE("Read relations with two handlers") {
+ osmium::io::File file{with_data_dir("t/relations/data.osm")};
+
+ TestHandler handler1;
+ TestHandler handler2;
+
+ osmium::relations::read_relations(file, handler1, handler2);
+
+ REQUIRE(handler1.count == 3);
+ REQUIRE(handler2.count == 3);
+ REQUIRE(handler1.prep);
+ REQUIRE(handler2.prep);
+}
+
+TEST_CASE("Read relations with progress bar and one handler") {
+ osmium::io::File file{with_data_dir("t/relations/data.osm")};
+ osmium::ProgressBar progress_bar{file.size(), false};
+
+ TestHandler handler;
+
+ osmium::relations::read_relations(progress_bar, file, handler);
+
+ REQUIRE(handler.count == 3);
+ REQUIRE(handler.prep);
+}
+
+TEST_CASE("Read relations with progress bar and two handlers") {
+ osmium::io::File file{with_data_dir("t/relations/data.osm")};
+ osmium::ProgressBar progress_bar{file.size(), false};
+
+ TestHandler handler1;
+ TestHandler handler2;
+
+ osmium::relations::read_relations(progress_bar, file, handler1, handler2);
+
+ REQUIRE(handler1.count == 3);
+ REQUIRE(handler2.count == 3);
+ REQUIRE(handler1.prep);
+ REQUIRE(handler2.prep);
+}
+
diff --git a/test/t/relations/test_relations_database.cpp b/test/t/relations/test_relations_database.cpp
new file mode 100644
index 0000000..e352ea5
--- /dev/null
+++ b/test/t/relations/test_relations_database.cpp
@@ -0,0 +1,105 @@
+#include "catch.hpp"
+
+#include <osmium/builder/attr.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/relations/relations_database.hpp>
+#include <osmium/storage/item_stash.hpp>
+
+osmium::memory::Buffer fill_buffer() {
+ using namespace osmium::builder::attr;
+ osmium::memory::Buffer buffer{1024 * 1024, osmium::memory::Buffer::auto_grow::yes};
+
+ osmium::builder::add_relation(buffer,
+ _id(1),
+ _member(osmium::item_type::way, 1, "outer")
+ );
+
+ osmium::builder::add_relation(buffer,
+ _id(2),
+ _member(osmium::item_type::way, 1, "outer"),
+ _member(osmium::item_type::way, 2, "outer")
+ );
+
+ osmium::builder::add_relation(buffer,
+ _id(3),
+ _member(osmium::item_type::way, 1, "outer"),
+ _member(osmium::item_type::way, 2, "inner"),
+ _member(osmium::item_type::way, 3, "inner")
+ );
+
+ return buffer;
+}
+
+TEST_CASE("Fill relation database") {
+ const auto buffer = fill_buffer();
+
+ osmium::ItemStash stash;
+ osmium::relations::RelationsDatabase rdb{stash};
+
+ REQUIRE(rdb.size() == 0);
+ REQUIRE(rdb.used_memory() < 100);
+
+ for (const auto& relation : buffer.select<osmium::Relation>()) {
+ auto handle = rdb.add(relation);
+ handle.set_members(relation.cmembers().size());
+ handle.decrement_members();
+ REQUIRE(handle.has_all_members() == (relation.id() == 1));
+ }
+
+ REQUIRE(rdb.size() == 3);
+
+ int n = 0;
+ rdb.for_each_relation([&](const osmium::relations::RelationHandle& rel_handle) {
+ ++n;
+ REQUIRE(rel_handle->members().size() == (*rel_handle).id());
+ });
+ REQUIRE(n == 3);
+}
+
+TEST_CASE("Check need members and handle ops") {
+ const auto buffer = fill_buffer();
+
+ osmium::ItemStash stash;
+ osmium::relations::RelationsDatabase rdb{stash};
+
+ for (const auto& relation : buffer.select<osmium::Relation>()) {
+ auto handle = rdb.add(relation);
+ REQUIRE(*handle == relation);
+ REQUIRE(handle->id() == relation.id());
+ REQUIRE(handle.pos() + 1 == relation.positive_id());
+ REQUIRE(rdb[handle.pos()].pos() == handle.pos());
+
+ for (auto i = relation.id(); i > 0; --i) {
+ handle.increment_members();
+ }
+
+ handle.decrement_members();
+ REQUIRE(handle.has_all_members() == (relation.id() == 1));
+ if (handle.has_all_members()) {
+ handle.remove();
+ }
+ }
+
+ REQUIRE(rdb.size() == 3);
+
+ std::vector<const osmium::Relation*> rels;
+ rdb.for_each_relation([&](const osmium::relations::RelationHandle& rel_handle) {
+ rels.push_back(&*rel_handle);
+ });
+
+ REQUIRE(rels.size() == 2);
+
+ osmium::object_id_type n = 2;
+ for (const auto* rel : rels) {
+ REQUIRE(rel->id() == n);
+ ++n;
+ }
+
+ REQUIRE(rdb[1]->id() == 2);
+ REQUIRE(rdb[2]->id() == 3);
+
+ rdb[1].remove();
+
+ REQUIRE(rdb.count_relations() == 1);
+}
+
diff --git a/test/t/relations/test_relations_manager.cpp b/test/t/relations/test_relations_manager.cpp
new file mode 100644
index 0000000..d7ea12f
--- /dev/null
+++ b/test/t/relations/test_relations_manager.cpp
@@ -0,0 +1,248 @@
+#include "catch.hpp"
+#include "utils.hpp"
+
+#include <osmium/io/xml_input.hpp>
+#include <osmium/osm/relation.hpp>
+#include <osmium/relations/relations_manager.hpp>
+
+struct EmptyRM : public osmium::relations::RelationsManager<EmptyRM, true, true, true> {
+};
+
+struct TestRM : public osmium::relations::RelationsManager<TestRM, true, true, true> {
+
+ std::size_t count_new_rels = 0;
+ std::size_t count_new_members = 0;
+ std::size_t count_complete_rels = 0;
+ std::size_t count_before = 0;
+ std::size_t count_not_in_any = 0;
+ std::size_t count_after = 0;
+
+ bool new_relation(const osmium::Relation& /*relation*/) noexcept {
+ ++count_new_rels;
+ return true;
+ }
+
+ bool new_member(const osmium::Relation& /*relation*/, const osmium::RelationMember& /*member*/, std::size_t /*n*/) noexcept {
+ ++count_new_members;
+ return true;
+ }
+
+ void complete_relation(const osmium::Relation& /*relation*/) noexcept {
+ ++count_complete_rels;
+ }
+
+ void before_node(const osmium::Node& /*node*/) noexcept {
+ ++count_before;
+ }
+
+ void node_not_in_any_relation(const osmium::Node& /*node*/) noexcept {
+ ++count_not_in_any;
+ }
+
+ void after_node(const osmium::Node& /*node*/) noexcept {
+ ++count_after;
+ }
+
+ void before_way(const osmium::Way& /*way*/) noexcept {
+ ++count_before;
+ }
+
+ void way_not_in_any_relation(const osmium::Way& /*way*/) noexcept {
+ ++count_not_in_any;
+ }
+
+ void after_way(const osmium::Way& /*way*/) noexcept {
+ ++count_after;
+ }
+
+ void before_relation(const osmium::Relation& /*relation*/) noexcept {
+ ++count_before;
+ }
+
+ void relation_not_in_any_relation(const osmium::Relation& /*relation*/) noexcept {
+ ++count_not_in_any;
+ }
+
+ void after_relation(const osmium::Relation& /*relation*/) noexcept {
+ ++count_after;
+ }
+
+};
+
+struct CallbackRM : public osmium::relations::RelationsManager<CallbackRM, true, false, false> {
+
+ std::size_t count_nodes = 0;
+
+ bool new_relation(const osmium::Relation& /*relation*/) noexcept {
+ return true;
+ }
+
+ bool new_member(const osmium::Relation& /*relation*/, const osmium::RelationMember& member, std::size_t /*n*/) noexcept {
+ return member.type() == osmium::item_type::node;
+ }
+
+ void complete_relation(const osmium::Relation& relation) noexcept {
+ for (const auto& member : relation.members()) {
+ if (member.type() == osmium::item_type::node) {
+ ++count_nodes;
+ const auto* node = get_member_node(member.ref());
+ REQUIRE(node);
+ buffer().add_item(*node);
+ buffer().commit();
+ }
+ }
+ }
+
+};
+
+TEST_CASE("Use RelationsManager without any overloaded functions in derived class") {
+ osmium::io::File file{with_data_dir("t/relations/data.osm")};
+
+ EmptyRM manager;
+
+ osmium::relations::read_relations(file, manager);
+
+ REQUIRE(manager.member_nodes_database().size() == 2);
+ REQUIRE(manager.member_ways_database().size() == 2);
+ REQUIRE(manager.member_relations_database().size() == 1);
+
+ REQUIRE(manager.member_database(osmium::item_type::node).size() == 2);
+ REQUIRE(manager.member_database(osmium::item_type::way).size() == 2);
+ REQUIRE(manager.member_database(osmium::item_type::relation).size() == 1);
+
+ const auto& m = manager;
+ REQUIRE(m.member_database(osmium::item_type::node).size() == 2);
+ REQUIRE(m.member_database(osmium::item_type::way).size() == 2);
+ REQUIRE(m.member_database(osmium::item_type::relation).size() == 1);
+
+ osmium::io::Reader reader{file};
+ osmium::apply(reader, manager.handler());
+ reader.close();
+}
+
+TEST_CASE("Relations manager derived class") {
+ osmium::io::File file{with_data_dir("t/relations/data.osm")};
+
+ TestRM manager;
+
+ osmium::relations::read_relations(file, manager);
+
+ REQUIRE(manager.member_nodes_database().size() == 2);
+ REQUIRE(manager.member_ways_database().size() == 2);
+ REQUIRE(manager.member_relations_database().size() == 1);
+
+ bool callback_called = false;
+ osmium::io::Reader reader{file};
+ osmium::apply(reader, manager.handler([&](osmium::memory::Buffer&&) {
+ callback_called = true;
+ }));
+ reader.close();
+ REQUIRE_FALSE(callback_called);
+
+ REQUIRE(manager.count_new_rels == 3);
+ REQUIRE(manager.count_new_members == 5);
+ REQUIRE(manager.count_complete_rels == 2);
+ REQUIRE(manager.count_before == 10);
+ REQUIRE(manager.count_not_in_any == 6);
+ REQUIRE(manager.count_after == 10);
+
+ int n = 0;
+ manager.for_each_incomplete_relation([&](const osmium::relations::RelationHandle& handle){
+ ++n;
+ REQUIRE(handle->id() == 31);
+ for (const auto& member : handle->members()) {
+ const auto* obj = manager.get_member_object(member);
+ if (member.ref() == 22) {
+ REQUIRE_FALSE(obj);
+ } else {
+ REQUIRE(obj);
+ }
+ }
+ });
+ REQUIRE(n == 1);
+}
+
+TEST_CASE("Relations manager with callback") {
+ osmium::io::File file{with_data_dir("t/relations/data.osm")};
+
+ CallbackRM manager;
+
+ osmium::relations::read_relations(file, manager);
+
+ REQUIRE(manager.member_nodes_database().size() == 2);
+ REQUIRE(manager.member_ways_database().size() == 0);
+ REQUIRE(manager.member_relations_database().size() == 0);
+
+ bool callback_called = false;
+ osmium::io::Reader reader{file};
+ osmium::apply(reader, manager.handler([&](osmium::memory::Buffer&& buffer) {
+ callback_called = true;
+ REQUIRE(std::distance(buffer.begin(), buffer.end()) == 2);
+ }));
+ reader.close();
+ REQUIRE(manager.count_nodes == 2);
+ REQUIRE(callback_called);
+}
+
+TEST_CASE("Relations manager reading buffer without callback") {
+ osmium::io::File file{with_data_dir("t/relations/data.osm")};
+
+ CallbackRM manager;
+
+ osmium::relations::read_relations(file, manager);
+
+ REQUIRE(manager.member_nodes_database().size() == 2);
+ REQUIRE(manager.member_ways_database().size() == 0);
+ REQUIRE(manager.member_relations_database().size() == 0);
+
+ osmium::io::Reader reader{file};
+ osmium::apply(reader, manager.handler());
+ reader.close();
+
+ auto buffer = manager.read();
+ REQUIRE(std::distance(buffer.begin(), buffer.end()) == 2);
+
+ REQUIRE(manager.count_nodes == 2);
+}
+
+TEST_CASE("Access members via RelationsManager") {
+ EmptyRM manager;
+
+ manager.prepare_for_lookup();
+
+ REQUIRE(nullptr == manager.get_member_node(0));
+ REQUIRE(nullptr == manager.get_member_way(0));
+ REQUIRE(nullptr == manager.get_member_relation(0));
+
+ REQUIRE(nullptr == manager.get_member_node(17));
+ REQUIRE(nullptr == manager.get_member_way(17));
+ REQUIRE(nullptr == manager.get_member_relation(17));
+}
+
+TEST_CASE("Handle duplicate members correctly") {
+ osmium::io::File file{with_data_dir("t/relations/dupl_member.osm")};
+
+ TestRM manager;
+
+ osmium::relations::read_relations(file, manager);
+
+ auto c = manager.member_nodes_database().count();
+ REQUIRE(c.tracked == 5);
+ REQUIRE(c.available == 0);
+ REQUIRE(c.removed == 0);
+
+ osmium::io::Reader reader{file};
+ osmium::apply(reader, manager.handler());
+ reader.close();
+
+ c = manager.member_nodes_database().count();
+ REQUIRE(c.tracked == 0);
+ REQUIRE(c.available == 0);
+ REQUIRE(c.removed == 5);
+
+ REQUIRE(manager.count_new_rels == 2);
+ REQUIRE(manager.count_new_members == 5);
+ REQUIRE(manager.count_complete_rels == 2);
+ REQUIRE(manager.count_not_in_any == 2); // 2 relations
+}
+
diff --git a/test/t/storage/test_item_stash.cpp b/test/t/storage/test_item_stash.cpp
new file mode 100644
index 0000000..62d910e
--- /dev/null
+++ b/test/t/storage/test_item_stash.cpp
@@ -0,0 +1,167 @@
+
+#include <catch.hpp>
+
+#include <sstream>
+
+#include <osmium/builder/attr.hpp>
+#include <osmium/storage/item_stash.hpp>
+
+osmium::memory::Buffer generate_test_data() {
+ using namespace osmium::builder::attr;
+
+ osmium::memory::Buffer buffer{1024 * 1024, osmium::memory::Buffer::auto_grow::yes};
+
+ const osmium::object_id_type num_nodes = 100;
+ const osmium::object_id_type num_ways = 50;
+ const osmium::object_id_type num_relations = 30;
+
+ osmium::object_id_type id = 1;
+ for (; id <= num_nodes; ++id) {
+ osmium::builder::add_node(buffer, _id(id));
+ }
+
+ for (; id <= num_nodes + num_ways; ++id) {
+ osmium::builder::add_way(buffer, _id(id));
+ }
+
+ for (; id <= num_nodes + num_ways + num_relations; ++id) {
+ osmium::builder::add_relation(buffer, _id(id));
+ }
+
+ return buffer;
+}
+
+
+TEST_CASE("Item stash handle") {
+ const auto handle = osmium::ItemStash::handle_type{};
+ REQUIRE_FALSE(handle.valid());
+
+ std::stringstream ss;
+ ss << handle;
+ REQUIRE(ss.str() == "-");
+}
+
+TEST_CASE("Item stash") {
+ const auto buffer = generate_test_data();
+
+ osmium::ItemStash stash;
+ REQUIRE(stash.size() == 0);
+ REQUIRE(stash.count_removed() == 0);
+
+ std::vector<osmium::ItemStash::handle_type> handles;
+ for (const auto& item : buffer) {
+ auto handle = stash.add_item(item);
+ handles.push_back(handle);
+ }
+
+ REQUIRE(stash.size() == 180);
+ REQUIRE(stash.count_removed() == 0);
+
+ REQUIRE(stash.used_memory() > 1024 * 1024);
+
+ osmium::object_id_type id = 1;
+ for (auto& handle : handles) { // must be reference because we will change it!
+ REQUIRE(handle.valid());
+ const auto& item = stash.get_item(handle);
+ bool correct_type = item.type() == osmium::item_type::node ||
+ item.type() == osmium::item_type::way ||
+ item.type() == osmium::item_type::relation;
+ REQUIRE(correct_type);
+ const auto& obj = static_cast<const osmium::OSMObject&>(item);
+ REQUIRE(obj.id() == id);
+
+ std::stringstream ss;
+ ss << handle;
+ REQUIRE(ss.str() == std::to_string(id));
+
+ if (obj.id() % 3 == 0) {
+ stash.remove_item(handle);
+ handle = osmium::ItemStash::handle_type{};
+ }
+
+ id++;
+ }
+
+ REQUIRE(stash.size() == 120);
+ REQUIRE(stash.count_removed() == 60);
+
+ id = 1;
+ int count_valid = 0;
+ int count_invalid = 0;
+ for (auto handle : handles) {
+ if (handle.valid()) {
+ ++count_valid;
+ const auto& item = stash.get_item(handle);
+ const bool correct_type = item.type() == osmium::item_type::node ||
+ item.type() == osmium::item_type::way ||
+ item.type() == osmium::item_type::relation;
+ REQUIRE(correct_type);
+ const auto& obj = static_cast<const osmium::OSMObject&>(item);
+ REQUIRE(obj.id() == id);
+ } else {
+ ++count_invalid;
+ }
+ id++;
+ }
+
+ REQUIRE(count_valid == 120);
+ REQUIRE(count_invalid == 60);
+
+ stash.garbage_collect();
+ REQUIRE(stash.size() == 120);
+ REQUIRE(stash.count_removed() == 0);
+
+ id = 1;
+ for (auto handle : handles) {
+ if (handle.valid()) {
+ const auto& item = stash.get_item(handle);
+ const bool correct_type = item.type() == osmium::item_type::node ||
+ item.type() == osmium::item_type::way ||
+ item.type() == osmium::item_type::relation;
+ REQUIRE(correct_type);
+ const auto& obj = static_cast<const osmium::OSMObject&>(item);
+ REQUIRE(obj.id() == id);
+ }
+ id++;
+ }
+
+ stash.clear();
+ REQUIRE(stash.size() == 0);
+ REQUIRE(stash.count_removed() == 0);
+}
+
+TEST_CASE("Fill item stash until it garbage collects") {
+ const auto buffer = generate_test_data();
+
+ osmium::ItemStash stash;
+ REQUIRE(stash.size() == 0);
+ REQUIRE(stash.count_removed() == 0);
+
+ const auto& node = buffer.get<osmium::Node>(0);
+
+ std::vector<osmium::ItemStash::handle_type> handles;
+ std::size_t num_items = 6 * 1000 * 1000;
+ for (std::size_t i = 0; i < num_items; ++i) {
+ auto handle = stash.add_item(node);
+ handles.push_back(handle);
+ }
+
+ REQUIRE(stash.size() == num_items);
+ REQUIRE(stash.count_removed() == 0);
+
+ for (std::size_t i = 0; i < num_items; ++i) {
+ if (i % 10 != 0) {
+ stash.remove_item(handles[i]);
+ }
+ }
+
+ REQUIRE(stash.size() == num_items / 10);
+ REQUIRE(stash.count_removed() == num_items / 10 * 9);
+
+ // trigger compaction
+ stash.add_item(node);
+
+ REQUIRE(stash.size() == num_items / 10 + 1);
+ REQUIRE(stash.count_removed() == 0);
+}
+
diff --git a/test/t/tags/test_filter.cpp b/test/t/tags/test_filter.cpp
index eab8844..6c15a80 100644
--- a/test/t/tags/test_filter.cpp
+++ b/test/t/tags/test_filter.cpp
@@ -26,7 +26,7 @@ void check_filter(const osmium::TagList& tag_list,
}
const osmium::TagList& make_tag_list(osmium::memory::Buffer& buffer,
- std::initializer_list<std::pair<const char*, const char*>> tags) {
+ const std::initializer_list<std::pair<const char*, const char*>>& tags) {
const auto pos = osmium::builder::add_tag_list(buffer, osmium::builder::attr::_tags(tags));
return buffer.get<osmium::TagList>(pos);
}
@@ -131,9 +131,9 @@ TEST_CASE("KeyValueFilter") {
{ "source", "GPS" }
});
- REQUIRE( osmium::tags::match_any_of(tag_list, filter));
- REQUIRE(!osmium::tags::match_all_of(tag_list, filter));
- REQUIRE(!osmium::tags::match_none_of(tag_list, filter));
+ REQUIRE( osmium::tags::match_any_of(tag_list, filter));
+ REQUIRE_FALSE(osmium::tags::match_all_of(tag_list, filter));
+ REQUIRE_FALSE(osmium::tags::match_none_of(tag_list, filter));
}
SECTION("KeyValueFilter matches against taglist with_all") {
@@ -147,9 +147,9 @@ TEST_CASE("KeyValueFilter") {
{ "name", "Main Street" }
});
- REQUIRE( osmium::tags::match_any_of(tag_list, filter));
- REQUIRE( osmium::tags::match_all_of(tag_list, filter));
- REQUIRE(!osmium::tags::match_none_of(tag_list, filter));
+ REQUIRE( osmium::tags::match_any_of(tag_list, filter));
+ REQUIRE( osmium::tags::match_all_of(tag_list, filter));
+ REQUIRE_FALSE(osmium::tags::match_none_of(tag_list, filter));
}
SECTION("KeyValueFilter matches against taglist with none") {
@@ -163,9 +163,9 @@ TEST_CASE("KeyValueFilter") {
{ "name", "Main Street" }
});
- REQUIRE(!osmium::tags::match_any_of(tag_list, filter));
- REQUIRE(!osmium::tags::match_all_of(tag_list, filter));
- REQUIRE( osmium::tags::match_none_of(tag_list, filter));
+ REQUIRE_FALSE(osmium::tags::match_any_of(tag_list, filter));
+ REQUIRE_FALSE(osmium::tags::match_all_of(tag_list, filter));
+ REQUIRE( osmium::tags::match_none_of(tag_list, filter));
}
SECTION("KeyValueFilter matches against taglist with any called with rvalue") {
@@ -233,7 +233,7 @@ TEST_CASE("KeyPrefixFilter matches some keys") {
}
-TEST_CASE("Generic Filterw with regex matches some keys") {
+TEST_CASE("Generic Filter with regex matches some keys") {
osmium::memory::Buffer buffer{10240};
osmium::tags::Filter<std::regex> filter{false};
diff --git a/test/t/tags/test_operators.cpp b/test/t/tags/test_operators.cpp
index 33a53c2..b90303a 100644
--- a/test/t/tags/test_operators.cpp
+++ b/test/t/tags/test_operators.cpp
@@ -6,56 +6,53 @@
#include <osmium/memory/buffer.hpp>
#include <osmium/osm/tag.hpp>
-TEST_CASE("Operators") {
-
- SECTION("Equal") {
- osmium::memory::Buffer buffer1(10240);
- {
- osmium::builder::TagListBuilder tl_builder(buffer1);
- tl_builder.add_tag("highway", "primary");
- tl_builder.add_tag("name", "Main Street");
- tl_builder.add_tag("source", "GPS");
- }
- buffer1.commit();
-
- osmium::memory::Buffer buffer2(10240);
- {
- osmium::builder::TagListBuilder tl_builder(buffer2);
- tl_builder.add_tag("highway", "primary");
- }
- buffer2.commit();
-
- const osmium::TagList& tl1 = buffer1.get<const osmium::TagList>(0);
- const osmium::TagList& tl2 = buffer2.get<const osmium::TagList>(0);
-
- auto tagit1 = tl1.begin();
- auto tagit2 = tl2.begin();
- REQUIRE(*tagit1 == *tagit2);
- ++tagit1;
- REQUIRE(!(*tagit1 == *tagit2));
+TEST_CASE("Equality comparison of tags") {
+ osmium::memory::Buffer buffer1{10240};
+ {
+ osmium::builder::TagListBuilder tl_builder{buffer1};
+ tl_builder.add_tag("highway", "primary");
+ tl_builder.add_tag("name", "Main Street");
+ tl_builder.add_tag("source", "GPS");
}
+ buffer1.commit();
- SECTION("Order") {
- osmium::memory::Buffer buffer(10240);
- {
- osmium::builder::TagListBuilder tl_builder(buffer);
- tl_builder.add_tag("highway", "residential");
- tl_builder.add_tag("highway", "primary");
- tl_builder.add_tag("name", "Main Street");
- tl_builder.add_tag("amenity", "post_box");
- }
- buffer.commit();
-
- const osmium::TagList& tl = buffer.get<const osmium::TagList>(0);
- const osmium::Tag& t1 = *(tl.begin());
- const osmium::Tag& t2 = *(std::next(tl.begin(), 1));
- const osmium::Tag& t3 = *(std::next(tl.begin(), 2));
- const osmium::Tag& t4 = *(std::next(tl.begin(), 3));
-
- REQUIRE(t2 < t1);
- REQUIRE(t1 < t3);
- REQUIRE(t2 < t3);
- REQUIRE(t4 < t1);
+ osmium::memory::Buffer buffer2{10240};
+ {
+ osmium::builder::TagListBuilder tl_builder{buffer2};
+ tl_builder.add_tag("highway", "primary");
}
+ buffer2.commit();
+ const osmium::TagList& tl1 = buffer1.get<const osmium::TagList>(0);
+ const osmium::TagList& tl2 = buffer2.get<const osmium::TagList>(0);
+
+ auto tagit1 = tl1.begin();
+ auto tagit2 = tl2.begin();
+ REQUIRE(*tagit1 == *tagit2);
+ ++tagit1;
+ REQUIRE_FALSE(*tagit1 == *tagit2);
}
+
+TEST_CASE("Ordering of tags") {
+ osmium::memory::Buffer buffer{10240};
+ {
+ osmium::builder::TagListBuilder tl_builder{buffer};
+ tl_builder.add_tag("highway", "residential");
+ tl_builder.add_tag("highway", "primary");
+ tl_builder.add_tag("name", "Main Street");
+ tl_builder.add_tag("amenity", "post_box");
+ }
+ buffer.commit();
+
+ const osmium::TagList& tl = buffer.get<const osmium::TagList>(0);
+ const osmium::Tag& t1 = *(tl.begin());
+ const osmium::Tag& t2 = *(std::next(tl.begin(), 1));
+ const osmium::Tag& t3 = *(std::next(tl.begin(), 2));
+ const osmium::Tag& t4 = *(std::next(tl.begin(), 3));
+
+ REQUIRE(t2 < t1);
+ REQUIRE(t1 < t3);
+ REQUIRE(t2 < t3);
+ REQUIRE(t4 < t1);
+}
+
diff --git a/test/t/thread/test_pool.cpp b/test/t/thread/test_pool.cpp
index c1047db..5f0e5b6 100644
--- a/test/t/thread/test_pool.cpp
+++ b/test/t/thread/test_pool.cpp
@@ -15,7 +15,7 @@ struct test_job_with_result {
struct test_job_throw {
OSMIUM_NORETURN void operator()() const {
- throw std::runtime_error("exception in pool thread");
+ throw std::runtime_error{"exception in pool thread"};
}
};
@@ -48,24 +48,70 @@ TEST_CASE("number of threads in pool") {
}
+TEST_CASE("if zero number of threads requested, threads configured") {
+ osmium::thread::Pool pool{0};
+ REQUIRE(pool.num_threads() > 0);
+}
+
+TEST_CASE("if any negative number of threads requested, threads configured") {
+ osmium::thread::Pool pool{-1};
+ REQUIRE(pool.num_threads() > 0);
+}
+
+TEST_CASE("if outlier negative number of threads requested, threads configured") {
+ osmium::thread::Pool pool{-100};
+ REQUIRE(pool.num_threads() > 0);
+}
+
+TEST_CASE("if outlier positive number of threads requested, threads configured") {
+ osmium::thread::Pool pool{1000};
+ REQUIRE(pool.num_threads() > 0);
+}
+
TEST_CASE("thread") {
- auto& pool = osmium::thread::Pool::instance();
+ auto& pool = osmium::thread::Pool::default_instance();
+
+ SECTION("can get access to thread pool") {
+ REQUIRE(pool.queue_empty());
+ }
+
+ SECTION("can send job to thread pool") {
+ auto future = pool.submit(test_job_with_result{});
+
+ REQUIRE(future.get() == 42);
+ }
+
+ SECTION("can throw from job in thread pool") {
+ auto future = pool.submit(test_job_throw{});
+
+ REQUIRE_THROWS_AS(future.get(), const std::runtime_error&);
+ }
+
+}
+
+TEST_CASE("thread (user-provided pool)") {
+
+ osmium::thread::Pool pool{7};
SECTION("can get access to thread pool") {
REQUIRE(pool.queue_empty());
}
+
+ SECTION("can access user-provided number of threads") {
+ REQUIRE(pool.num_threads() == 7);
+ }
SECTION("can send job to thread pool") {
- auto future = pool.submit(test_job_with_result {});
+ auto future = pool.submit(test_job_with_result{});
REQUIRE(future.get() == 42);
}
SECTION("can throw from job in thread pool") {
- auto future = pool.submit(test_job_throw {});
+ auto future = pool.submit(test_job_throw{});
- REQUIRE_THROWS_AS(future.get(), std::runtime_error);
+ REQUIRE_THROWS_AS(future.get(), const std::runtime_error&);
}
}
diff --git a/test/t/thread/test_util.cpp b/test/t/thread/test_util.cpp
new file mode 100644
index 0000000..419329e
--- /dev/null
+++ b/test/t/thread/test_util.cpp
@@ -0,0 +1,37 @@
+#include <catch.hpp>
+
+#include <stdexcept>
+
+#include <osmium/thread/util.hpp>
+
+TEST_CASE("check_for_exception") {
+ std::promise<int> p;
+ auto f = p.get_future();
+
+ SECTION("not ready") {
+ osmium::thread::check_for_exception(f);
+ }
+ SECTION("ready") {
+ p.set_value(3);
+ osmium::thread::check_for_exception(f);
+ }
+ SECTION("no shared state") {
+ p.set_value(3);
+ REQUIRE(f.get() == 3);
+ osmium::thread::check_for_exception(f);
+ }
+}
+
+TEST_CASE("check_for_exception with exception") {
+ std::promise<int> p;
+ auto f = p.get_future();
+
+ try {
+ throw std::runtime_error{"TEST"};
+ } catch(...) {
+ p.set_exception(std::current_exception());
+ }
+
+ REQUIRE_THROWS_AS(osmium::thread::check_for_exception(f), const std::runtime_error&);
+}
+
diff --git a/test/t/util/test_cast_with_assert.cpp b/test/t/util/test_cast_with_assert.cpp
index 2c65e0c..e9aaef7 100644
--- a/test/t/util/test_cast_with_assert.cpp
+++ b/test/t/util/test_cast_with_assert.cpp
@@ -6,7 +6,7 @@ struct assert_error : public std::runtime_error {
explicit assert_error(const char* what_arg) : std::runtime_error(what_arg) {
}
};
-#define assert(x) if (!(x)) { throw(assert_error(#x)); }
+#define assert(x) if (!(x)) { throw assert_error{#x}; }
#include <osmium/util/cast.hpp>
@@ -31,7 +31,7 @@ TEST_CASE("static_cast_with_assert: cast int32_t -> int16_t should not trigger a
TEST_CASE("static_cast_with_assert: cast int32_t -> int16_t should trigger assert for large int") {
const int32_t f = 100000;
- REQUIRE_THROWS_AS(osmium::static_cast_with_assert<int16_t>(f), assert_error);
+ REQUIRE_THROWS_AS(osmium::static_cast_with_assert<int16_t>(f), const assert_error&);
}
@@ -49,7 +49,7 @@ TEST_CASE("static_cast_with_assert: cast int16_t -> uint16_t should not trigger
TEST_CASE("static_cast_with_assert: cast int16_t -> uint16_t should trigger assert for negative int") {
const int16_t f = -1;
- REQUIRE_THROWS_AS(osmium::static_cast_with_assert<uint16_t>(f), assert_error);
+ REQUIRE_THROWS_AS(osmium::static_cast_with_assert<uint16_t>(f), const assert_error&);
}
@@ -67,7 +67,7 @@ TEST_CASE("static_cast_with_assert: cast uint32_t -> uint16_t should not trigger
TEST_CASE("static_cast_with_assert: cast uint32_t -> uint16_t should trigger assert for large int") {
const uint32_t f = 100000;
- REQUIRE_THROWS_AS(osmium::static_cast_with_assert<uint16_t>(f), assert_error);
+ REQUIRE_THROWS_AS(osmium::static_cast_with_assert<uint16_t>(f), const assert_error&);
}
@@ -79,6 +79,6 @@ TEST_CASE("static_cast_with_assert: cast uint16_t -> int16_t should not trigger
TEST_CASE("static_cast_with_assert: cast uint16_t -> int16_t should trigger assert for large int") {
const uint16_t f = 65000;
- REQUIRE_THROWS_AS(osmium::static_cast_with_assert<int16_t>(f), assert_error);
+ REQUIRE_THROWS_AS(osmium::static_cast_with_assert<int16_t>(f), const assert_error&);
}
diff --git a/test/t/util/test_config.cpp b/test/t/util/test_config.cpp
new file mode 100644
index 0000000..1f168d1
--- /dev/null
+++ b/test/t/util/test_config.cpp
@@ -0,0 +1,75 @@
+#include "catch.hpp"
+
+#include <cstdlib>
+
+const char* env = nullptr;
+std::string name;
+
+const char* fake_getenv(const char* env_var) {
+ name = env_var;
+ return env;
+}
+
+#define getenv fake_getenv
+
+#include <osmium/util/config.hpp>
+
+TEST_CASE("get_pool_threads") {
+ env = nullptr;
+ REQUIRE(osmium::config::get_pool_threads() == 0);
+ REQUIRE(name == "OSMIUM_POOL_THREADS");
+ env = "";
+ REQUIRE(osmium::config::get_pool_threads() == 0);
+ env = "2";
+ REQUIRE(osmium::config::get_pool_threads() == 2);
+}
+
+TEST_CASE("use_pool_threads_for_pbf_parsing") {
+ env = nullptr;
+ REQUIRE(osmium::config::use_pool_threads_for_pbf_parsing());
+ REQUIRE(name == "OSMIUM_USE_POOL_THREADS_FOR_PBF_PARSING");
+ env = "";
+ REQUIRE(osmium::config::use_pool_threads_for_pbf_parsing());
+
+ env = "off";
+ REQUIRE_FALSE(osmium::config::use_pool_threads_for_pbf_parsing());
+ env = "OFF";
+ REQUIRE_FALSE(osmium::config::use_pool_threads_for_pbf_parsing());
+ env = "false";
+ REQUIRE_FALSE(osmium::config::use_pool_threads_for_pbf_parsing());
+ env = "no";
+ REQUIRE_FALSE(osmium::config::use_pool_threads_for_pbf_parsing());
+ env = "No";
+ REQUIRE_FALSE(osmium::config::use_pool_threads_for_pbf_parsing());
+ env = "0";
+ REQUIRE_FALSE(osmium::config::use_pool_threads_for_pbf_parsing());
+
+ env = "on";
+ REQUIRE(osmium::config::use_pool_threads_for_pbf_parsing());
+ env = "ON";
+ REQUIRE(osmium::config::use_pool_threads_for_pbf_parsing());
+ env = "true";
+ REQUIRE(osmium::config::use_pool_threads_for_pbf_parsing());
+ env = "yes";
+ REQUIRE(osmium::config::use_pool_threads_for_pbf_parsing());
+ env = "Yes";
+ REQUIRE(osmium::config::use_pool_threads_for_pbf_parsing());
+ env = "1";
+ REQUIRE(osmium::config::use_pool_threads_for_pbf_parsing());
+}
+
+TEST_CASE("get_max_queue_size") {
+ env = nullptr;
+ REQUIRE(osmium::config::get_max_queue_size("NAME", 0) == 0);
+ REQUIRE(name == "OSMIUM_MAX_NAME_QUEUE_SIZE");
+
+ REQUIRE(osmium::config::get_max_queue_size("NAME", 7) == 7);
+
+ env = "";
+ REQUIRE(osmium::config::get_max_queue_size("NAME", 7) == 7);
+ env = "0";
+ REQUIRE(osmium::config::get_max_queue_size("NAME", 7) == 7);
+ env = "3";
+ REQUIRE(osmium::config::get_max_queue_size("NAME", 7) == 3);
+}
+
diff --git a/test/t/util/test_delta.cpp b/test/t/util/test_delta.cpp
index 31b4276..f6f2a54 100644
--- a/test/t/util/test_delta.cpp
+++ b/test/t/util/test_delta.cpp
@@ -1,5 +1,6 @@
#include "catch.hpp"
+#include <cstdint>
#include <vector>
#include <osmium/util/delta.hpp>
@@ -8,8 +9,26 @@ TEST_CASE("delta encode int") {
osmium::util::DeltaEncode<int> x;
REQUIRE(x.update(17) == 17);
+ REQUIRE(x.value() == 17);
REQUIRE(x.update(10) == -7);
+ REQUIRE(x.value() == 10);
REQUIRE(x.update(-10) == -20);
+ REQUIRE(x.value() == -10);
+ x.clear();
+ REQUIRE(x.value() == 0);
+}
+
+TEST_CASE("delta encode int with int32") {
+ osmium::util::DeltaEncode<int, int32_t> x;
+
+ REQUIRE(x.update(17) == 17);
+ REQUIRE(x.value() == 17);
+ REQUIRE(x.update(10) == -7);
+ REQUIRE(x.value() == 10);
+ REQUIRE(x.update(-10) == -20);
+ REQUIRE(x.value() == -10);
+ x.clear();
+ REQUIRE(x.value() == 0);
}
TEST_CASE("delta decode int") {
@@ -18,6 +37,18 @@ TEST_CASE("delta decode int") {
REQUIRE(x.update(17) == 17);
REQUIRE(x.update(10) == 27);
REQUIRE(x.update(-40) == -13);
+ x.clear();
+ REQUIRE(x.update(17) == 17);
+}
+
+TEST_CASE("delta decode int with int32") {
+ osmium::util::DeltaDecode<int, int32_t> x;
+
+ REQUIRE(x.update(17) == 17);
+ REQUIRE(x.update(10) == 27);
+ REQUIRE(x.update(-40) == -13);
+ x.clear();
+ REQUIRE(x.update(17) == 17);
}
TEST_CASE("delta encode unsigned int") {
diff --git a/test/t/util/test_file.cpp b/test/t/util/test_file.cpp
index 475f285..17afd07 100644
--- a/test/t/util/test_file.cpp
+++ b/test/t/util/test_file.cpp
@@ -42,12 +42,12 @@ TEST_CASE("file_size") {
#endif
SECTION("illegal fd should throw") {
- REQUIRE_THROWS_AS(osmium::util::file_size(-1), std::system_error);
+ REQUIRE_THROWS_AS(osmium::util::file_size(-1), const std::system_error&);
}
SECTION("unused fd should throw") {
// its unlikely that fd 1000 is open...
- REQUIRE_THROWS_AS(osmium::util::file_size(1000), std::system_error);
+ REQUIRE_THROWS_AS(osmium::util::file_size(1000), const std::system_error&);
}
}
@@ -59,12 +59,12 @@ TEST_CASE("resize_file") {
#endif
SECTION("illegal fd should throw") {
- REQUIRE_THROWS_AS(osmium::util::resize_file(-1, 10), std::system_error);
+ REQUIRE_THROWS_AS(osmium::util::resize_file(-1, 10), const std::system_error&);
}
SECTION("unused fd should throw") {
// its unlikely that fd 1000 is open...
- REQUIRE_THROWS_AS(osmium::util::resize_file(1000, 10), std::system_error);
+ REQUIRE_THROWS_AS(osmium::util::resize_file(1000, 10), const std::system_error&);
}
}
diff --git a/test/t/util/test_options.cpp b/test/t/util/test_options.cpp
index 00bc1da..618fa89 100644
--- a/test/t/util/test_options.cpp
+++ b/test/t/util/test_options.cpp
@@ -2,62 +2,63 @@
#include <osmium/util/options.hpp>
-TEST_CASE("Options") {
-
+TEST_CASE("Set a single option value from string") {
osmium::util::Options o;
- SECTION("set a single value from string") {
- o.set("foo", "bar");
- REQUIRE("bar" == o.get("foo"));
- REQUIRE("" == o.get("empty"));
- REQUIRE("default" == o.get("empty", "default"));
+ o.set("foo", "bar");
+ REQUIRE("bar" == o.get("foo"));
+ REQUIRE("" == o.get("empty"));
+ REQUIRE("default" == o.get("empty", "default"));
- REQUIRE(!o.is_true("foo"));
- REQUIRE(!o.is_true("empty"));
+ REQUIRE_FALSE(o.is_true("foo"));
+ REQUIRE_FALSE(o.is_true("empty"));
- REQUIRE(o.is_not_false("foo"));
- REQUIRE(o.is_not_false("empty"));
+ REQUIRE(o.is_not_false("foo"));
+ REQUIRE(o.is_not_false("empty"));
- REQUIRE(1 == o.size());
- }
+ REQUIRE(1 == o.size());
+}
- SECTION("set values from booleans") {
- o.set("t", true);
- o.set("f", false);
- REQUIRE("true" == o.get("t"));
- REQUIRE("false" == o.get("f"));
- REQUIRE("" == o.get("empty"));
+TEST_CASE("Set option values from booleans") {
+ osmium::util::Options o;
- REQUIRE(o.is_true("t"));
- REQUIRE(!o.is_true("f"));
+ o.set("t", true);
+ o.set("f", false);
+ REQUIRE("true" == o.get("t"));
+ REQUIRE("false" == o.get("f"));
+ REQUIRE("" == o.get("empty"));
- REQUIRE(o.is_not_false("t"));
- REQUIRE(!o.is_not_false("f"));
+ REQUIRE(o.is_true("t"));
+ REQUIRE_FALSE(o.is_true("f"));
- REQUIRE(2 == o.size());
- }
+ REQUIRE(o.is_not_false("t"));
+ REQUIRE_FALSE(o.is_not_false("f"));
- SECTION("set value from string with equal sign") {
- o.set("foo=bar");
- REQUIRE("bar" == o.get("foo"));
- REQUIRE(1 == o.size());
- }
+ REQUIRE(2 == o.size());
+}
- SECTION("set value from string without equal sign") {
- o.set("foo");
- REQUIRE("true" == o.get("foo"));
+TEST_CASE("Set option value from string with equal sign") {
+ osmium::util::Options o;
- REQUIRE(o.is_true("foo"));
- REQUIRE(o.is_not_false("foo"));
+ o.set("foo=bar");
+ REQUIRE("bar" == o.get("foo"));
+ REQUIRE(1 == o.size());
+}
- REQUIRE(1 == o.size());
- }
+TEST_CASE("Set option value from string without equal sign") {
+ osmium::util::Options o;
+ o.set("foo");
+ REQUIRE("true" == o.get("foo"));
+
+ REQUIRE(o.is_true("foo"));
+ REQUIRE(o.is_not_false("foo"));
+
+ REQUIRE(1 == o.size());
}
TEST_CASE("Options with initializer list") {
-
- osmium::util::Options o{ { "foo", "true" }, { "bar", "17" } };
+ osmium::util::Options o{{ "foo", "true" }, { "bar", "17" }};
REQUIRE(o.get("foo") == "true");
REQUIRE(o.get("bar") == "17");
@@ -77,3 +78,41 @@ TEST_CASE("Options with initializer list") {
}
}
+TEST_CASE("Iterating over options") {
+ /*not const*/ osmium::util::Options o{{ "foo", "true" }, { "bar", "17" }};
+
+ auto it = o.begin();
+ REQUIRE(it->first == "bar");
+ REQUIRE(it->second == "17");
+ ++it;
+ REQUIRE(it->first == "foo");
+ REQUIRE(it->second == "true");
+ ++it;
+ REQUIRE(it == o.end());
+}
+
+TEST_CASE("Const iterating over options") {
+ const osmium::util::Options o{{ "foo", "true" }, { "bar", "17" }};
+
+ SECTION("begin/end") {
+ auto it = o.begin();
+ REQUIRE(it->first == "bar");
+ REQUIRE(it->second == "17");
+ ++it;
+ REQUIRE(it->first == "foo");
+ REQUIRE(it->second == "true");
+ ++it;
+ REQUIRE(it == o.end());
+ }
+ SECTION("cbegin/cend") {
+ auto it = o.cbegin();
+ REQUIRE(it->first == "bar");
+ REQUIRE(it->second == "17");
+ ++it;
+ REQUIRE(it->first == "foo");
+ REQUIRE(it->second == "true");
+ ++it;
+ REQUIRE(it == o.cend());
+ }
+}
+
diff --git a/test/t/util/test_string.cpp b/test/t/util/test_string.cpp
index e6b4e00..95e0e9a 100644
--- a/test/t/util/test_string.cpp
+++ b/test/t/util/test_string.cpp
@@ -3,62 +3,83 @@
#include <osmium/util/string.hpp>
TEST_CASE("split_string string") {
- std::string str { "foo,baramba,baz" };
- std::vector<std::string> result = {"foo", "baramba", "baz"};
+ const std::string str{"foo,baramba,baz"};
+ const std::vector<std::string> result = {"foo", "baramba", "baz"};
REQUIRE(result == osmium::split_string(str, ','));
REQUIRE(result == osmium::split_string(str, ',', true));
+ REQUIRE(result == osmium::split_string(str, ",;"));
+ REQUIRE(result == osmium::split_string(str, ",;", true));
}
TEST_CASE("split_string string without sep") {
- std::string str { "foo" };
- std::vector<std::string> result = {"foo"};
+ const std::string str{"foo"};
+ const std::vector<std::string> result = {"foo"};
REQUIRE(result == osmium::split_string(str, ','));
REQUIRE(result == osmium::split_string(str, ',', true));
+ REQUIRE(result == osmium::split_string(str, ",;"));
+ REQUIRE(result == osmium::split_string(str, ",;", true));
}
TEST_CASE("split_string string with empty at end") {
- std::string str { "foo,bar," };
- std::vector<std::string> result = {"foo", "bar", ""};
- std::vector<std::string> resultc = {"foo", "bar"};
+ const std::string str{"foo,bar,"};
+ const std::vector<std::string> result = {"foo", "bar", ""};
+ const std::vector<std::string> resultc = {"foo", "bar"};
REQUIRE(result == osmium::split_string(str, ','));
REQUIRE(resultc == osmium::split_string(str, ',', true));
+ REQUIRE(result == osmium::split_string(str, ";,"));
+ REQUIRE(resultc == osmium::split_string(str, ";,", true));
}
TEST_CASE("split_string string with empty in middle") {
- std::string str { "foo,,bar" };
- std::vector<std::string> result = {"foo", "", "bar"};
- std::vector<std::string> resultc = {"foo", "bar"};
+ const std::string str{"foo,,bar"};
+ const std::vector<std::string> result = {"foo", "", "bar"};
+ const std::vector<std::string> resultc = {"foo", "bar"};
REQUIRE(result == osmium::split_string(str, ','));
REQUIRE(resultc == osmium::split_string(str, ',', true));
+ REQUIRE(result == osmium::split_string(str, ",;"));
+ REQUIRE(resultc == osmium::split_string(str, ";,", true));
}
TEST_CASE("split_string string with empty at start") {
- std::string str { ",bar,baz" };
- std::vector<std::string> result = {"", "bar", "baz"};
- std::vector<std::string> resultc = {"bar", "baz"};
+ const std::string str{",bar,baz"};
+ const std::vector<std::string> result = {"", "bar", "baz"};
+ const std::vector<std::string> resultc = {"bar", "baz"};
REQUIRE(result == osmium::split_string(str, ','));
REQUIRE(resultc == osmium::split_string(str, ',', true));
+ REQUIRE(result == osmium::split_string(str, ";,"));
+ REQUIRE(resultc == osmium::split_string(str, ",;", true));
}
TEST_CASE("split_string sep") {
- std::string str { "," };
- std::vector<std::string> result = {"", ""};
- std::vector<std::string> resultc;
+ const std::string str{","};
+ const std::vector<std::string> result = {"", ""};
+ const std::vector<std::string> resultc;
REQUIRE(result == osmium::split_string(str, ','));
REQUIRE(resultc == osmium::split_string(str, ',', true));
+ REQUIRE(result == osmium::split_string(str, ",;"));
+ REQUIRE(resultc == osmium::split_string(str, ",;", true));
}
TEST_CASE("split_string empty string") {
- std::string str { "" };
- std::vector<std::string> result;
+ const std::string str{""};
+ const std::vector<std::string> result;
REQUIRE(result == osmium::split_string(str, ','));
REQUIRE(result == osmium::split_string(str, ',', true));
+ REQUIRE(result == osmium::split_string(str, ",;"));
+ REQUIRE(result == osmium::split_string(str, ",;", true));
+}
+
+TEST_CASE("split_string string with multiple sep characters") {
+ const std::string str{"foo,bar;baz-,blub"};
+ const std::vector<std::string> result = {"foo", "bar", "baz", "", "blub"};
+
+ REQUIRE(result == osmium::split_string(str, ";,-"));
}
diff --git a/test/t/util/test_string_matcher.cpp b/test/t/util/test_string_matcher.cpp
index e9cd39e..64b2f28 100644
--- a/test/t/util/test_string_matcher.cpp
+++ b/test/t/util/test_string_matcher.cpp
@@ -35,7 +35,7 @@ TEST_CASE("String matcher: equal") {
REQUIRE_FALSE(m.match("foobar"));
}
-TEST_CASE("String matcher: prefix") {
+TEST_CASE("String matcher: prefix from const char*") {
osmium::StringMatcher::prefix m{"foo"};
REQUIRE(m.match("foo"));
REQUIRE_FALSE(m.match("bar"));
@@ -43,7 +43,16 @@ TEST_CASE("String matcher: prefix") {
REQUIRE_FALSE(m.match(""));
}
-TEST_CASE("String matcher: substring") {
+TEST_CASE("String matcher: prefix from std::string") {
+ const std::string v{"foo"};
+ osmium::StringMatcher::prefix m{v};
+ REQUIRE(m.match("foo"));
+ REQUIRE_FALSE(m.match("bar"));
+ REQUIRE(m.match("foobar"));
+ REQUIRE_FALSE(m.match(""));
+}
+
+TEST_CASE("String matcher: substring from const char*") {
osmium::StringMatcher::substring m{"foo"};
REQUIRE(m.match("foo"));
REQUIRE_FALSE(m.match("bar"));
@@ -52,6 +61,16 @@ TEST_CASE("String matcher: substring") {
REQUIRE(m.match("xfoox"));
}
+TEST_CASE("String matcher: substring from std::string") {
+ const std::string v{"foo"};
+ osmium::StringMatcher::substring m{v};
+ REQUIRE(m.match("foo"));
+ REQUIRE_FALSE(m.match("bar"));
+ REQUIRE(m.match("foobar"));
+ REQUIRE(m.match("barfoo"));
+ REQUIRE(m.match("xfoox"));
+}
+
TEST_CASE("String matcher: empty prefix") {
osmium::StringMatcher::prefix m{""};
REQUIRE(m.match("foo"));
@@ -94,7 +113,7 @@ TEST_CASE("String matcher: list with add") {
REQUIRE_FALSE(m.match("bar"));
m.add_string("foo");
REQUIRE(m.match("foo"));
- m.add_string("bar");
+ m.add_string(std::string{"bar"});
REQUIRE(m.match("bar"));
REQUIRE_FALSE(m.match("foobar"));
REQUIRE_FALSE(m.match("baz"));
@@ -146,11 +165,25 @@ TEST_CASE("Construct StringMatcher from list") {
TEST_CASE("Construct StringMatcher") {
osmium::StringMatcher m{osmium::StringMatcher::equal{"foo"}};
+ REQUIRE(print(m) == "equal[foo]");
REQUIRE(m("foo"));
REQUIRE_FALSE(m("bar"));
m = osmium::StringMatcher::list{{"foo", "bar"}};
REQUIRE(m("foo"));
- REQUIRE(m("bar"));
+ REQUIRE(m(std::string{"bar"}));
+ REQUIRE(print(m) == "list[[foo][bar]]");
+
+ m = osmium::StringMatcher::prefix{"foo"};
+ REQUIRE(m("foo"));
+ REQUIRE(m("foobar"));
+ REQUIRE_FALSE(m("barfoo"));
+ REQUIRE(print(m) == "prefix[foo]");
+
+ m = osmium::StringMatcher::substring{"foo"};
+ REQUIRE(m("foo"));
+ REQUIRE(m("foobar"));
+ REQUIRE(m(std::string{"barfoo"}));
+ REQUIRE(print(m) == "substring[foo]");
}
diff --git a/test/t/util/test_timer_disabled.cpp b/test/t/util/test_timer_disabled.cpp
new file mode 100644
index 0000000..2bf01ff
--- /dev/null
+++ b/test/t/util/test_timer_disabled.cpp
@@ -0,0 +1,15 @@
+#include "catch.hpp"
+
+#include <chrono>
+#include <thread>
+
+#include <osmium/util/timer.hpp>
+
+TEST_CASE("timer") {
+ osmium::Timer timer;
+ timer.start();
+ std::this_thread::sleep_for(std::chrono::milliseconds(1));
+ timer.stop();
+ REQUIRE(timer.elapsed_microseconds() == 0);
+}
+
diff --git a/test/t/util/test_timer_enabled.cpp b/test/t/util/test_timer_enabled.cpp
new file mode 100644
index 0000000..c1fb665
--- /dev/null
+++ b/test/t/util/test_timer_enabled.cpp
@@ -0,0 +1,16 @@
+#include "catch.hpp"
+
+#include <chrono>
+#include <thread>
+
+#define OSMIUM_WITH_TIMER
+#include <osmium/util/timer.hpp>
+
+TEST_CASE("timer") {
+ osmium::Timer timer;
+ timer.start();
+ std::this_thread::sleep_for(std::chrono::milliseconds(1));
+ timer.stop();
+ REQUIRE(timer.elapsed_microseconds() > 900);
+}
+
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/libosmium.git
More information about the Pkg-grass-devel
mailing list