[libosmium] 01/05: Imported Upstream version 2.10.0
Bas Couwenberg
sebastic at debian.org
Sat Nov 12 05:24:51 UTC 2016
This is an automated email from the git hooks/post-receive script.
sebastic pushed a commit to branch master
in repository libosmium.
commit e92062cbdfc249ec7221a678a044e5ac0d5ca416
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date: Sat Nov 12 05:54:31 2016 +0100
Imported Upstream version 2.10.0
---
CHANGELOG.md | 58 ++-
CMakeLists.txt | 6 +-
README.md | 4 +-
benchmarks/CMakeLists.txt | 3 +
benchmarks/download_data.sh | 10 +-
benchmarks/osmium_benchmark_count.cpp | 6 +-
benchmarks/osmium_benchmark_count_tag.cpp | 6 +-
...ark_count.cpp => osmium_benchmark_mercator.cpp} | 26 +-
benchmarks/run_benchmark_mercator.sh | 22 +
benchmarks/setup.sh | 16 +-
cmake/FindOsmium.cmake | 62 ++-
examples/CMakeLists.txt | 8 +-
examples/README.md | 12 +
examples/osmium_area_test.cpp | 4 +-
examples/osmium_change_tags.cpp | 203 ++++++++++
examples/osmium_convert.cpp | 8 +-
examples/osmium_create_pois.cpp | 96 +++++
examples/osmium_dump_internal.cpp | 179 +++++++++
examples/osmium_filter_discussions.cpp | 2 +-
examples/osmium_index.cpp | 260 ------------
examples/osmium_index_lookup.cpp | 333 ++++++++++++++++
examples/osmium_pub_names.cpp | 0
examples/osmium_road_length.cpp | 0
examples/osmium_serdump.cpp | 206 ----------
include/osmium/area/assembler.hpp | 52 +--
include/osmium/area/detail/node_ref_segment.hpp | 4 +-
include/osmium/area/detail/segment_list.hpp | 2 +-
include/osmium/area/detail/vector.hpp | 20 +-
include/osmium/builder/attr.hpp | 64 +--
include/osmium/builder/builder.hpp | 91 ++---
include/osmium/builder/osm_object_builder.hpp | 314 +++++++++++++--
include/osmium/geom/factory.hpp | 2 +-
include/osmium/geom/geos.hpp | 16 +-
include/osmium/geom/relations.hpp | 10 +-
include/osmium/geom/tile.hpp | 20 +-
include/osmium/handler/disk_store.hpp | 5 +-
include/osmium/handler/node_locations_for_ways.hpp | 2 +-
include/osmium/handler/object_relations.hpp | 2 +
include/osmium/index/bool_vector.hpp | 41 +-
include/osmium/index/detail/vector_map.hpp | 6 +-
include/osmium/index/id_set.hpp | 431 ++++++++++++++++++++
include/osmium/index/index.hpp | 12 +-
include/osmium/index/map.hpp | 27 +-
include/osmium/index/map/dummy.hpp | 2 +-
include/osmium/index/map/sparse_mem_map.hpp | 2 +-
include/osmium/index/map/sparse_mem_table.hpp | 4 +-
include/osmium/io/compression.hpp | 60 ++-
include/osmium/io/detail/input_format.hpp | 23 +-
include/osmium/io/detail/o5m_input_format.hpp | 104 +++--
include/osmium/io/detail/opl_input_format.hpp | 8 +-
include/osmium/io/detail/opl_parser_functions.hpp | 80 ++--
include/osmium/io/detail/pbf_decoder.hpp | 170 ++++++--
include/osmium/io/detail/pbf_input_format.hpp | 10 +-
include/osmium/io/detail/queue_util.hpp | 13 +-
include/osmium/io/detail/xml_input_format.hpp | 94 +++--
include/osmium/io/file_format.hpp | 5 +
include/osmium/io/header.hpp | 79 +++-
include/osmium/io/reader.hpp | 63 ++-
include/osmium/memory/buffer.hpp | 82 ++--
include/osmium/memory/collection.hpp | 47 ++-
include/osmium/memory/item.hpp | 4 +-
include/osmium/osm/area.hpp | 12 +-
include/osmium/osm/changeset.hpp | 18 +-
include/osmium/osm/crc.hpp | 42 +-
include/osmium/osm/entity_bits.hpp | 24 +-
include/osmium/osm/location.hpp | 52 ++-
include/osmium/osm/node.hpp | 8 +-
include/osmium/osm/node_ref_list.hpp | 33 +-
include/osmium/osm/object.hpp | 8 +
include/osmium/osm/relation.hpp | 17 +-
include/osmium/osm/tag.hpp | 19 +-
include/osmium/osm/way.hpp | 6 +-
include/osmium/relations/collector.hpp | 58 ++-
include/osmium/relations/detail/member_meta.hpp | 40 +-
include/osmium/thread/queue.hpp | 57 ++-
include/osmium/util/progress_bar.hpp | 12 +
include/osmium/version.hpp | 4 +-
test/CMakeLists.txt | 52 ++-
test/data-tests/testdata-xml.cpp | 2 +-
test/examples/CMakeLists.txt | 21 +
test/examples/t/pub_names/CMakeLists.txt | 7 +
test/examples/t/pub_names/pubs.osm | 7 +
test/examples/t/road_length/CMakeLists.txt | 8 +
test/examples/t/road_length/road.osm | 59 +++
test/include/catch.hpp | 50 ++-
test/t/basic/test_entity_bits.cpp | 32 --
test/t/builder/test_object_builder.cpp | 444 +++++++++++++++++++++
test/t/geom/helper.hpp | 15 -
test/t/geom/test_crs.cpp | 10 +-
test/t/geom/test_exception.cpp | 8 +-
test/t/geom/test_factory_with_projection.cpp | 40 +-
test/t/geom/test_geojson.cpp | 193 ++++-----
test/t/geom/test_geos.cpp | 56 +--
test/t/geom/test_geos_wkb.cpp | 92 -----
test/t/geom/test_ogr.cpp | 128 +++---
test/t/geom/test_ogr_wkb.cpp | 100 +++++
test/t/geom/test_projection.cpp | 143 +++----
test/t/geom/test_tile.cpp | 2 -
test/t/geom/test_wkb.cpp | 18 +-
test/t/geom/wnl_helper.hpp | 6 +-
test/t/index/test_id_set.cpp | 166 ++++++++
test/t/index/test_id_to_location.cpp | 165 ++++----
test/t/io/test_compression_factory.cpp | 27 ++
test/t/io/test_reader_with_mock_parser.cpp | 8 +-
test/t/{buffer => memory}/test_buffer_basics.cpp | 0
test/t/{buffer => memory}/test_buffer_node.cpp | 140 +++----
test/t/{buffer => memory}/test_buffer_purge.cpp | 82 ++--
test/t/{basic => osm}/test_area.cpp | 0
test/t/{basic => osm}/test_box.cpp | 0
test/t/{basic => osm}/test_changeset.cpp | 67 ++--
test/t/{basic => osm}/test_crc.cpp | 0
test/t/osm/test_entity_bits.cpp | 62 +++
test/t/{basic => osm}/test_location.cpp | 119 +++---
test/t/{basic => osm}/test_node.cpp | 0
test/t/{basic => osm}/test_node_ref.cpp | 0
test/t/{basic => osm}/test_object_comparisons.cpp | 0
test/t/{basic => osm}/test_relation.cpp | 0
test/t/{basic => osm}/test_timestamp.cpp | 0
test/t/{basic => osm}/test_types_from_string.cpp | 0
test/t/{basic => osm}/test_way.cpp | 2 +-
120 files changed, 4211 insertions(+), 2031 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0d132ef..25327c8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,6 +13,53 @@ This project adheres to [Semantic Versioning](http://semver.org/).
### Fixed
+## [2.10.0] - 2016-11-11
+
+### Added
+
+- The `Reader` can take an additional optional `read_meta` flag. If this is
+ set to false the PBF input will ignore metadata on OSM objects (like version,
+ timestamp, uid, ...) which speeds up file reading by 10 to 20%.
+- New `IdSet` virtual class with two implementations: `IdSetDense` and
+ `IdSetSmall`. Used to efficiently store a set of Ids. This is often needed
+ to track, for instance, which nodes are needed for ways, etc.
+- Added more examples and better documented existing examples.
+- Add a benchmark "mercator" converting all node locations in a file to
+ WebMercator and creating geometries in WKB format.
+
+### Changed
+
+- Better queue handling makes I/O faster in some circumstances.
+- The `FindOsmium.cmake` CMake script can now check a current enough libosmium
+ version is found.
+- Builders can now be constructed with a reference to parent builder.
+- Made builders more robust by adding asserts that will catch common usage
+ problems.
+- Calling `OSMObjectBuilder::add_user()` is now optional, and the method was
+ renamed to `set_user()`. (`add_user()` is marked as deprecated.)
+- Benchmarks now show compiler and compiler options used.
+- `Builder::add_item()` now takes a reference instead of pointer (old version
+ of the function marked as deprecated).
+- GEOS support is deprecated. It does not work any more for GEOS 3.6 or newer.
+ Reason is the changed interface in GEOS 3.6. If there is interest for the
+ GEOS support, we can add support back in later (but probably using the
+ GEOS C API which is more stable than the C++ API). Some tests using GEOS
+ were rewritten to work without it.
+- The `BoolVector` has been deprecated in favour of the new `IdSet` classes.
+- Lots of code cleanups and improved API documentation in many places.
+- The relations collector can now tell you whether a relation member was in
+ the input data. See the new `is_available()` and
+ `get_availability_and_offset()` methods.
+- Updated embedded Catch unit test header to version 1.5.8.
+
+### Fixed
+
+- Parsing of coordinates starting with decimal dot and coordinates in
+ scientific notation.
+- `~` operator for `entity_bits` doesn't set unused bits any more.
+- Progress bar can now be (temporarily) removed, to allow other output.
+
+
## [2.9.0] - 2016-09-15
### Added
@@ -110,7 +157,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- New functions for iterating over specific item types in buffers
(`osmium::memory::Buffer::select()`), over specific subitems
(`osmium::OSMObject::subitems()`), and for iterating over all rings of
- an area (`osmium::Areas::outer_rings(`), `inner_rings()`).
+ an area (`osmium::Areas::outer_rings()`, `inner_rings()`).
- Debug output optionally prints CRC32 when `add_crc32` file option is set.
### Changed
@@ -267,9 +314,9 @@ This project adheres to [Semantic Versioning](http://semver.org/).
one in Writer. Calling flush() on the OutputIterator isn't needed any
more.
- Reader now throws when trying to read after eof or an error.
-- I/O functions that used to throw std::runtime_error now throw
- osmium::io_error or derived.
-- Optional parameters on osmium::io::Writer now work in any order.
+- I/O functions that used to throw `std::runtime_error` now throw
+ `osmium::io_error` or derived.
+- Optional parameters on `osmium::io::Writer` now work in any order.
### Fixed
@@ -410,7 +457,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.9.0...HEAD
+[unreleased]: https://github.com/osmcode/libosmium/compare/v2.10.0...HEAD
+[2.10.0]: https://github.com/osmcode/libosmium/compare/v2.9.0...v2.10.0
[2.9.0]: https://github.com/osmcode/libosmium/compare/v2.8.0...v2.9.0
[2.8.0]: https://github.com/osmcode/libosmium/compare/v2.7.2...v2.8.0
[2.7.2]: https://github.com/osmcode/libosmium/compare/v2.7.1...v2.7.2
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 095137b..21cf98e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -24,7 +24,7 @@ set(CMAKE_CONFIGURATION_TYPES "Debug;Release;RelWithDebInfo;MinSizeRel;Dev;Cover
project(libosmium)
set(LIBOSMIUM_VERSION_MAJOR 2)
-set(LIBOSMIUM_VERSION_MINOR 9)
+set(LIBOSMIUM_VERSION_MINOR 10)
set(LIBOSMIUM_VERSION_PATCH 0)
set(LIBOSMIUM_VERSION
@@ -285,6 +285,10 @@ if(BUILD_DATA_TESTS)
add_subdirectory(test/data-tests)
endif()
+if(BUILD_EXAMPLES)
+ add_subdirectory(test/examples)
+endif()
+
#-----------------------------------------------------------------------------
#
diff --git a/README.md b/README.md
index 68fc2f6..d526f13 100644
--- a/README.md
+++ b/README.md
@@ -4,8 +4,8 @@ http://osmcode.org/libosmium
A fast and flexible C++ library for working with OpenStreetMap data.
-[![Build Status](https://secure.travis-ci.org/osmcode/libosmium.png)](https://travis-ci.org/osmcode/libosmium)
-[![Build status](https://ci.appveyor.com/api/projects/status/mkbg6e6stdgq7c1b?svg=true)](https://ci.appveyor.com/project/Mapbox/libosmium)
+[![Build Status](https://secure.travis-ci.org/osmcode/libosmium.svg)](https://travis-ci.org/osmcode/libosmium)
+[![Build status](https://ci.appveyor.com/api/projects/status/github/osmcode/libosmium?svg=true)](https://ci.appveyor.com/project/Mapbox/libosmium)
Libosmium is developed on Linux, but also works on OSX and Windows (with some
limitations).
diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt
index e46c833..4b76fcb 100644
--- a/benchmarks/CMakeLists.txt
+++ b/benchmarks/CMakeLists.txt
@@ -12,6 +12,7 @@ set(BENCHMARKS
count
count_tag
index_map
+ mercator
static_vs_dynamic_index
write_pbf
CACHE STRING "Benchmark programs"
@@ -37,6 +38,8 @@ foreach(benchmark ${BENCHMARKS})
@ONLY)
endforeach()
+string(TOUPPER "${CMAKE_BUILD_TYPE}" _cmake_build_type)
+set(_cxx_flags "${CMAKE_CXX_FLAGS_${_cmake_build_type}}")
foreach(file setup run_benchmarks)
configure_file(${file}.sh ${CMAKE_CURRENT_BINARY_DIR}/${file}.sh @ONLY)
endforeach()
diff --git a/benchmarks/download_data.sh b/benchmarks/download_data.sh
index 8a6a8ff..be6adb9 100755
--- a/benchmarks/download_data.sh
+++ b/benchmarks/download_data.sh
@@ -4,9 +4,9 @@
#
cd $DATA_DIR
-curl --location --output 1_liechtenstein.osm.pbf http://download.geofabrik.de/europe/liechtenstein-latest.osm.pbf # about 1 MB
-curl --location --output 2_bremen.osm.pbf http://download.geofabrik.de/europe/germany/bremen-latest.osm.pbf # about 13 MB
-curl --location --output 3_sachsen.osm.pbf http://download.geofabrik.de/europe/germany/sachsen-latest.osm.pbf # about 120 MB
-curl --location --output 4_germany.osm.pbf http://download.geofabrik.de/europe/germany-latest.osm.pbf # about 2 GB
-curl --location --output 5_planet.osm.pbf http://planet.osm.org/pbf/planet-latest.osm.pbf # about 26 GB
+curl --location --output 1_liechtenstein.osm.pbf http://download.geofabrik.de/europe/liechtenstein-latest.osm.pbf # about 2 MB
+curl --location --output 2_bremen.osm.pbf http://download.geofabrik.de/europe/germany/bremen-latest.osm.pbf # about 16 MB
+curl --location --output 3_sachsen.osm.pbf http://download.geofabrik.de/europe/germany/sachsen-latest.osm.pbf # about 160 MB
+curl --location --output 4_germany.osm.pbf http://download.geofabrik.de/europe/germany-latest.osm.pbf # about 3 GB
+curl --location --output 5_planet.osm.pbf http://planet.osm.org/pbf/planet-latest.osm.pbf # about 35 GB
diff --git a/benchmarks/osmium_benchmark_count.cpp b/benchmarks/osmium_benchmark_count.cpp
index 1a16275..41f9aa0 100644
--- a/benchmarks/osmium_benchmark_count.cpp
+++ b/benchmarks/osmium_benchmark_count.cpp
@@ -19,15 +19,15 @@ struct CountHandler : public osmium::handler::Handler {
uint64_t ways = 0;
uint64_t relations = 0;
- void node(osmium::Node&) {
+ void node(const osmium::Node&) {
++nodes;
}
- void way(osmium::Way&) {
+ void way(const osmium::Way&) {
++ways;
}
- void relation(osmium::Relation&) {
+ void relation(const osmium::Relation&) {
++relations;
}
diff --git a/benchmarks/osmium_benchmark_count_tag.cpp b/benchmarks/osmium_benchmark_count_tag.cpp
index 6062ecc..5b82a7c 100644
--- a/benchmarks/osmium_benchmark_count_tag.cpp
+++ b/benchmarks/osmium_benchmark_count_tag.cpp
@@ -18,7 +18,7 @@ struct CountHandler : public osmium::handler::Handler {
uint64_t counter = 0;
uint64_t all = 0;
- void node(osmium::Node& node) {
+ void node(const osmium::Node& node) {
++all;
const char* amenity = node.tags().get_value_by_key("amenity");
if (amenity && !strcmp(amenity, "post_box")) {
@@ -26,11 +26,11 @@ struct CountHandler : public osmium::handler::Handler {
}
}
- void way(osmium::Way&) {
+ void way(const osmium::Way&) {
++all;
}
- void relation(osmium::Relation&) {
+ void relation(const osmium::Relation&) {
++all;
}
diff --git a/benchmarks/osmium_benchmark_count.cpp b/benchmarks/osmium_benchmark_mercator.cpp
similarity index 52%
copy from benchmarks/osmium_benchmark_count.cpp
copy to benchmarks/osmium_benchmark_mercator.cpp
index 1a16275..091e5c0 100644
--- a/benchmarks/osmium_benchmark_count.cpp
+++ b/benchmarks/osmium_benchmark_mercator.cpp
@@ -12,23 +12,15 @@
#include <osmium/io/any_input.hpp>
#include <osmium/handler.hpp>
#include <osmium/visitor.hpp>
+#include <osmium/geom/wkb.hpp>
+#include <osmium/geom/mercator_projection.hpp>
-struct CountHandler : public osmium::handler::Handler {
+struct GeomHandler : public osmium::handler::Handler {
- uint64_t nodes = 0;
- uint64_t ways = 0;
- uint64_t relations = 0;
+ osmium::geom::WKBFactory<osmium::geom::MercatorProjection> factory;
- void node(osmium::Node&) {
- ++nodes;
- }
-
- void way(osmium::Way&) {
- ++ways;
- }
-
- void relation(osmium::Relation&) {
- ++relations;
+ void node(const osmium::Node& node) {
+ const std::string geom = factory.create_point(node);
}
};
@@ -44,12 +36,8 @@ int main(int argc, char* argv[]) {
osmium::io::Reader reader{input_filename};
- CountHandler handler;
+ GeomHandler handler;
osmium::apply(reader, handler);
reader.close();
-
- std::cout << "Nodes: " << handler.nodes << "\n";
- std::cout << "Ways: " << handler.ways << "\n";
- std::cout << "Relations: " << handler.relations << "\n";
}
diff --git a/benchmarks/run_benchmark_mercator.sh b/benchmarks/run_benchmark_mercator.sh
new file mode 100755
index 0000000..a520727
--- /dev/null
+++ b/benchmarks/run_benchmark_mercator.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+#
+# run_benchmark_mercator.sh
+#
+
+set -e
+
+BENCHMARK_NAME=mercator
+
+. @CMAKE_BINARY_DIR@/benchmarks/setup.sh
+
+CMD=$OB_DIR/osmium_benchmark_$BENCHMARK_NAME
+
+echo "# file size num mem time cpu_kernel cpu_user cpu_percent cmd options"
+for data in $OB_DATA_FILES; do
+ filename=`basename $data`
+ filesize=`stat --format="%s" --dereference $data`
+ for n in $OB_SEQ; do
+ $OB_TIME_CMD -f "$filename $filesize $n $OB_TIME_FORMAT" $CMD $data 2>&1 >/dev/null | sed -e "s%$DATA_DIR/%%" | sed -e "s%$OB_DIR/%%"
+ done
+done
+
diff --git a/benchmarks/setup.sh b/benchmarks/setup.sh
index 9733bfe..f8901c2 100755
--- a/benchmarks/setup.sh
+++ b/benchmarks/setup.sh
@@ -9,6 +9,10 @@ if [ -z $DATA_DIR ]; then
fi
OB_DIR=@CMAKE_BINARY_DIR@/benchmarks
+OB_BUILD_TYPE=@CMAKE_BUILD_TYPE@
+OB_COMPILER=@CMAKE_CXX_COMPILER@
+OB_COMPILER_VERSION=`$OB_COMPILER --version | head -1`
+OB_CXXFLAGS="@_cxx_flags@"
OB_RUNS=3
OB_SEQ=`seq -s' ' 1 $OB_RUNS`
@@ -20,11 +24,17 @@ OB_DATA_FILES=`find -L $DATA_DIR -mindepth 1 -maxdepth 1 -type f | sort`
echo "BENCHMARK: $BENCHMARK_NAME"
echo "---------------------"
+echo "BUILD:"
+echo "build type\t: $OB_BUILD_TYPE"
+echo "compiler\t: $OB_COMPILER"
+echo "CXX version\t: $OB_COMPILER_VERSION"
+echo "CXX flags\t: $OB_CXXFLAGS"
+echo "---------------------"
echo "CPU:"
grep '^model name' /proc/cpuinfo | tail -1
-grep '^cpu MHz' /proc/cpuinfo | tail -1
-grep '^cpu cores' /proc/cpuinfo | tail -1
-grep '^siblings' /proc/cpuinfo | tail -1
+grep '^cpu MHz' /proc/cpuinfo | tail -1
+grep '^cpu cores' /proc/cpuinfo | tail -1
+grep '^siblings' /proc/cpuinfo | tail -1
echo "---------------------"
echo "MEMORY:"
diff --git a/cmake/FindOsmium.cmake b/cmake/FindOsmium.cmake
index fba8ffb..2224e18 100644
--- a/cmake/FindOsmium.cmake
+++ b/cmake/FindOsmium.cmake
@@ -2,8 +2,8 @@
#
# FindOsmium.cmake
#
-# Find the Libosmium headers and, optionally, several components needed for
-# different Libosmium functions.
+# Find the Libosmium headers and, optionally, several components needed
+# for different Libosmium functions.
#
#----------------------------------------------------------------------
#
@@ -18,9 +18,12 @@
#
# Then add the following in your CMakeLists.txt:
#
-# find_package(Osmium REQUIRED COMPONENTS <XXX>)
+# find_package(Osmium [version] REQUIRED COMPONENTS <XXX>)
# include_directories(SYSTEM ${OSMIUM_INCLUDE_DIRS})
#
+# The version number is optional. If it is not set, any version of
+# libosmium will do.
+#
# For the <XXX> substitute a space separated list of one or more of the
# following components:
#
@@ -51,10 +54,9 @@
#
#----------------------------------------------------------------------
-# Look for the header file.
-find_path(OSMIUM_INCLUDE_DIR osmium/osm.hpp
- PATH_SUFFIXES include
- PATHS
+# This is the list of directories where we look for osmium and protozero
+# includes.
+set(_osmium_include_path
../libosmium
~/Library/Frameworks
/Library/Frameworks
@@ -62,6 +64,22 @@ find_path(OSMIUM_INCLUDE_DIR osmium/osm.hpp
/opt
)
+# Look for the header file.
+find_path(OSMIUM_INCLUDE_DIR osmium/version.hpp
+ PATH_SUFFIXES include
+ PATHS ${_osmium_include_path}
+)
+
+# Check libosmium version number
+if(Osmium_FIND_VERSION)
+ file(STRINGS "${OSMIUM_INCLUDE_DIR}/osmium/version.hpp" _libosmium_version_define REGEX "#define LIBOSMIUM_VERSION_STRING")
+ if("${_libosmium_version_define}" MATCHES "#define LIBOSMIUM_VERSION_STRING \"([0-9.]+)\"")
+ set(_libosmium_version "${CMAKE_MATCH_1}")
+ else()
+ set(_libosmium_version "unknown")
+ endif()
+endif()
+
set(OSMIUM_INCLUDE_DIRS "${OSMIUM_INCLUDE_DIR}")
#----------------------------------------------------------------------
@@ -95,17 +113,31 @@ if(Osmium_USE_PBF)
find_package(ZLIB)
find_package(Threads)
- list(APPEND OSMIUM_EXTRA_FIND_VARS ZLIB_FOUND Threads_FOUND)
- if(ZLIB_FOUND AND Threads_FOUND)
+ message(STATUS "Looking for protozero")
+ find_path(PROTOZERO_INCLUDE_DIR protozero/version.hpp
+ PATH_SUFFIXES include
+ PATHS ${_osmium_include_path}
+ ${OSMIUM_INCLUDE_DIR}
+ )
+ if(PROTOZERO_INCLUDE_DIR)
+ message(STATUS "Looking for protozero - found")
+ else()
+ message(STATUS "Looking for protozero - not found")
+ endif()
+
+ list(APPEND OSMIUM_EXTRA_FIND_VARS ZLIB_FOUND Threads_FOUND PROTOZERO_INCLUDE_DIR)
+ if(ZLIB_FOUND AND Threads_FOUND AND PROTOZERO_INCLUDE_DIR)
list(APPEND OSMIUM_PBF_LIBRARIES
${ZLIB_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT}
)
if(WIN32)
+ # This is needed for the ntohl() function
list(APPEND OSMIUM_PBF_LIBRARIES ws2_32)
endif()
list(APPEND OSMIUM_INCLUDE_DIRS
${ZLIB_INCLUDE_DIR}
+ ${PROTOZERO_INCLUDE_DIR}
)
else()
message(WARNING "Osmium: Can not find some libraries for PBF input/output, please install them or configure the paths.")
@@ -203,7 +235,7 @@ if(Osmium_USE_SPARSEHASH)
if(SPARSEHASH_INCLUDE_DIR)
# Find size of sparsetable::size_type. This does not work on older
# CMake versions because they can do this check only in C, not in C++.
- if (NOT CMAKE_VERSION VERSION_LESS 3.0)
+ if(NOT CMAKE_VERSION VERSION_LESS 3.0)
include(CheckTypeSize)
set(CMAKE_REQUIRED_INCLUDES ${SPARSEHASH_INCLUDE_DIR})
set(CMAKE_EXTRA_INCLUDE_FILES "google/sparsetable")
@@ -253,13 +285,15 @@ endif()
# Check that all required libraries are available
#
#----------------------------------------------------------------------
-if (OSMIUM_EXTRA_FIND_VARS)
+if(OSMIUM_EXTRA_FIND_VARS)
list(REMOVE_DUPLICATES OSMIUM_EXTRA_FIND_VARS)
endif()
-# Handle the QUIETLY and REQUIRED arguments and set OSMIUM_FOUND to TRUE if
-# all listed variables are TRUE.
+# Handle the QUIETLY and REQUIRED arguments and the optional version check
+# and set OSMIUM_FOUND to TRUE if all listed variables are TRUE.
include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(Osmium REQUIRED_VARS OSMIUM_INCLUDE_DIR ${OSMIUM_EXTRA_FIND_VARS})
+find_package_handle_standard_args(Osmium
+ REQUIRED_VARS OSMIUM_INCLUDE_DIR ${OSMIUM_EXTRA_FIND_VARS}
+ VERSION_VAR _libosmium_version)
unset(OSMIUM_EXTRA_FIND_VARS)
#----------------------------------------------------------------------
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index b47cfdc..ac07896 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -10,18 +10,20 @@ message(STATUS "Configuring examples")
set(EXAMPLES
area_test
+ change_tags
convert
count
+ create_pois
debug
+ dump_internal
filter_discussions
- index
+ index_lookup
location_cache_create
location_cache_use
pub_names
read
read_with_progress
road_length
- serdump
tiles
CACHE STRING "Example programs"
)
@@ -32,7 +34,7 @@ set(EXAMPLES
# Examples depending on wingetopt
#
#-----------------------------------------------------------------------------
-set(GETOPT_EXAMPLES area_test convert index serdump)
+set(GETOPT_EXAMPLES area_test convert index_lookup)
if(NOT GETOPT_MISSING)
foreach(example ${GETOPT_EXAMPLES})
list(APPEND EXAMPLE_LIBS_${example} ${GETOPT_LIBRARY})
diff --git a/examples/README.md b/examples/README.md
index e291032..55bd406 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -18,12 +18,24 @@ them.
## Still reasonably simple examples
+* `osmium_read_with_progress`
* `osmium_filter_discussions`
* `osmium_convert`
+* `osmium_pub_names`
+* `osmium_road_length`
## More advanced examples
* `osmium_area_test`
+* `osmium_create_pois`
+
+## Even more advanced examples
+
+* `osmium_change_tags`
+* `osmium_location_cache_create`
+* `osmium_location_cache_use`
+* `osmium_dump_internal`
+* `osmium_index_lookup`
## License
diff --git a/examples/osmium_area_test.cpp b/examples/osmium_area_test.cpp
index 0303374..0c849a7 100644
--- a/examples/osmium_area_test.cpp
+++ b/examples/osmium_area_test.cpp
@@ -106,7 +106,7 @@ int main(int argc, char* argv[]) {
// Read options from command line.
while (true) {
- int c = getopt_long(argc, argv, "hwo", long_options, 0);
+ const int c = getopt_long(argc, argv, "hwo", long_options, 0);
if (c == -1) {
break;
}
@@ -126,7 +126,7 @@ int main(int argc, char* argv[]) {
}
}
- int remaining_args = argc - optind;
+ const int remaining_args = argc - optind;
if (remaining_args != 1) {
std::cerr << "Usage: " << argv[0] << " [OPTIONS] OSMFILE\n";
std::exit(1);
diff --git a/examples/osmium_change_tags.cpp b/examples/osmium_change_tags.cpp
new file mode 100644
index 0000000..a7c1904
--- /dev/null
+++ b/examples/osmium_change_tags.cpp
@@ -0,0 +1,203 @@
+/*
+
+ EXAMPLE osmium_change_tags
+
+ An example how tags in OSM files can be removed or changed. Removes
+ "created_by" tags and changes tag "landuse=forest" into "natural_wood".
+
+ DEMONSTRATES USE OF:
+ * file input and output
+ * Osmium buffers
+ * your own handler
+ * access to tags
+ * using builders to write data
+
+ SIMPLER EXAMPLES you might want to understand first:
+ * osmium_read
+ * osmium_count
+ * osmium_pub_names
+
+ LICENSE
+ The code in this example file is released into the Public Domain.
+
+*/
+
+#include <cstdlib> // for std::exit
+#include <cstring> // for std::strcmp
+#include <exception> // for std::exception
+#include <iostream> // for std::cout, std::cerr
+#include <string> // for std::string
+#include <utility> // for std::move
+
+// Allow any format of input files (XML, PBF, ...)
+#include <osmium/io/any_input.hpp>
+
+// Allow any format of output files (XML, PBF, ...)
+#include <osmium/io/any_output.hpp>
+
+// We want to use the builder interface
+#include <osmium/builder/osm_object_builder.hpp>
+
+// We want to use the handler interface
+#include <osmium/handler.hpp>
+
+// For osmium::apply()
+#include <osmium/visitor.hpp>
+
+// The functions in this class will be called for each object in the input
+// and will write a (changed) copy of those objects to the given buffer.
+class RewriteHandler : public osmium::handler::Handler {
+
+ osmium::memory::Buffer& m_buffer;
+
+ // Copy attributes common to all OSM objects (nodes, ways, and relations).
+ template <typename T>
+ void copy_attributes(T& builder, const osmium::OSMObject& object) {
+ // The setter functions on the builder object all return the same
+ // builder object so they can be chained.
+ builder.set_id(object.id())
+ .set_version(object.version())
+ .set_changeset(object.changeset())
+ .set_timestamp(object.timestamp())
+ .set_uid(object.uid())
+ .set_user(object.user());
+ }
+
+ // Copy all tags with two changes:
+ // * Do not copy "created_by" tags
+ // * Change "landuse=forest" into "natural=wood"
+ void copy_tags(osmium::builder::Builder& parent, const osmium::TagList& tags) {
+
+ // The TagListBuilder is used to create a list of tags. The parameter
+ // to create it is a reference to the builder of the object that
+ // should have those tags.
+ osmium::builder::TagListBuilder builder{parent};
+
+ // Iterate over all tags and build new tags using the new builder
+ // based on the old ones.
+ for (const auto& tag : tags) {
+ if (std::strcmp(tag.key(), "created_by")) {
+ if (!std::strcmp(tag.key(), "landuse") && !std::strcmp(tag.value(), "forest")) {
+ // add_tag() can be called with key and value C strings
+ builder.add_tag("natural", "wood");
+ } else {
+ // add_tag() can also be called with an osmium::Tag
+ builder.add_tag(tag);
+ }
+ }
+ }
+ }
+
+public:
+
+ // Constructor. New data will be added to the given buffer.
+ RewriteHandler(osmium::memory::Buffer& buffer) :
+ m_buffer(buffer) {
+ }
+
+ // The node handler is called for each node in the input data.
+ void node(const osmium::Node& node) {
+ // Open a new scope, because the NodeBuilder we are creating has to
+ // be destructed, before we can call commit() below.
+ {
+ // To create a node, we need a NodeBuilder object. It will create
+ // the node in the given buffer.
+ osmium::builder::NodeBuilder builder{m_buffer};
+
+ // Copy common object attributes over to the new node.
+ copy_attributes(builder, node);
+
+ // Copy the location over to the new node.
+ builder.set_location(node.location());
+
+ // Copy (changed) tags.
+ copy_tags(builder, node.tags());
+ }
+
+ // Once the object is written to the buffer completely, we have to call
+ // commit().
+ m_buffer.commit();
+ }
+
+ // The way handler is called for each node in the input data.
+ void way(const osmium::Way& way) {
+ {
+ osmium::builder::WayBuilder builder{m_buffer};
+ copy_attributes(builder, way);
+ copy_tags(builder, way.tags());
+
+ // Copy the node list over to the new way.
+ builder.add_item(way.nodes());
+ }
+ m_buffer.commit();
+ }
+
+ // The relation handler is called for each node in the input data.
+ void relation(const osmium::Relation& relation) {
+ {
+ osmium::builder::RelationBuilder builder{m_buffer};
+ copy_attributes(builder, relation);
+ copy_tags(builder, relation.tags());
+
+ // Copy the relation member list over to the new way.
+ builder.add_item(relation.members());
+ }
+ m_buffer.commit();
+ }
+
+}; // class RewriteHandler
+
+int main(int argc, char* argv[]) {
+ if (argc != 3) {
+ std::cerr << "Usage: " << argv[0] << " INFILE OUTFILE\n";
+ std::exit(1);
+ }
+
+ // Get input and output file names from command line.
+ std::string input_file_name{argv[1]};
+ std::string output_file_name{argv[2]};
+
+ try {
+ // Initialize Reader
+ osmium::io::Reader reader{input_file_name};
+
+ // Get header from input file and change the "generator" setting to
+ // ourselves.
+ osmium::io::Header header = reader.header();
+ header.set("generator", "osmium_change_tags");
+
+ // 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};
+
+ // Read in buffers with OSM objects until there are no more.
+ while (osmium::memory::Buffer input_buffer = reader.read()) {
+ // Create an empty buffer with the same size as the input buffer.
+ // We'll copy the changed data into output buffer, the changes
+ // are small, so the output buffer needs to be about the same size.
+ // In case it has to be bigger, we allow it to grow automatically
+ // by adding the auto_grow::yes parameter.
+ osmium::memory::Buffer output_buffer{input_buffer.committed(), osmium::memory::Buffer::auto_grow::yes};
+
+ // Construct a handler as defined above and feed the input buffer
+ // to it.
+ RewriteHandler handler{output_buffer};
+ osmium::apply(input_buffer, handler);
+
+ // Write out the contents of the output buffer.
+ writer(std::move(output_buffer));
+ }
+
+ // Explicitly close the writer and reader. Will throw an exception if
+ // there is a problem. If you wait for the destructor to close the writer
+ // and reader, you will not notice the problem, because destructors must
+ // not throw.
+ writer.close();
+ reader.close();
+ } catch (const std::exception& e) {
+ // All exceptions used by the Osmium library derive from std::exception.
+ std::cerr << e.what() << "\n";
+ std::exit(1);
+ }
+}
+
diff --git a/examples/osmium_convert.cpp b/examples/osmium_convert.cpp
index 48a0823..0ced82c 100644
--- a/examples/osmium_convert.cpp
+++ b/examples/osmium_convert.cpp
@@ -67,7 +67,7 @@ int main(int argc, char* argv[]) {
// Read options from command line.
while (true) {
- int c = getopt_long(argc, argv, "dhf:t:", long_options, 0);
+ const int c = getopt_long(argc, argv, "dhf:t:", long_options, 0);
if (c == -1) {
break;
}
@@ -87,7 +87,7 @@ int main(int argc, char* argv[]) {
}
}
- int remaining_args = argc - optind;
+ const int remaining_args = argc - optind;
if (remaining_args > 2) {
std::cerr << "Usage: " << argv[0] << " [OPTIONS] [INFILE [OUTFILE]]\n";
std::exit(1);
@@ -124,13 +124,13 @@ int main(int argc, char* argv[]) {
osmium::io::Reader reader{input_file};
// Get header from input file and change the "generator" setting to
- // outselves.
+ // ourselves.
osmium::io::Header header = reader.header();
header.set("generator", "osmium_convert");
// 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, header, osmium::io::overwrite::allow);
+ osmium::io::Writer writer{output_file, header, osmium::io::overwrite::allow};
// Copy the contents from the input to the output file one buffer at
// a time. This is much easier and faster than copying each object
diff --git a/examples/osmium_create_pois.cpp b/examples/osmium_create_pois.cpp
new file mode 100644
index 0000000..ff79cbb
--- /dev/null
+++ b/examples/osmium_create_pois.cpp
@@ -0,0 +1,96 @@
+/*
+
+ EXAMPLE osmium_create_pois
+
+ Showing how to create nodes for points of interest out of thin air.
+
+ DEMONSTRATES USE OF:
+ * file output
+ * Osmium buffers
+ * using builders to write data
+
+ SIMPLER EXAMPLES you might want to understand first:
+ * osmium_read
+ * osmium_count
+ * osmium_pub_names
+
+ LICENSE
+ The code in this example file is released into the Public Domain.
+
+*/
+
+#include <cstdlib> // for std::exit
+#include <cstring> // for std::strcmp
+#include <ctime> // for std::time
+#include <exception> // for std::exception
+#include <iostream> // for std::cout, std::cerr
+#include <string> // for std::string
+#include <utility> // for std::move
+
+// Allow any format of output files (XML, PBF, ...)
+#include <osmium/io/any_output.hpp>
+
+// We want to use the builder interface
+#include <osmium/builder/osm_object_builder.hpp>
+#include <osmium/builder/attr.hpp>
+
+// Declare this to use the functions starting with the underscore (_) below.
+using namespace osmium::builder::attr;
+
+int main(int argc, char* argv[]) {
+ if (argc != 2) {
+ std::cerr << "Usage: " << argv[0] << " OUTFILE\n";
+ std::exit(1);
+ }
+
+ // Get output file name from command line.
+ std::string output_file_name{argv[1]};
+
+ try {
+ // Create a buffer where all objects will live. Use a sensible initial
+ // buffer size and set the buffer to automatically grow if needed.
+ const size_t initial_buffer_size = 10000;
+ osmium::memory::Buffer buffer{initial_buffer_size, osmium::memory::Buffer::auto_grow::yes};
+
+ // Add nodes to the buffer. This is, of course, only an example.
+ // You can set any of the attributes and more tags, etc. Ways and
+ // relations can be added in a similar way.
+ osmium::builder::add_node(buffer,
+ _id(-1),
+ _version(1),
+ _timestamp(std::time(nullptr)),
+ _location(osmium::Location{1.23, 3.45}),
+ _tag("amenity", "post_box")
+ );
+
+ osmium::builder::add_node(buffer,
+ _id(-2),
+ _version(1),
+ _timestamp(std::time(nullptr)),
+ _location(1.24, 3.46),
+ _tags({{"amenity", "restaurant"},
+ {"name", "Chez OSM"}})
+ );
+
+ // Create header and set generator.
+ osmium::io::Header header;
+ header.set("generator", "osmium_create_pois");
+
+ // 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};
+
+ // Write out the contents of the output buffer.
+ writer(std::move(buffer));
+
+ // Explicitly close the writer. Will throw an exception if there is
+ // a problem. If you wait for the destructor to close the writer, you
+ // will not notice the problem, because destructors must not throw.
+ writer.close();
+ } catch (const std::exception& e) {
+ // All exceptions used by the Osmium library derive from std::exception.
+ std::cerr << e.what() << "\n";
+ std::exit(1);
+ }
+}
+
diff --git a/examples/osmium_dump_internal.cpp b/examples/osmium_dump_internal.cpp
new file mode 100644
index 0000000..dbc50db
--- /dev/null
+++ b/examples/osmium_dump_internal.cpp
@@ -0,0 +1,179 @@
+/*
+
+ EXAMPLE osmium_dump_internal
+
+ Reads an OSM file and dumps the internal datastructure to disk including
+ 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.
+
+ You can use the osmium_index example program to inspect the indexes.
+
+ DEMONSTRATES USE OF:
+ * file input
+ * indexes and maps
+ * use of the DiskStore handler
+ * use of the ObjectRelations handler
+
+ SIMPLER EXAMPLES you might want to understand first:
+ * osmium_read
+ * osmium_count
+ * osmium_road_length
+ * osmium_location_cache_create
+ * osmium_location_cache_use
+
+ LICENSE
+ The code in this example file is released into the Public Domain.
+
+*/
+
+#include <cerrno> // for errno
+#include <cstring> // for std::strerror
+#include <cstdlib> // for std::exit
+#include <iostream> // for std::cout, std::cerr
+#include <string> // for std::string
+#include <sys/stat.h> // for open
+#include <sys/types.h> // for open
+
+#ifdef _MSC_VER
+# include <direct.h>
+#endif
+
+// Allow any format of input files (XML, PBF, ...)
+#include <osmium/io/any_input.hpp>
+
+// The DiskStore handler
+#include <osmium/handler/disk_store.hpp>
+
+// The ObjectRelations handler
+#include <osmium/handler/object_relations.hpp>
+
+// The indexes
+#include <osmium/index/map/sparse_mem_array.hpp>
+#include <osmium/index/multimap/sparse_mem_array.hpp>
+
+using offset_index_type = osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, size_t>;
+using map_type = osmium::index::multimap::SparseMemArray<osmium::unsigned_object_id_type, osmium::unsigned_object_id_type>;
+
+/**
+ * Small class wrapping index files, basically making sure errors are handled
+ * and the files are closed on destruction.
+ */
+class IndexFile {
+
+ int m_fd;
+
+public:
+
+ IndexFile(const std::string& filename) :
+ m_fd(::open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666)) {
+ if (m_fd < 0) {
+ std::cerr << "Can't open index file '" << filename << "': " << std::strerror(errno) << "\n";
+ std::exit(2);
+ }
+ }
+
+ ~IndexFile() {
+ if (m_fd >= 0) {
+ close(m_fd);
+ }
+ }
+
+ int fd() const noexcept {
+ return m_fd;
+ }
+
+}; // class IndexFile
+
+int main(int argc, char* argv[]) {
+ if (argc != 3) {
+ std::cerr << "Usage: " << argv[0] << " OSMFILE DIR\n";
+ std::exit(2);
+ }
+
+ const std::string input_file_name{argv[1]};
+ const std::string output_dir{argv[2]};
+
+ // Create output directory. Ignore the error if it already exists.
+#ifndef _WIN32
+ const int result = ::mkdir(output_dir.c_str(), 0777);
+#else
+ const int result = mkdir(output_dir.c_str());
+#endif
+ if (result == -1 && errno != EEXIST) {
+ std::cerr << "Problem creating directory '" << output_dir << "': " << std::strerror(errno) << "\n";
+ std::exit(2);
+ }
+
+ // Create the output file which will contain our serialized OSM data
+ const std::string data_file{output_dir + "/data.osm.ser"};
+ const int data_fd = ::open(data_file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (data_fd < 0) {
+ std::cerr << "Can't open data file '" << data_file << "': " << std::strerror(errno) << "\n";
+ std::exit(2);
+ }
+
+ // These indexes store the offset in the data file where each node, way,
+ // or relation is stored.
+ offset_index_type node_index;
+ offset_index_type way_index;
+ offset_index_type relation_index;
+
+ // This handler will dump the internal data to disk using the given file
+ // descriptor while updating the indexes.
+ osmium::handler::DiskStore disk_store_handler{data_fd, node_index, way_index, relation_index};
+
+ // These indexes store the mapping from node id to the ids of the ways
+ // containing this node, and from node/way/relation ids to the ids of the
+ // relations containing those objects.
+ map_type map_node2way;
+ map_type map_node2relation;
+ map_type map_way2relation;
+ map_type map_relation2relation;
+
+ // This handler will update the map indexes.
+ osmium::handler::ObjectRelations object_relations_handler{map_node2way, map_node2relation, map_way2relation, map_relation2relation};
+
+ // Read OSM data buffer by buffer.
+ osmium::io::Reader reader{input_file_name};
+
+ while (osmium::memory::Buffer buffer = reader.read()) {
+ // Write buffer to disk and update indexes.
+ disk_store_handler(buffer);
+
+ // Update object relation index maps.
+ osmium::apply(buffer, object_relations_handler);
+ }
+
+ reader.close();
+
+ // Write out node, way, and relation offset indexes to disk.
+ IndexFile nodes_idx{output_dir + "/nodes.idx"};
+ node_index.dump_as_list(nodes_idx.fd());
+
+ IndexFile ways_idx{output_dir + "/ways.idx"};
+ way_index.dump_as_list(ways_idx.fd());
+
+ IndexFile relations_idx{output_dir + "/relations.idx"};
+ relation_index.dump_as_list(relations_idx.fd());
+
+ // Sort the maps (so later binary search will work on them) and write
+ // them to disk.
+ map_node2way.sort();
+ IndexFile node2way_idx{output_dir + "/node2way.map"};
+ map_node2way.dump_as_list(node2way_idx.fd());
+
+ map_node2relation.sort();
+ IndexFile node2relation_idx{output_dir + "/node2rel.map"};
+ map_node2relation.dump_as_list(node2relation_idx.fd());
+
+ map_way2relation.sort();
+ IndexFile way2relation_idx{output_dir + "/way2rel.map"};
+ map_way2relation.dump_as_list(way2relation_idx.fd());
+
+ map_relation2relation.sort();
+ IndexFile relation2relation_idx{output_dir + "/rel2rel.map"};
+ map_relation2relation.dump_as_list(relation2relation_idx.fd());
+}
+
diff --git a/examples/osmium_filter_discussions.cpp b/examples/osmium_filter_discussions.cpp
index 6334981..c2a94e5 100644
--- a/examples/osmium_filter_discussions.cpp
+++ b/examples/osmium_filter_discussions.cpp
@@ -67,7 +67,7 @@ int main(int argc, char* argv[]) {
// file for the output file. This will copy over some header information.
// The last parameter will tell the writer that it is allowed to overwrite
// an existing file. Without it, it will refuse to do so.
- osmium::io::Writer writer(output_file, header, osmium::io::overwrite::allow);
+ osmium::io::Writer writer{output_file, header, osmium::io::overwrite::allow};
// Create range of input iterators that will iterator over all changesets
// delivered from input file through the "reader".
diff --git a/examples/osmium_index.cpp b/examples/osmium_index.cpp
deleted file mode 100644
index 478b6c6..0000000
--- a/examples/osmium_index.cpp
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
-
- Example program to look at Osmium indexes on disk.
-
- The code in this example file is released into the Public Domain.
-
-*/
-
-#include <fcntl.h>
-#include <iomanip>
-#include <iostream>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <getopt.h>
-
-#include <osmium/index/map/dense_file_array.hpp>
-#include <osmium/index/map/sparse_file_array.hpp>
-#include <osmium/osm/location.hpp>
-#include <osmium/osm/types.hpp>
-
-template <typename TKey, typename TValue>
-class IndexSearch {
-
- typedef typename osmium::index::map::DenseFileArray<TKey, TValue> dense_index_type;
- typedef typename osmium::index::map::SparseFileArray<TKey, TValue> sparse_index_type;
-
- int m_fd;
- bool m_dense_format;
-
- void dump_dense() {
- dense_index_type index(m_fd);
-
- for (std::size_t i = 0; i < index.size(); ++i) {
- if (index.get(i) != TValue()) {
- std::cout << i << " " << index.get(i) << "\n";
- }
- }
- }
-
- void dump_sparse() {
- sparse_index_type index(m_fd);
-
- for (auto& element : index) {
- std::cout << element.first << " " << element.second << "\n";
- }
- }
-
- bool search_dense(TKey key) {
- dense_index_type index(m_fd);
-
- try {
- TValue value = index.get(key);
- std::cout << key << " " << value << "\n";
- } catch (...) {
- std::cout << key << " not found\n";
- return false;
- }
-
- return true;
- }
-
- bool search_sparse(TKey key) {
- typedef typename sparse_index_type::element_type element_type;
- sparse_index_type index(m_fd);
-
- element_type elem {key, TValue()};
- auto positions = std::equal_range(index.begin(), index.end(), elem, [](const element_type& lhs, const element_type& rhs) {
- return lhs.first < rhs.first;
- });
- if (positions.first == positions.second) {
- std::cout << key << " not found\n";
- return false;
- }
-
- for (auto& it = positions.first; it != positions.second; ++it) {
- std::cout << it->first << " " << it->second << "\n";
- }
-
- return true;
- }
-
-public:
-
- IndexSearch(int fd, bool dense_format) :
- m_fd(fd),
- m_dense_format(dense_format) {
- }
-
- void dump() {
- if (m_dense_format) {
- dump_dense();
- } else {
- dump_sparse();
- }
- }
-
- bool search(TKey key) {
- if (m_dense_format) {
- return search_dense(key);
- } else {
- return search_sparse(key);
- }
- }
-
- bool search(const std::vector<TKey>& keys) {
- bool found_all = true;
-
- for (const auto key : keys) {
- if (!search(key)) {
- found_all = false;
- }
- }
-
- return found_all;
- }
-
-}; // class IndexSearch
-
-enum return_code : int {
- okay = 0,
- not_found = 1,
- error = 2,
- fatal = 3
-};
-
-class Options {
-
- std::vector<osmium::unsigned_object_id_type> m_ids;
- std::string m_type;
- std::string m_filename;
- bool m_dump = false;
- bool m_array_format = false;
- bool m_list_format = false;
-
- void print_help() {
- std::cout << "Usage: osmium_index [OPTIONS]\n\n"
- << "-h, --help Print this help message\n"
- << "-a, --array=FILE Read given index file in array format\n"
- << "-l, --list=FILE Read given index file in list format\n"
- << "-d, --dump Dump contents of index file to STDOUT\n"
- << "-s, --search=ID Search for given id (Option can appear multiple times)\n"
- << "-t, --type=TYPE Type of value ('location' or 'offset')\n"
- ;
- }
-
-public:
-
- Options(int argc, char* argv[]) {
- 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}
- };
-
- while (true) {
- int c = getopt_long(argc, argv, "a:dhl:s:t:", long_options, 0);
- if (c == -1) {
- break;
- }
-
- switch (c) {
- case 'a':
- m_array_format = true;
- m_filename = optarg;
- break;
- case 'd':
- m_dump = true;
- break;
- case 'h':
- print_help();
- std::exit(return_code::okay);
- case 'l':
- m_list_format = true;
- m_filename = optarg;
- break;
- case 's':
- m_ids.push_back(std::atoll(optarg));
- break;
- case 't':
- m_type = optarg;
- if (m_type != "location" && m_type != "offset") {
- std::cerr << "Unknown type '" << m_type << "'. Must be 'location' or 'offset'.\n";
- std::exit(return_code::fatal);
- }
- break;
- default:
- std::exit(return_code::fatal);
- }
- }
-
- if (m_array_format == m_list_format) {
- std::cerr << "Need option --array or --list, but not both\n";
- std::exit(return_code::fatal);
- }
-
- if (m_type.empty()) {
- std::cerr << "Need --type argument.\n";
- std::exit(return_code::fatal);
- }
-
- }
-
- const std::string& filename() const noexcept {
- return m_filename;
- }
-
- bool dense_format() const noexcept {
- return m_array_format;
- }
-
- bool do_dump() const noexcept {
- return m_dump;
- }
-
- const std::vector<osmium::unsigned_object_id_type>& search_keys() const noexcept {
- return m_ids;
- }
-
- bool type_is(const char* type) const noexcept {
- return m_type == type;
- }
-
-}; // class Options
-
-int main(int argc, char* argv[]) {
- std::ios_base::sync_with_stdio(false);
-
- Options options(argc, argv);
-
- std::cout << std::fixed << std::setprecision(7);
- int fd = open(options.filename().c_str(), O_RDWR);
-
- bool result_okay = true;
-
- if (options.type_is("location")) {
- IndexSearch<osmium::unsigned_object_id_type, osmium::Location> is(fd, options.dense_format());
-
- if (options.do_dump()) {
- is.dump();
- } else {
- result_okay = is.search(options.search_keys());
- }
- } else {
- IndexSearch<osmium::unsigned_object_id_type, size_t> is(fd, options.dense_format());
-
- if (options.do_dump()) {
- is.dump();
- } else {
- result_okay = is.search(options.search_keys());
- }
- }
-
- std::exit(result_okay ? return_code::okay : return_code::not_found);
-}
-
diff --git a/examples/osmium_index_lookup.cpp b/examples/osmium_index_lookup.cpp
new file mode 100644
index 0000000..01d7e36
--- /dev/null
+++ b/examples/osmium_index_lookup.cpp
@@ -0,0 +1,333 @@
+/*
+
+ EXAMPLE osmium_index
+
+ Example program to look at Osmium indexes on disk.
+
+ You can use the osmium_dump_internal example program to create the offset
+ indexes or osmium_location_cache_create to create a node location index.
+
+ DEMONSTRATES USE OF:
+ * access to indexes on disk
+
+ SIMPLER EXAMPLES you might want to understand first:
+ * osmium_read
+ * osmium_count
+ * osmium_road_length
+ * osmium_location_cache_create
+ * osmium_location_cache_use
+
+ LICENSE
+ The code in this example file is released into the Public Domain.
+
+*/
+
+#include <algorithm> // for std::all_of, std::equal_range
+#include <cstdlib> // for std::exit
+#include <fcntl.h> // for open
+#include <getopt.h> // for getopt_long
+#include <iostream> // for std::cout, std::cerr
+#include <memory> // for std::unique_ptr
+#include <string> // for std::string
+#include <sys/stat.h> // for open
+#include <sys/types.h> // for open
+#include <vector> // for std::vector
+
+// Disk-based indexes
+#include <osmium/index/map/dense_file_array.hpp>
+#include <osmium/index/map/sparse_file_array.hpp>
+
+// osmium::Location
+#include <osmium/osm/location.hpp>
+
+// Basic Osmium types
+#include <osmium/osm/types.hpp>
+
+// Virtual class for disk index access. If offers functions to dump the
+// indexes and to search for ids in the index.
+template <typename TValue>
+class IndexAccess {
+
+ int m_fd;
+
+public:
+
+ IndexAccess(int fd) :
+ m_fd(fd) {
+ }
+
+ int fd() const noexcept {
+ return m_fd;
+ }
+
+ virtual ~IndexAccess() = default;
+
+ virtual void dump() const = 0;
+
+ virtual bool search(const osmium::unsigned_object_id_type& key) const = 0;
+
+ bool search(const std::vector<osmium::unsigned_object_id_type>& keys) const {
+ return std::all_of(keys.cbegin(), keys.cend(), [this](const osmium::unsigned_object_id_type& key) {
+ return search(key);
+ });
+ }
+
+}; // class IndexAccess
+
+// Implementation of IndexAccess for dense indexes usually used for very large
+// extracts or the planet.
+template <typename TValue>
+class IndexAccessDense : public IndexAccess<TValue> {
+
+ using index_type = typename osmium::index::map::DenseFileArray<osmium::unsigned_object_id_type, TValue>;
+
+public:
+
+ IndexAccessDense(int fd) :
+ IndexAccess<TValue>(fd) {
+ }
+
+ void dump() const override {
+ index_type index{this->fd()};
+
+ for (std::size_t i = 0; i < index.size(); ++i) {
+ if (index.get(i) != TValue{}) {
+ std::cout << i << " " << index.get(i) << "\n";
+ }
+ }
+ }
+
+ bool search(const osmium::unsigned_object_id_type& key) const override {
+ index_type index{this->fd()};
+
+ try {
+ TValue value = index.get(key);
+ std::cout << key << " " << value << "\n";
+ } catch (...) {
+ std::cout << key << " not found\n";
+ return false;
+ }
+
+ return true;
+ }
+
+}; // class IndexAccessDense
+
+// Implementation of IndexAccess for sparse indexes usually used for small or
+// medium sized extracts or for "multimap" type indexes.
+template <typename TValue>
+class IndexAccessSparse : public IndexAccess<TValue> {
+
+ using index_type = typename osmium::index::map::SparseFileArray<osmium::unsigned_object_id_type, TValue>;
+
+public:
+
+ IndexAccessSparse(int fd) :
+ IndexAccess<TValue>(fd) {
+ }
+
+ void dump() const override {
+ index_type index{this->fd()};
+
+ for (const auto& element : index) {
+ std::cout << element.first << " " << element.second << "\n";
+ }
+ }
+
+ bool search(const osmium::unsigned_object_id_type& key) const override {
+ using element_type = typename index_type::element_type;
+ index_type index{this->fd()};
+
+ element_type elem{key, TValue{}};
+ const auto positions = std::equal_range(index.begin(),
+ index.end(),
+ elem,
+ [](const element_type& lhs,
+ const element_type& rhs) {
+ return lhs.first < rhs.first;
+ });
+ if (positions.first == positions.second) {
+ std::cout << key << " not found\n";
+ return false;
+ }
+
+ for (auto it = positions.first; it != positions.second; ++it) {
+ std::cout << it->first << " " << it->second << "\n";
+ }
+
+ return true;
+ }
+
+}; // class IndexAccessSparse
+
+// This class contains the code to parse the command line arguments, check
+// them and present the results to the rest of the program in an easy-to-use
+// way.
+class Options {
+
+ std::vector<osmium::unsigned_object_id_type> m_ids;
+ std::string m_type;
+ std::string m_filename;
+ bool m_dump = false;
+ bool m_array_format = false;
+ bool m_list_format = false;
+
+ void print_help() {
+ std::cout << "Usage: osmium_index_lookup [OPTIONS]\n\n"
+ << "-h, --help Print this help message\n"
+ << "-a, --array=FILE Read given index file in array format\n"
+ << "-l, --list=FILE Read given index file in list format\n"
+ << "-d, --dump Dump contents of index file to STDOUT\n"
+ << "-s, --search=ID Search for given id (Option can appear multiple times)\n"
+ << "-t, --type=TYPE Type of value ('location', 'id', or 'offset')\n"
+ ;
+ }
+
+public:
+
+ Options(int argc, char* argv[]) {
+ if (argc == 1) {
+ print_help();
+ std::exit(1);
+ }
+
+ 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}
+ };
+
+ while (true) {
+ const int c = getopt_long(argc, argv, "a:dhl:s:t:", long_options, 0);
+ if (c == -1) {
+ break;
+ }
+
+ switch (c) {
+ case 'a':
+ m_array_format = true;
+ m_filename = optarg;
+ break;
+ case 'd':
+ m_dump = true;
+ break;
+ case 'h':
+ print_help();
+ std::exit(0);
+ case 'l':
+ m_list_format = true;
+ m_filename = optarg;
+ break;
+ case 's':
+ m_ids.push_back(std::atoll(optarg));
+ break;
+ case 't':
+ m_type = optarg;
+ if (m_type != "location" && m_type != "id" && m_type != "offset") {
+ std::cerr << "Unknown type '" << m_type
+ << "'. Must be 'location', 'id', or 'offset'.\n";
+ std::exit(2);
+ }
+ break;
+ default:
+ std::exit(2);
+ }
+ }
+
+ if (m_array_format == m_list_format) {
+ std::cerr << "Need option --array or --list, but not both\n";
+ std::exit(2);
+ }
+
+ if (m_dump && !m_ids.empty()) {
+ std::cerr << "Need option --dump or --search, but not both\n";
+ std::exit(2);
+ }
+
+ if (m_type.empty()) {
+ std::cerr << "Need --type argument.\n";
+ std::exit(2);
+ }
+
+ }
+
+ const char* filename() const noexcept {
+ return m_filename.c_str();
+ }
+
+ bool dense_format() const noexcept {
+ return m_array_format;
+ }
+
+ bool do_dump() const noexcept {
+ return m_dump;
+ }
+
+ const std::vector<osmium::unsigned_object_id_type>& search_keys() const noexcept {
+ return m_ids;
+ }
+
+ bool type_is(const char* type) const noexcept {
+ return m_type == type;
+ }
+
+}; // class Options
+
+
+// Factory function to create the right IndexAccess-derived class.
+template <typename TValue>
+std::unique_ptr<IndexAccess<TValue>> create(bool dense, int fd) {
+ std::unique_ptr<IndexAccess<TValue>> ptr;
+
+ if (dense) {
+ ptr.reset(new IndexAccessDense<TValue>{fd});
+ } else {
+ ptr.reset(new IndexAccessSparse<TValue>{fd});
+ }
+
+ return ptr;
+}
+
+// Do the actual work: Either dump the index or search in the index.
+template <typename TValue>
+int run(const IndexAccess<TValue>& index, const Options& options) {
+ if (options.do_dump()) {
+ index.dump();
+ return 0;
+ } else {
+ return index.search(options.search_keys()) ? 0 : 1;
+ }
+}
+
+int main(int argc, char* argv[]) {
+ // Parse command line options.
+ Options options{argc, argv};
+
+ // Open the index file.
+ const int fd = open(options.filename(), O_RDWR);
+ if (fd < 0) {
+ std::cerr << "Can not open file '" << options.filename()
+ << "': " << std::strerror(errno) << '\n';
+ std::exit(2);
+ }
+
+ // Depending on the type of index, we have different implementations.
+ if (options.type_is("location")) {
+ // index id -> location
+ const auto index = create<osmium::Location>(options.dense_format(), fd);
+ return run(*index, options);
+ } else if (options.type_is("id")) {
+ // index id -> id
+ const auto index = create<osmium::unsigned_object_id_type>(options.dense_format(), fd);
+ return run(*index, options);
+ } else {
+ // index id -> offset
+ const auto index = create<std::size_t>(options.dense_format(), fd);
+ return run(*index, options);
+ }
+}
+
diff --git a/examples/osmium_pub_names.cpp b/examples/osmium_pub_names.cpp
old mode 100755
new mode 100644
diff --git a/examples/osmium_road_length.cpp b/examples/osmium_road_length.cpp
old mode 100755
new mode 100644
diff --git a/examples/osmium_serdump.cpp b/examples/osmium_serdump.cpp
deleted file mode 100644
index 81a6d0c..0000000
--- a/examples/osmium_serdump.cpp
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
-
- This is a small tool to dump the contents of the input file
- in serialized format to stdout.
-
- The code in this example file is released into the Public Domain.
-
-*/
-
-#include <cerrno>
-#include <cstring>
-#include <getopt.h>
-#include <iostream>
-#include <string>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#ifdef _MSC_VER
-# include <direct.h>
-#endif
-
-#include <osmium/io/any_input.hpp>
-#include <osmium/handler/disk_store.hpp>
-#include <osmium/handler/object_relations.hpp>
-
-#include <osmium/index/map/sparse_mem_array.hpp>
-#include <osmium/index/multimap/sparse_mem_multimap.hpp>
-#include <osmium/index/multimap/sparse_mem_array.hpp>
-#include <osmium/index/multimap/hybrid.hpp>
-
-// ==============================================================================
-// Choose the following depending on the size of the input OSM files:
-// ==============================================================================
-// for smaller OSM files (extracts)
-typedef osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, size_t> offset_index_type;
-//typedef osmium::index::map::SparseMapMmap<osmium::unsigned_object_id_type, size_t> offset_index_type;
-//typedef osmium::index::map::SparseMapFile<osmium::unsigned_object_id_type, size_t> offset_index_type;
-
-typedef osmium::index::multimap::SparseMemArray<osmium::unsigned_object_id_type, osmium::unsigned_object_id_type> map_type;
-//typedef osmium::index::multimap::SparseMemMultimap<osmium::unsigned_object_id_type, osmium::unsigned_object_id_type> map_type;
-//typedef osmium::index::multimap::Hybrid<osmium::unsigned_object_id_type, osmium::unsigned_object_id_type> map_type;
-
-// ==============================================================================
-// for very large OSM files (planet)
-//typedef osmium::index::map::DenseMmapArray<osmium::unsigned_object_id_type, size_t> offset_index_type;
-// ==============================================================================
-
-void print_help() {
- std::cout << "osmium_serdump OSMFILE DIR\n" \
- << "Serialize content of OSMFILE into data file in DIR.\n" \
- << "\nOptions:\n" \
- << " -h, --help This help message\n";
-}
-
-int main(int argc, char* argv[]) {
- std::ios_base::sync_with_stdio(false);
-
- static struct option long_options[] = {
- {"help", no_argument, 0, 'h'},
- {0, 0, 0, 0}
- };
-
- while (true) {
- int c = getopt_long(argc, argv, "h", long_options, 0);
- if (c == -1) {
- break;
- }
-
- switch (c) {
- case 'h':
- print_help();
- std::exit(0);
- default:
- std::exit(2);
- }
- }
-
- int remaining_args = argc - optind;
-
- if (remaining_args != 2) {
- std::cerr << "Usage: " << argv[0] << " OSMFILE DIR\n";
- std::exit(2);
- }
-
- std::string dir(argv[optind+1]);
-#ifndef _WIN32
- int result = ::mkdir(dir.c_str(), 0777);
-#else
- int result = mkdir(dir.c_str());
-#endif
- if (result == -1 && errno != EEXIST) {
- std::cerr << "Problem creating directory '" << dir << "': " << strerror(errno) << "\n";
- std::exit(2);
- }
-
- std::string data_file(dir + "/data.osm.ser");
- int data_fd = ::open(data_file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
- if (data_fd < 0) {
- std::cerr << "Can't open data file '" << data_file << "': " << strerror(errno) << "\n";
- std::exit(2);
- }
-
- offset_index_type node_index;
- offset_index_type way_index;
- offset_index_type relation_index;
-
- osmium::handler::DiskStore disk_store_handler(data_fd, node_index, way_index, relation_index);
-
- map_type map_node2way;
- map_type map_node2relation;
- map_type map_way2relation;
- map_type map_relation2relation;
-
- osmium::handler::ObjectRelations object_relations_handler(map_node2way, map_node2relation, map_way2relation, map_relation2relation);
-
- osmium::io::Reader reader(argv[1]);
-
- while (osmium::memory::Buffer buffer = reader.read()) {
- disk_store_handler(buffer); // XXX
- osmium::apply(buffer, object_relations_handler);
- }
-
- reader.close();
-
- {
- std::string index_file(dir + "/nodes.idx");
- int fd = ::open(index_file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
- if (fd < 0) {
- std::cerr << "Can't open nodes index file '" << index_file << "': " << strerror(errno) << "\n";
- std::exit(2);
- }
- node_index.dump_as_list(fd);
- close(fd);
- }
-
- {
- std::string index_file(dir + "/ways.idx");
- int fd = ::open(index_file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
- if (fd < 0) {
- std::cerr << "Can't open ways index file '" << index_file << "': " << strerror(errno) << "\n";
- std::exit(2);
- }
- way_index.dump_as_list(fd);
- close(fd);
- }
-
- {
- std::string index_file(dir + "/relations.idx");
- int fd = ::open(index_file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
- if (fd < 0) {
- std::cerr << "Can't open relations index file '" << index_file << "': " << strerror(errno) << "\n";
- std::exit(2);
- }
- relation_index.dump_as_list(fd);
- close(fd);
- }
-
- {
- map_node2way.sort();
- std::string index_file(dir + "/node2way.map");
- int fd = ::open(index_file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
- if (fd < 0) {
- std::cerr << "Can't open node->way map file '" << index_file << "': " << strerror(errno) << "\n";
- std::exit(2);
- }
- map_node2way.dump_as_list(fd);
- close(fd);
- }
-
- {
- map_node2relation.sort();
- std::string index_file(dir + "/node2rel.map");
- int fd = ::open(index_file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
- if (fd < 0) {
- std::cerr << "Can't open node->rel map file '" << index_file << "': " << strerror(errno) << "\n";
- std::exit(2);
- }
- map_node2relation.dump_as_list(fd);
- close(fd);
- }
-
- {
- map_way2relation.sort();
- std::string index_file(dir + "/way2rel.map");
- int fd = ::open(index_file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
- if (fd < 0) {
- std::cerr << "Can't open way->rel map file '" << index_file << "': " << strerror(errno) << "\n";
- std::exit(2);
- }
- map_way2relation.dump_as_list(fd);
- close(fd);
- }
-
- {
- map_relation2relation.sort();
- std::string index_file(dir + "/rel2rel.map");
- int fd = ::open(index_file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
- if (fd < 0) {
- std::cerr << "Can't open rel->rel map file '" << index_file << "': " << strerror(errno) << "\n";
- std::exit(2);
- }
- map_relation2relation.dump_as_list(fd);
- close(fd);
- }
-}
-
diff --git a/include/osmium/area/assembler.hpp b/include/osmium/area/assembler.hpp
index d5bf8d8..092f4b4 100644
--- a/include/osmium/area/assembler.hpp
+++ b/include/osmium/area/assembler.hpp
@@ -193,12 +193,12 @@ namespace osmium {
}; // struct location_to_ring_map
- inline bool operator==(const location_to_ring_map& a, const location_to_ring_map& b) noexcept {
- return a.location == b.location;
+ inline bool operator==(const location_to_ring_map& lhs, const location_to_ring_map& rhs) noexcept {
+ return lhs.location == rhs.location;
}
- inline bool operator<(const location_to_ring_map& a, const location_to_ring_map& b) noexcept {
- return a.location < b.location;
+ inline bool operator<(const location_to_ring_map& lhs, const location_to_ring_map& rhs) noexcept {
+ return lhs.location < rhs.location;
}
} // namespace detail
@@ -288,7 +288,7 @@ namespace osmium {
}
void add_tags_to_area(osmium::builder::AreaBuilder& builder, const osmium::Way& way) const {
- builder.add_item(&way.tags());
+ builder.add_item(way.tags());
}
void add_common_tags(osmium::builder::TagListBuilder& tl_builder, std::set<const osmium::Way*>& ways) const {
@@ -333,7 +333,7 @@ namespace osmium {
}
static void copy_tags_without_type(osmium::builder::AreaBuilder& builder, const osmium::TagList& tags) {
- osmium::builder::TagListBuilder tl_builder(builder.buffer(), &builder);
+ 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());
@@ -354,7 +354,7 @@ namespace osmium {
}
if (m_config.keep_type_tag) {
- builder.add_item(&relation.tags());
+ builder.add_item(relation.tags());
} else {
copy_tags_without_type(builder, relation.tags());
}
@@ -373,12 +373,12 @@ namespace osmium {
if (debug()) {
std::cerr << " only one outer way\n";
}
- builder.add_item(&(*ways.cbegin())->tags());
+ builder.add_item((*ways.cbegin())->tags());
} else {
if (debug()) {
std::cerr << " multiple outer ways, get common tags\n";
}
- osmium::builder::TagListBuilder tl_builder(builder.buffer(), &builder);
+ osmium::builder::TagListBuilder tl_builder{builder};
add_common_tags(tl_builder, ways);
}
}
@@ -386,7 +386,7 @@ namespace osmium {
template <typename TBuilder>
static void build_ring_from_proto_ring(osmium::builder::AreaBuilder& builder, const detail::ProtoRing& ring) {
- TBuilder ring_builder(builder.buffer(), &builder);
+ TBuilder ring_builder{builder};
ring_builder.add_node_ref(ring.get_node_ref_start());
for (const auto& segment : ring.segments()) {
ring_builder.add_node_ref(segment->stop());
@@ -458,8 +458,8 @@ namespace osmium {
}
detail::NodeRefSegment* get_next_segment(const osmium::Location& location) {
- auto it = std::lower_bound(m_locations.begin(), m_locations.end(), slocation{}, [this, &location](const slocation& a, const slocation& b) {
- return a.location(m_segment_list, location) < b.location(m_segment_list, 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);
});
assert(it != m_locations.end());
@@ -744,8 +744,8 @@ namespace osmium {
m_locations.emplace_back(n, true);
}
- std::stable_sort(m_locations.begin(), m_locations.end(), [this](const slocation& a, const slocation& b) {
- return a.location(m_segment_list) < b.location(m_segment_list);
+ std::stable_sort(m_locations.begin(), m_locations.end(), [this](const slocation& lhs, const slocation& rhs) {
+ return lhs.location(m_segment_list) < rhs.location(m_segment_list);
});
}
@@ -1015,8 +1015,8 @@ namespace osmium {
std::vector<location_to_ring_map> xrings = create_location_to_ring_map(open_ring_its);
- const auto ring_min = std::min_element(xrings.begin(), xrings.end(), [](const location_to_ring_map& a, const location_to_ring_map& b) {
- return a.ring().min_segment() < b.ring().min_segment();
+ const auto ring_min = std::min_element(xrings.begin(), xrings.end(), [](const location_to_ring_map& lhs, const location_to_ring_map& rhs) {
+ return lhs.ring().min_segment() < rhs.ring().min_segment();
});
find_inner_outer_complex();
@@ -1068,11 +1068,11 @@ namespace osmium {
// Find the candidate with the smallest/largest area
const auto chosen_cand = ring_min_is_outer ?
- std::min_element(candidates.cbegin(), candidates.cend(), [](const candidate& a, const candidate& b) {
- return std::abs(a.sum) < std::abs(b.sum);
+ std::min_element(candidates.cbegin(), candidates.cend(), [](const candidate& lhs, const candidate& rhs) {
+ return std::abs(lhs.sum) < std::abs(rhs.sum);
}) :
- std::max_element(candidates.cbegin(), candidates.cend(), [](const candidate& a, const candidate& b) {
- return std::abs(a.sum) < std::abs(b.sum);
+ std::max_element(candidates.cbegin(), candidates.cend(), [](const candidate& lhs, const candidate& rhs) {
+ return std::abs(lhs.sum) < std::abs(rhs.sum);
});
if (debug()) {
@@ -1103,8 +1103,8 @@ namespace osmium {
const auto locs = make_range(std::equal_range(m_locations.begin(),
m_locations.end(),
slocation{},
- [this, &location](const slocation& a, const slocation& b) {
- return a.location(m_segment_list, location) < b.location(m_segment_list, location);
+ [this, &location](const slocation& lhs, const slocation& rhs) {
+ return lhs.location(m_segment_list, location) < rhs.location(m_segment_list, location);
}));
for (auto& loc : locs) {
if (!m_segment_list[loc.item].is_done()) {
@@ -1267,8 +1267,8 @@ namespace osmium {
}
for (const auto& location : m_split_locations) {
if (m_config.problem_reporter) {
- auto it = std::lower_bound(m_locations.cbegin(), m_locations.cend(), slocation{}, [this, &location](const slocation& a, const slocation& b) {
- return a.location(m_segment_list, location) < b.location(m_segment_list, location);
+ auto it = std::lower_bound(m_locations.cbegin(), m_locations.cend(), slocation{}, [this, &location](const slocation& lhs, const slocation& rhs) {
+ return lhs.location(m_segment_list, location) < rhs.location(m_segment_list, location);
});
assert(it != m_locations.cend());
const osmium::object_id_type id = it->node_ref(m_segment_list).ref();
@@ -1362,7 +1362,7 @@ namespace osmium {
#endif
bool create_area(osmium::memory::Buffer& out_buffer, const osmium::Way& way) {
- osmium::builder::AreaBuilder builder(out_buffer);
+ osmium::builder::AreaBuilder builder{out_buffer};
builder.initialize_from_object(way);
const bool area_okay = create_rings();
@@ -1382,7 +1382,7 @@ namespace osmium {
bool create_area(osmium::memory::Buffer& out_buffer, const osmium::Relation& relation, const std::vector<const osmium::Way*>& members) {
m_num_members = members.size();
- osmium::builder::AreaBuilder builder(out_buffer);
+ osmium::builder::AreaBuilder builder{out_buffer};
builder.initialize_from_object(relation);
const bool area_okay = create_rings();
diff --git a/include/osmium/area/detail/node_ref_segment.hpp b/include/osmium/area/detail/node_ref_segment.hpp
index b131a43..1c03d3e 100644
--- a/include/osmium/area/detail/node_ref_segment.hpp
+++ b/include/osmium/area/detail/node_ref_segment.hpp
@@ -379,8 +379,8 @@ namespace osmium {
sl[2] = {1, s2.first().location() };
sl[3] = {1, s2.second().location()};
- std::sort(sl, sl+4, [](const seg_loc& a, const seg_loc& b) {
- return a.location < b.location;
+ std::sort(sl, sl+4, [](const seg_loc& lhs, const seg_loc& rhs) {
+ return lhs.location < rhs.location;
});
if (sl[1].location == sl[2].location) {
diff --git a/include/osmium/area/detail/segment_list.hpp b/include/osmium/area/detail/segment_list.hpp
index a4361e0..97d512a 100644
--- a/include/osmium/area/detail/segment_list.hpp
+++ b/include/osmium/area/detail/segment_list.hpp
@@ -101,7 +101,7 @@ 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(), 0, [](size_t sum, const osmium::Way* way) {
+ return std::accumulate(members.cbegin(), members.cend(), static_cast<size_t>(0), [](size_t sum, const osmium::Way* way) {
if (way->nodes().empty()) {
return sum;
} else {
diff --git a/include/osmium/area/detail/vector.hpp b/include/osmium/area/detail/vector.hpp
index 44983cc..fae1280 100644
--- a/include/osmium/area/detail/vector.hpp
+++ b/include/osmium/area/detail/vector.hpp
@@ -73,18 +73,18 @@ namespace osmium {
}; // struct vec
// addition
- constexpr inline vec operator+(const vec& a, const vec& b) noexcept {
- return vec{a.x + b.x, a.y + b.y};
+ constexpr inline vec operator+(const vec& lhs, const vec& rhs) noexcept {
+ return vec{lhs.x + rhs.x, lhs.y + rhs.y};
}
// subtraction
- constexpr inline vec operator-(const vec& a, const vec& b) noexcept {
- return vec{a.x - b.x, a.y - b.y};
+ constexpr inline vec operator-(const vec& lhs, const vec& rhs) noexcept {
+ return vec{lhs.x - rhs.x, lhs.y - rhs.y};
}
// cross product
- constexpr inline int64_t operator*(const vec& a, const vec& b) noexcept {
- return a.x * b.y - a.y * b.x;
+ constexpr inline int64_t operator*(const vec& lhs, const vec& rhs) noexcept {
+ return lhs.x * rhs.y - lhs.y * rhs.x;
}
// scale vector
@@ -98,13 +98,13 @@ namespace osmium {
}
// equality
- constexpr inline bool operator==(const vec& a, const vec& b) noexcept {
- return a.x == b.x && a.y == b.y;
+ constexpr inline bool operator==(const vec& lhs, const vec& rhs) noexcept {
+ return lhs.x == rhs.x && lhs.y == rhs.y;
}
// inequality
- constexpr inline bool operator!=(const vec& a, const vec& b) noexcept {
- return !(a == b);
+ constexpr inline bool operator!=(const vec& lhs, const vec& rhs) noexcept {
+ return !(lhs == rhs);
}
template <typename TChar, typename TTraits>
diff --git a/include/osmium/builder/attr.hpp b/include/osmium/builder/attr.hpp
index 2a5b690..8e0b4a3 100644
--- a/include/osmium/builder/attr.hpp
+++ b/include/osmium/builder/attr.hpp
@@ -617,7 +617,7 @@ namespace osmium {
template <typename TBuilder, typename... TArgs>
inline void add_user(TBuilder& builder, const TArgs&... args) {
- builder.add_user(get_user(args...));
+ builder.set_user(get_user(args...));
}
// ==============================================================
@@ -761,11 +761,13 @@ namespace osmium {
static_assert(sizeof...(args) > 0, "add_node() must have buffer and at least one additional argument");
static_assert(detail::are_all_handled_by<detail::any_node_handlers, TArgs...>::value, "Attribute not allowed in add_node()");
- NodeBuilder builder(buffer);
+ {
+ NodeBuilder builder(buffer);
- detail::add_basic<detail::node_handler>(builder, args...);
- detail::add_user(builder, args...);
- detail::add_list<TagListBuilder, detail::tags_handler>(builder, args...);
+ detail::add_basic<detail::node_handler>(builder, args...);
+ detail::add_user(builder, args...);
+ detail::add_list<TagListBuilder, detail::tags_handler>(builder, args...);
+ }
return buffer.commit();
}
@@ -782,12 +784,14 @@ namespace osmium {
static_assert(sizeof...(args) > 0, "add_way() must have buffer and at least one additional argument");
static_assert(detail::are_all_handled_by<detail::any_way_handlers, TArgs...>::value, "Attribute not allowed in add_way()");
- WayBuilder builder(buffer);
+ {
+ WayBuilder builder(buffer);
- detail::add_basic<detail::object_handler>(builder, args...);
- detail::add_user(builder, args...);
- detail::add_list<TagListBuilder, detail::tags_handler>(builder, args...);
- detail::add_list<WayNodeListBuilder, detail::nodes_handler>(builder, args...);
+ detail::add_basic<detail::object_handler>(builder, args...);
+ detail::add_user(builder, args...);
+ detail::add_list<TagListBuilder, detail::tags_handler>(builder, args...);
+ detail::add_list<WayNodeListBuilder, detail::nodes_handler>(builder, args...);
+ }
return buffer.commit();
}
@@ -804,12 +808,14 @@ namespace osmium {
static_assert(sizeof...(args) > 0, "add_relation() must have buffer and at least one additional argument");
static_assert(detail::are_all_handled_by<detail::any_relation_handlers, TArgs...>::value, "Attribute not allowed in add_relation()");
- RelationBuilder builder(buffer);
+ {
+ RelationBuilder builder(buffer);
- detail::add_basic<detail::object_handler>(builder, args...);
- detail::add_user(builder, args...);
- detail::add_list<TagListBuilder, detail::tags_handler>(builder, args...);
- detail::add_list<RelationMemberListBuilder, detail::members_handler>(builder, args...);
+ detail::add_basic<detail::object_handler>(builder, args...);
+ detail::add_user(builder, args...);
+ detail::add_list<TagListBuilder, detail::tags_handler>(builder, args...);
+ detail::add_list<RelationMemberListBuilder, detail::members_handler>(builder, args...);
+ }
return buffer.commit();
}
@@ -826,12 +832,14 @@ namespace osmium {
static_assert(sizeof...(args) > 0, "add_changeset() must have buffer and at least one additional argument");
static_assert(detail::are_all_handled_by<detail::any_changeset_handlers, TArgs...>::value, "Attribute not allowed in add_changeset()");
- ChangesetBuilder builder(buffer);
+ {
+ ChangesetBuilder builder(buffer);
- detail::add_basic<detail::changeset_handler>(builder, args...);
- detail::add_user(builder, args...);
- detail::add_list<TagListBuilder, detail::tags_handler>(builder, args...);
- detail::add_list<ChangesetDiscussionBuilder, detail::discussion_handler>(builder, args...);
+ detail::add_basic<detail::changeset_handler>(builder, args...);
+ detail::add_user(builder, args...);
+ detail::add_list<TagListBuilder, detail::tags_handler>(builder, args...);
+ detail::add_list<ChangesetDiscussionBuilder, detail::discussion_handler>(builder, args...);
+ }
return buffer.commit();
}
@@ -848,15 +856,17 @@ namespace osmium {
static_assert(sizeof...(args) > 0, "add_area() must have buffer and at least one additional argument");
static_assert(detail::are_all_handled_by<detail::any_area_handlers, TArgs...>::value, "Attribute not allowed in add_area()");
- AreaBuilder builder(buffer);
+ {
+ AreaBuilder builder(buffer);
- detail::add_basic<detail::object_handler>(builder, args...);
- detail::add_user(builder, args...);
- detail::add_list<TagListBuilder, detail::tags_handler>(builder, args...);
+ detail::add_basic<detail::object_handler>(builder, args...);
+ detail::add_user(builder, args...);
+ detail::add_list<TagListBuilder, detail::tags_handler>(builder, args...);
- (void)std::initializer_list<int>{
- (detail::ring_handler::set_value(builder, args), 0)...
- };
+ (void)std::initializer_list<int>{
+ (detail::ring_handler::set_value(builder, args), 0)...
+ };
+ }
return buffer.commit();
}
diff --git a/include/osmium/builder/builder.hpp b/include/osmium/builder/builder.hpp
index 1b274ad..044da1e 100644
--- a/include/osmium/builder/builder.hpp
+++ b/include/osmium/builder/builder.hpp
@@ -45,6 +45,7 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/memory/item.hpp>
#include <osmium/osm/types.hpp>
#include <osmium/util/cast.hpp>
+#include <osmium/util/compatibility.hpp>
namespace osmium {
@@ -53,6 +54,10 @@ namespace osmium {
*/
namespace builder {
+ /**
+ * Parent class for individual builder classes. Instantiate one of
+ * its derived classes.
+ */
class Builder {
osmium::memory::Buffer& m_buffer;
@@ -71,20 +76,34 @@ namespace osmium {
m_buffer(buffer),
m_parent(parent),
m_item_offset(buffer.written()) {
- m_buffer.reserve_space(size);
+ reserve_space(size);
assert(buffer.is_aligned());
if (m_parent) {
+ assert(m_buffer.builder_count() == 1 && "Only one sub-builder can be open at any time.");
m_parent->add_size(size);
+ } else {
+ assert(m_buffer.builder_count() == 0 && "Only one builder can be open at any time.");
}
+#ifndef NDEBUG
+ m_buffer.increment_builder_count();
+#endif
}
+#ifdef NDEBUG
~Builder() = default;
+#else
+ ~Builder() noexcept {
+ m_buffer.decrement_builder_count();
+ }
+#endif
osmium::memory::Item& item() const {
return *reinterpret_cast<osmium::memory::Item*>(m_buffer.data() + m_item_offset);
}
- public:
+ unsigned char* reserve_space(size_t size) {
+ return m_buffer.reserve_space(size);
+ }
/**
* Add padding to buffer (if needed) to align data properly.
@@ -102,7 +121,7 @@ namespace osmium {
void add_padding(bool self = false) {
const auto padding = osmium::memory::align_bytes - (size() % osmium::memory::align_bytes);
if (padding != osmium::memory::align_bytes) {
- std::fill_n(m_buffer.reserve_space(padding), padding, 0);
+ std::fill_n(reserve_space(padding), padding, 0);
if (self) {
add_size(padding);
} else if (m_parent) {
@@ -123,12 +142,6 @@ namespace osmium {
return item().byte_size();
}
- void add_item(const osmium::memory::Item* item) {
- unsigned char* target = m_buffer.reserve_space(item->padded_size());
- std::copy_n(reinterpret_cast<const unsigned char*>(item), item->padded_size(), target);
- add_size(item->padded_size());
- }
-
/**
* Reserve space for an object of class T in buffer and return
* pointer to it.
@@ -136,7 +149,7 @@ namespace osmium {
template <typename T>
T* reserve_space_for() {
assert(m_buffer.is_aligned());
- return reinterpret_cast<T*>(m_buffer.reserve_space(sizeof(T)));
+ return reinterpret_cast<T*>(reserve_space(sizeof(T)));
}
/**
@@ -149,7 +162,7 @@ namespace osmium {
* @returns The number of bytes appended (length).
*/
osmium::memory::item_size_type append(const char* data, const osmium::memory::item_size_type length) {
- unsigned char* target = m_buffer.reserve_space(length);
+ unsigned char* target = reserve_space(length);
std::copy_n(reinterpret_cast<const unsigned char*>(data), length, target);
return length;
}
@@ -170,64 +183,36 @@ namespace osmium {
* @returns The number of bytes appended (always 1).
*/
osmium::memory::item_size_type append_zero() {
- *m_buffer.reserve_space(1) = '\0';
+ *reserve_space(1) = '\0';
return 1;
}
+ public:
+
/// Return the buffer this builder is using.
osmium::memory::Buffer& buffer() noexcept {
return m_buffer;
}
- }; // class Builder
-
- template <typename TItem>
- class ObjectBuilder : public Builder {
-
- static_assert(std::is_base_of<osmium::memory::Item, TItem>::value, "ObjectBuilder can only build objects derived from osmium::memory::Item");
-
- public:
-
- explicit ObjectBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
- Builder(buffer, parent, sizeof(TItem)) {
- new (&item()) TItem();
- }
-
- TItem& object() noexcept {
- return static_cast<TItem&>(item());
- }
-
- /**
- * Add user name to buffer.
- *
- * @param user Pointer to user name.
- * @param length Length of user name (without \0 termination).
- */
- void add_user(const char* user, const string_size_type length) {
- object().set_user_size(length + 1);
- add_size(append(user, length) + append_zero());
- add_padding(true);
- }
-
/**
- * Add user name to buffer.
- *
- * @param user Pointer to \0-terminated user name.
+ * Add a subitem to the object being built. This can be something
+ * like a TagList or RelationMemberList.
*/
- void add_user(const char* user) {
- add_user(user, static_cast_with_assert<string_size_type>(std::strlen(user)));
+ void add_item(const osmium::memory::Item& item) {
+ m_buffer.add_item(item);
+ add_size(item.padded_size());
}
/**
- * Add user name to buffer.
- *
- * @param user User name.
+ * @deprecated Use the version of add_item() taking a
+ * reference instead.
*/
- void add_user(const std::string& user) {
- add_user(user.data(), static_cast_with_assert<string_size_type>(user.size()));
+ OSMIUM_DEPRECATED void add_item(const osmium::memory::Item* item) {
+ assert(item);
+ add_item(*item);
}
- }; // class ObjectBuilder
+ }; // class Builder
} // namespace builder
diff --git a/include/osmium/builder/osm_object_builder.hpp b/include/osmium/builder/osm_object_builder.hpp
index e7a8298..b1c7220 100644
--- a/include/osmium/builder/osm_object_builder.hpp
+++ b/include/osmium/builder/osm_object_builder.hpp
@@ -45,6 +45,7 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/builder/builder.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>
@@ -55,6 +56,7 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/osm/relation.hpp>
#include <osmium/osm/timestamp.hpp>
#include <osmium/osm/way.hpp>
+#include <osmium/util/compatibility.hpp>
namespace osmium {
@@ -66,12 +68,18 @@ namespace osmium {
namespace builder {
- class TagListBuilder : public ObjectBuilder<TagList> {
+ class TagListBuilder : public Builder {
public:
explicit TagListBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
- ObjectBuilder<TagList>(buffer, parent) {
+ Builder(buffer, parent, sizeof(TagList)) {
+ new (&item()) TagList();
+ }
+
+ explicit TagListBuilder(Builder& parent) :
+ Builder(parent.buffer(), &parent, sizeof(TagList)) {
+ new (&item()) TagList();
}
~TagListBuilder() {
@@ -169,21 +177,27 @@ namespace osmium {
}; // class TagListBuilder
template <typename T>
- class NodeRefListBuilder : public ObjectBuilder<T> {
+ class NodeRefListBuilder : public Builder {
public:
explicit NodeRefListBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
- ObjectBuilder<T>(buffer, parent) {
+ Builder(buffer, parent, sizeof(T)) {
+ new (&item()) T();
+ }
+
+ explicit NodeRefListBuilder(Builder& parent) :
+ Builder(parent.buffer(), &parent, sizeof(T)) {
+ new (&item()) T();
}
~NodeRefListBuilder() {
- static_cast<Builder*>(this)->add_padding();
+ add_padding();
}
void add_node_ref(const NodeRef& node_ref) {
- new (static_cast<Builder*>(this)->reserve_space_for<osmium::NodeRef>()) osmium::NodeRef(node_ref);
- static_cast<Builder*>(this)->add_size(sizeof(osmium::NodeRef));
+ 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{}) {
@@ -196,7 +210,7 @@ namespace osmium {
using OuterRingBuilder = NodeRefListBuilder<OuterRing>;
using InnerRingBuilder = NodeRefListBuilder<InnerRing>;
- class RelationMemberListBuilder : public ObjectBuilder<RelationMemberList> {
+ class RelationMemberListBuilder : public Builder {
/**
* Add role to buffer.
@@ -219,7 +233,13 @@ namespace osmium {
public:
explicit RelationMemberListBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
- ObjectBuilder<RelationMemberList>(buffer, parent) {
+ Builder(buffer, parent, sizeof(RelationMemberList)) {
+ new (&item()) RelationMemberList();
+ }
+
+ explicit RelationMemberListBuilder(Builder& parent) :
+ Builder(parent.buffer(), &parent, sizeof(RelationMemberList)) {
+ new (&item()) RelationMemberList();
}
~RelationMemberListBuilder() {
@@ -245,7 +265,7 @@ namespace osmium {
add_size(sizeof(RelationMember));
add_role(*member, role, role_length);
if (full_member) {
- add_item(full_member);
+ add_item(*full_member);
}
}
@@ -281,7 +301,7 @@ namespace osmium {
}; // class RelationMemberListBuilder
- class ChangesetDiscussionBuilder : public ObjectBuilder<ChangesetDiscussion> {
+ class ChangesetDiscussionBuilder : public Builder {
osmium::ChangesetComment* m_comment = nullptr;
@@ -309,7 +329,13 @@ namespace osmium {
public:
explicit ChangesetDiscussionBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
- ObjectBuilder<ChangesetDiscussion>(buffer, parent) {
+ Builder(buffer, parent, sizeof(ChangesetDiscussion)) {
+ new (&item()) ChangesetDiscussion();
+ }
+
+ explicit ChangesetDiscussionBuilder(Builder& parent) :
+ Builder(parent.buffer(), &parent, sizeof(ChangesetDiscussion)) {
+ new (&item()) ChangesetDiscussion();
}
~ChangesetDiscussionBuilder() {
@@ -339,19 +365,101 @@ namespace osmium {
}; // class ChangesetDiscussionBuilder
- template <typename T>
- class OSMObjectBuilder : public ObjectBuilder<T> {
+#define OSMIUM_FORWARD(setter) \
+ template <typename... TArgs> \
+ type& setter(TArgs&&... args) { \
+ object().setter(std::forward<TArgs>(args)...); \
+ return static_cast<type&>(*this); \
+ }
+
+ template <typename TDerived, typename T>
+ class OSMObjectBuilder : public Builder {
+
+ using type = TDerived;
+
+ constexpr static const 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) :
- ObjectBuilder<T>(buffer, parent) {
- static_cast<Builder*>(this)->reserve_space_for<string_size_type>();
- static_cast<Builder*>(this)->add_size(sizeof(string_size_type));
+ Builder(buffer, parent, sizeof(T) + min_size_for_user) {
+ 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);
+ }
+
+ /**
+ * Get a 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.
+ */
+ T& object() noexcept {
+ return static_cast<T&>(item());
+ }
+
+ /**
+ * Set user name.
+ *
+ * @param user Pointer to user name.
+ * @param length Length of user name (without \0 termination).
+ */
+ 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))
+ && "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) {
+ const auto space_needed = osmium::memory::padded_length(length - available_space);
+ reserve_space(space_needed);
+ add_size(static_cast<uint32_t>(space_needed));
+ }
+ std::copy_n(user, length, object().data() + size_of_object);
+ std::fill_n(object().data() + size_of_object + length, osmium::memory::padded_length(length + 1) - length, 0);
+ object().set_user_size(length + 1);
+
+ return static_cast<TDerived&>(*this);
}
+ /**
+ * Set user name.
+ *
+ * @param user Pointer to \0-terminated user name.
+ */
+ TDerived& set_user(const char* user) {
+ return set_user(user, static_cast_with_assert<string_size_type>(std::strlen(user)));
+ }
+
+ /**
+ * Set user name.
+ *
+ * @param user User name.
+ */
+ TDerived& set_user(const std::string& user) {
+ return set_user(user.data(), static_cast_with_assert<string_size_type>(user.size()));
+ }
+
+ /// @deprecated Use set_user(...) instead.
+ template <typename... TArgs>
+ OSMIUM_DEPRECATED void add_user(TArgs&&... args) {
+ set_user(std::forward<TArgs>(args)...);
+ }
+
+ OSMIUM_FORWARD(set_id)
+ OSMIUM_FORWARD(set_visible)
+ OSMIUM_FORWARD(set_deleted)
+ OSMIUM_FORWARD(set_version)
+ OSMIUM_FORWARD(set_changeset)
+ OSMIUM_FORWARD(set_uid)
+ OSMIUM_FORWARD(set_uid_from_signed)
+ OSMIUM_FORWARD(set_timestamp)
+ OSMIUM_FORWARD(set_attribute)
+ OSMIUM_FORWARD(set_removed)
+
void add_tags(const std::initializer_list<std::pair<const char*, const char*>>& tags) {
- osmium::builder::TagListBuilder tl_builder(static_cast<Builder*>(this)->buffer(), this);
+ osmium::builder::TagListBuilder tl_builder{buffer(), this};
for (const auto& p : tags) {
tl_builder.add_tag(p.first, p.second);
}
@@ -359,19 +467,40 @@ namespace osmium {
}; // class OSMObjectBuilder
- using NodeBuilder = OSMObjectBuilder<osmium::Node>;
- using RelationBuilder = OSMObjectBuilder<osmium::Relation>;
+ class NodeBuilder : public OSMObjectBuilder<NodeBuilder, Node> {
- class WayBuilder : public OSMObjectBuilder<osmium::Way> {
+ using type = NodeBuilder;
+
+ public:
+
+ explicit NodeBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
+ OSMObjectBuilder<NodeBuilder, Node>(buffer, parent) {
+ }
+
+ explicit NodeBuilder(Builder& parent) :
+ OSMObjectBuilder<NodeBuilder, Node>(parent.buffer(), &parent) {
+ }
+
+ OSMIUM_FORWARD(set_location)
+
+ }; // class NodeBuilder
+
+ class WayBuilder : public OSMObjectBuilder<WayBuilder, Way> {
+
+ using type = WayBuilder;
public:
explicit WayBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
- OSMObjectBuilder<osmium::Way>(buffer, parent) {
+ OSMObjectBuilder<WayBuilder, Way>(buffer, parent) {
+ }
+
+ explicit WayBuilder(Builder& parent) :
+ OSMObjectBuilder<WayBuilder, Way>(parent.buffer(), &parent) {
}
void add_node_refs(const std::initializer_list<osmium::NodeRef>& nodes) {
- osmium::builder::WayNodeListBuilder builder(buffer(), this);
+ osmium::builder::WayNodeListBuilder builder{buffer(), this};
for (const auto& node_ref : nodes) {
builder.add_node_ref(node_ref);
}
@@ -379,32 +508,147 @@ namespace osmium {
}; // class WayBuilder
- class AreaBuilder : public OSMObjectBuilder<osmium::Area> {
+ class RelationBuilder : public OSMObjectBuilder<RelationBuilder, Relation> {
+
+ using type = RelationBuilder;
+
+ public:
+
+ explicit RelationBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
+ OSMObjectBuilder<RelationBuilder, Relation>(buffer, parent) {
+ }
+
+ explicit RelationBuilder(Builder& parent) :
+ OSMObjectBuilder<RelationBuilder, Relation>(parent.buffer(), &parent) {
+ }
+
+ }; // class RelationBuilder
+
+ class AreaBuilder : public OSMObjectBuilder<AreaBuilder, Area> {
+
+ using type = AreaBuilder;
public:
explicit AreaBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
- OSMObjectBuilder<osmium::Area>(buffer, parent) {
+ OSMObjectBuilder<AreaBuilder, Area>(buffer, parent) {
+ }
+
+ explicit AreaBuilder(Builder& parent) :
+ OSMObjectBuilder<AreaBuilder, Area>(parent.buffer(), &parent) {
}
/**
* Initialize area attributes from the attributes of the given object.
*/
void initialize_from_object(const osmium::OSMObject& source) {
- osmium::Area& area = object();
- area.set_id(osmium::object_id_to_area_id(source.id(), source.type()));
- area.set_version(source.version());
- area.set_changeset(source.changeset());
- area.set_timestamp(source.timestamp());
- area.set_visible(source.visible());
- area.set_uid(source.uid());
-
- add_user(source.user());
+ set_id(osmium::object_id_to_area_id(source.id(), source.type()));
+ set_version(source.version());
+ set_changeset(source.changeset());
+ set_timestamp(source.timestamp());
+ set_visible(source.visible());
+ set_uid(source.uid());
+ set_user(source.user());
}
}; // class AreaBuilder
- using ChangesetBuilder = ObjectBuilder<osmium::Changeset>;
+ class ChangesetBuilder : public Builder {
+
+ using type = ChangesetBuilder;
+
+ constexpr static const 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();
+ add_size(min_size_for_user);
+ std::fill_n(object().data() + sizeof(Changeset), min_size_for_user, 0);
+ object().set_user_size(1);
+ }
+
+ /**
+ * Get a 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.
+ */
+ Changeset& object() noexcept {
+ return static_cast<Changeset&>(item());
+ }
+
+ OSMIUM_FORWARD(set_id)
+ OSMIUM_FORWARD(set_uid)
+ OSMIUM_FORWARD(set_uid_from_signed)
+ OSMIUM_FORWARD(set_created_at)
+ OSMIUM_FORWARD(set_closed_at)
+ OSMIUM_FORWARD(set_num_changes)
+ OSMIUM_FORWARD(set_num_comments)
+ OSMIUM_FORWARD(set_attribute)
+ OSMIUM_FORWARD(set_removed)
+
+ // @deprecated Use set_bounds() instead.
+ OSMIUM_DEPRECATED osmium::Box& bounds() noexcept {
+ return object().bounds();
+ }
+
+ ChangesetBuilder& set_bounds(const osmium::Box& box) noexcept {
+ object().bounds() = box;
+ return *this;
+ }
+
+ /**
+ * Set user name.
+ *
+ * @param user Pointer to user name.
+ * @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))
+ && "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) {
+ const auto space_needed = osmium::memory::padded_length(length - available_space);
+ reserve_space(space_needed);
+ add_size(static_cast<uint32_t>(space_needed));
+ }
+ std::copy_n(user, length, object().data() + sizeof(Changeset));
+ std::fill_n(object().data() + sizeof(Changeset) + length, osmium::memory::padded_length(length + 1) - length, 0);
+ object().set_user_size(length + 1);
+
+ return *this;
+ }
+
+ /**
+ * Set user name.
+ *
+ * @param user Pointer to \0-terminated user name.
+ */
+ ChangesetBuilder& set_user(const char* user) {
+ return set_user(user, static_cast_with_assert<string_size_type>(std::strlen(user)));
+ }
+
+ /**
+ * Set user name.
+ *
+ * @param user User name.
+ */
+ ChangesetBuilder& set_user(const std::string& user) {
+ return set_user(user.data(), static_cast_with_assert<string_size_type>(user.size()));
+ }
+
+ /// @deprecated Use set_user(...) instead.
+ template <typename... TArgs>
+ OSMIUM_DEPRECATED void add_user(TArgs&&... args) {
+ set_user(std::forward<TArgs>(args)...);
+ }
+
+ }; // class ChangesetBuilder
+
+#undef OSMIUM_FORWARD
} // namespace builder
diff --git a/include/osmium/geom/factory.hpp b/include/osmium/geom/factory.hpp
index 14c51df..f2db402 100644
--- a/include/osmium/geom/factory.hpp
+++ b/include/osmium/geom/factory.hpp
@@ -95,7 +95,7 @@ namespace osmium {
return m_message.c_str();
}
- }; // struct geometry_error
+ }; // class geometry_error
/**
* @brief Everything related to geometry handling.
diff --git a/include/osmium/geom/geos.hpp b/include/osmium/geom/geos.hpp
index f406076..d59e7ce 100644
--- a/include/osmium/geom/geos.hpp
+++ b/include/osmium/geom/geos.hpp
@@ -33,12 +33,22 @@ DEALINGS IN THE SOFTWARE.
*/
+#include <geos/version.h>
+#if defined(GEOS_VERSION_MAJOR) && defined(GEOS_VERSION_MINOR) && (GEOS_VERSION_MAJOR < 3 || (GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR <= 5))
+
+#define OSMIUM_WITH_GEOS
+
/**
* @file
*
- * This file contains code for conversion of OSM geometries into GDAL
+ * This file contains code for conversion of OSM geometries into GEOS
* geometries.
*
+ * Note that everything in this file is deprecated and only works up to
+ * GEOS 3.5. It uses the GEOS C++ API which the GEOS project does not consider
+ * to be a stable, external API. We probably should have used the GEOS C API
+ * instead.
+ *
* @attention If you include this file, you'll need to link with `libgeos`.
*/
@@ -88,6 +98,7 @@ namespace osmium {
namespace detail {
+ /// @deprecated
class GEOSFactoryImpl {
std::unique_ptr<const geos::geom::PrecisionModel> m_precision_model;
@@ -245,6 +256,7 @@ namespace osmium {
} // namespace detail
+ /// @deprecated
template <typename TProjection = IdentityProjection>
using GEOSFactory = GeometryFactory<osmium::geom::detail::GEOSFactoryImpl, TProjection>;
@@ -254,4 +266,6 @@ namespace osmium {
#undef THROW
+#endif
+
#endif // OSMIUM_GEOM_GEOS_HPP
diff --git a/include/osmium/geom/relations.hpp b/include/osmium/geom/relations.hpp
index 76d452e..5e6e773 100644
--- a/include/osmium/geom/relations.hpp
+++ b/include/osmium/geom/relations.hpp
@@ -43,11 +43,11 @@ namespace osmium {
/**
* Check whether one geometry contains another.
*/
- inline bool contains(const osmium::Box& a, const osmium::Box& b) {
- return ((a.bottom_left().x() >= b.bottom_left().x()) &&
- (a.top_right().x() <= b.top_right().x()) &&
- (a.bottom_left().y() >= b.bottom_left().y()) &&
- (a.top_right().y() <= b.top_right().y()));
+ inline bool contains(const osmium::Box& lhs, const osmium::Box& rhs) {
+ 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()));
}
} // namespace geom
diff --git a/include/osmium/geom/tile.hpp b/include/osmium/geom/tile.hpp
index 672ae54..2c33017 100644
--- a/include/osmium/geom/tile.hpp
+++ b/include/osmium/geom/tile.hpp
@@ -118,23 +118,23 @@ namespace osmium {
}; // struct Tile
/// Tiles are equal if all their attributes are equal.
- inline bool operator==(const Tile& a, const Tile& b) {
- return a.z == b.z && a.x == b.x && a.y == b.y;
+ inline bool operator==(const Tile& lhs, const Tile& rhs) {
+ return lhs.z == rhs.z && lhs.x == rhs.x && lhs.y == rhs.y;
}
- inline bool operator!=(const Tile& a, const Tile& b) {
- return ! (a == b);
+ inline bool operator!=(const Tile& lhs, const Tile& rhs) {
+ return ! (lhs == rhs);
}
/**
* This defines an arbitrary order on tiles for use in std::map etc.
*/
- inline bool operator<(const Tile& a, const Tile& b) {
- if (a.z < b.z) return true;
- if (a.z > b.z) return false;
- if (a.x < b.x) return true;
- if (a.x > b.x) return false;
- return a.y < b.y;
+ 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;
+ return lhs.y < rhs.y;
}
} // namespace geom
diff --git a/include/osmium/handler/disk_store.hpp b/include/osmium/handler/disk_store.hpp
index 4e95573..d112ac0 100644
--- a/include/osmium/handler/disk_store.hpp
+++ b/include/osmium/handler/disk_store.hpp
@@ -51,6 +51,9 @@ namespace osmium {
namespace handler {
/**
+ * Writes OSM data in the Osmium-internal serialized format to disk
+ * keeping track of object offsets in the indexes given to the
+ * constructor.
*
* Note: This handler will only work if either all object IDs are
* positive or all object IDs are negative.
@@ -95,10 +98,8 @@ namespace osmium {
m_offset += relation.byte_size();
}
- // XXX
void operator()(const osmium::memory::Buffer& buffer) {
osmium::io::detail::reliable_write(m_data_fd, buffer.data(), buffer.committed());
-
osmium::apply(buffer.begin(), buffer.end(), *this);
}
diff --git a/include/osmium/handler/node_locations_for_ways.hpp b/include/osmium/handler/node_locations_for_ways.hpp
index a490f9e..61c6de2 100644
--- a/include/osmium/handler/node_locations_for_ways.hpp
+++ b/include/osmium/handler/node_locations_for_ways.hpp
@@ -165,7 +165,7 @@ namespace osmium {
}
}
if (error && !m_ignore_errors) {
- throw osmium::not_found("location for one or more nodes not found in node location index");
+ throw osmium::not_found{"location for one or more nodes not found in node location index"};
}
}
diff --git a/include/osmium/handler/object_relations.hpp b/include/osmium/handler/object_relations.hpp
index 279365d..5f1956d 100644
--- a/include/osmium/handler/object_relations.hpp
+++ b/include/osmium/handler/object_relations.hpp
@@ -46,6 +46,8 @@ namespace osmium {
namespace handler {
/**
+ * This handler updates the indexes given to the constructor with
+ * the relations between objects.
*
* Note: This handler will only work if either all object IDs are
* positive or all object IDs are negative.
diff --git a/include/osmium/index/bool_vector.hpp b/include/osmium/index/bool_vector.hpp
index e6e190e..2ef80f9 100644
--- a/include/osmium/index/bool_vector.hpp
+++ b/include/osmium/index/bool_vector.hpp
@@ -33,50 +33,15 @@ DEALINGS IN THE SOFTWARE.
*/
-#include <type_traits>
-#include <vector>
+#include <osmium/index/id_set.hpp>
namespace osmium {
namespace index {
- /**
- * Index storing one bit for each Id. The index automatically scales
- * with the Ids stored. Default value is 'false'. Storage uses
- * std::vector<bool> and needs a minimum of memory if the Ids are
- * dense.
- */
+ /// @deprecated Use osmium::index::IdSet instead.
template <typename T>
- class BoolVector {
-
- static_assert(std::is_unsigned<T>::value, "Needs unsigned type");
-
- std::vector<bool> m_bits;
-
- public:
-
- BoolVector() = default;
-
- BoolVector(const BoolVector&) = default;
- BoolVector(BoolVector&&) = default;
- BoolVector& operator=(const BoolVector&) = default;
- BoolVector& operator=(BoolVector&&) = default;
-
- ~BoolVector() noexcept = default;
-
- void set(T id, bool value = true) {
- if (m_bits.size() <= id) {
- m_bits.resize(id + 1024 * 1024);
- }
-
- m_bits[id] = value;
- }
-
- bool get(T id) const {
- return id < m_bits.size() && m_bits[id];
- }
-
- }; // class BoolVector
+ using BoolVector = IdSet<T>;
} // namespace index
diff --git a/include/osmium/index/detail/vector_map.hpp b/include/osmium/index/detail/vector_map.hpp
index ac87c2f..9f4af1f 100644
--- a/include/osmium/index/detail/vector_map.hpp
+++ b/include/osmium/index/detail/vector_map.hpp
@@ -85,11 +85,11 @@ namespace osmium {
try {
const TValue& value = m_vector.at(id);
if (value == osmium::index::empty_value<TValue>()) {
- not_found_error(id);
+ throw osmium::not_found{id};
}
return value;
} catch (const std::out_of_range&) {
- not_found_error(id);
+ throw osmium::not_found{id};
}
}
@@ -180,7 +180,7 @@ namespace osmium {
return a.first < b.first;
});
if (result == m_vector.end() || result->first != id) {
- not_found_error(id);
+ throw osmium::not_found{id};
} else {
return result->second;
}
diff --git a/include/osmium/index/id_set.hpp b/include/osmium/index/id_set.hpp
new file mode 100644
index 0000000..4a894a0
--- /dev/null
+++ b/include/osmium/index/id_set.hpp
@@ -0,0 +1,431 @@
+#ifndef OSMIUM_INDEX_ID_SET_HPP
+#define OSMIUM_INDEX_ID_SET_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2016 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 <cstring>
+#include <memory>
+#include <type_traits>
+#include <unordered_set>
+#include <vector>
+
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/types.hpp>
+
+namespace osmium {
+
+ namespace index {
+
+ /**
+ * Virtual parent class for IdSets. Use one of the implementations
+ * provided.
+ */
+ template <typename T>
+ class IdSet {
+
+ public:
+
+ virtual ~IdSet() {
+ }
+
+ /**
+ * Add the given Id to the set.
+ */
+ virtual void set(T id) = 0;
+
+ /**
+ * Is the Id in the set?
+ */
+ virtual bool get(T id) const noexcept = 0;
+
+ /**
+ * Is the set empty?
+ */
+ virtual bool empty() const = 0;
+
+ /**
+ * Clear the set.
+ */
+ virtual void clear() = 0;
+
+ }; // class IdSet
+
+ template <typename T>
+ class IdSetDense;
+
+ /**
+ * Const_iterator for iterating over a IdSetDense.
+ */
+ template <typename T>
+ class IdSetDenseIterator {
+
+ const IdSetDense<T>* m_set;
+ T m_value;
+ T m_last;
+
+ void next() noexcept {
+ while (m_value != m_last && !m_set->get(m_value)) {
+ const auto cid = IdSetDense<T>::chunk_id(m_value);
+ assert(cid < m_set->m_data.size());
+ if (!m_set->m_data[cid]) {
+ m_value = (cid + 1) << (IdSetDense<T>::chunk_bits + 3);
+ } else {
+ const auto slot = m_set->m_data[cid][IdSetDense<T>::offset(m_value)];
+ if (slot == 0) {
+ m_value += 8;
+ m_value &= ~0x7;
+ } else {
+ ++m_value;
+ }
+ }
+ }
+ }
+
+ public:
+
+ using iterator_category = std::forward_iterator_tag;
+ using value_type = T;
+ using pointer = value_type*;
+ using reference = value_type&;
+
+ IdSetDenseIterator(const IdSetDense<T>* set, T value, T last) noexcept :
+ m_set(set),
+ m_value(value),
+ m_last(last) {
+ next();
+ }
+
+ IdSetDenseIterator<T>& operator++() noexcept {
+ if (m_value != m_last) {
+ ++m_value;
+ next();
+ }
+ return *this;
+ }
+
+ IdSetDenseIterator<T> operator++(int) noexcept {
+ IdSetDenseIterator<T> tmp(*this);
+ operator++();
+ return tmp;
+ }
+
+ bool operator==(const IdSetDenseIterator<T>& rhs) const noexcept {
+ return m_set == rhs.m_set && m_value == rhs.m_value;
+ }
+
+ bool operator!=(const IdSetDenseIterator<T>& rhs) const noexcept {
+ return ! (*this == rhs);
+ }
+
+ T operator*() const noexcept {
+ assert(m_value < m_last);
+ return m_value;
+ }
+
+ }; // class IdSetDenseIterator
+
+ /**
+ * A set of Ids of the given type. Internal storage is in chunks of
+ * arrays used as bit fields. Internally those chunks will be allocated
+ * as needed, so it works relatively efficiently with both smaller
+ * and larger Id sets. If it is not used, no memory is allocated at
+ * all.
+ */
+ template <typename T>
+ class IdSetDense : public IdSet<T> {
+
+ static_assert(std::is_unsigned<T>::value, "Needs unsigned type");
+ static_assert(sizeof(T) >= 4, "Needs at least 32bit type");
+
+ friend class IdSetDenseIterator<T>;
+
+ // This value is a compromise. For node Ids it could be bigger
+ // 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;
+
+ std::vector<std::unique_ptr<unsigned char[]>> m_data;
+ size_t m_size = 0;
+
+ static size_t chunk_id(T id) noexcept {
+ return id >> (chunk_bits + 3);
+ }
+
+ static size_t offset(T id) noexcept {
+ return (id >> 3) & ((1 << chunk_bits) - 1);
+ }
+
+ static unsigned char bitmask(T id) noexcept {
+ return 1 << (id & 0x7);
+ }
+
+ T last() const noexcept {
+ return m_data.size() * chunk_size * 8;
+ }
+
+ unsigned char& get_element(T id) {
+ const auto cid = chunk_id(id);
+ if (cid >= m_data.size()) {
+ m_data.resize(cid + 1);
+ }
+
+ auto& chunk = m_data[cid];
+ if (!chunk) {
+ chunk.reset(new unsigned char[chunk_size]);
+ ::memset(chunk.get(), 0, chunk_size);
+ }
+
+ return chunk[offset(id)];
+ }
+
+ public:
+
+ using const_iterator = IdSetDenseIterator<T>;
+
+ IdSetDense() = default;
+
+ /**
+ * Add the Id to the set if it is not already in there.
+ *
+ * @param id The Id to set.
+ * @returns true if the Id was added, false if it was already set.
+ */
+ bool check_and_set(T id) {
+ auto& element = get_element(id);
+
+ if ((element & bitmask(id)) == 0) {
+ element |= bitmask(id);
+ ++m_size;
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Add the given Id to the set.
+ *
+ * @param id The Id to set.
+ */
+ void set(T id) override final {
+ (void)check_and_set(id);
+ }
+
+ /**
+ * Remove the given Id from the set.
+ *
+ * @param id The Id to set.
+ */
+ void unset(T id) {
+ auto& element = get_element(id);
+
+ if ((element & bitmask(id)) != 0) {
+ element &= ~bitmask(id);
+ --m_size;
+ }
+ }
+
+ /**
+ * Is the Id in the set?
+ *
+ * @param id The Id to check.
+ */
+ bool get(T id) const noexcept override final {
+ if (chunk_id(id) >= m_data.size()) {
+ return false;
+ }
+ auto* r = m_data[chunk_id(id)].get();
+ if (!r) {
+ return false;
+ }
+ return (r[offset(id)] & bitmask(id)) != 0;
+ }
+
+ /**
+ * Is the set empty?
+ */
+ bool empty() const noexcept override final {
+ return m_size == 0;
+ }
+
+ /**
+ * The number of Ids stored in the set.
+ */
+ size_t size() const noexcept {
+ return m_size;
+ }
+
+ /**
+ * Clear the set.
+ */
+ void clear() override final {
+ m_data.clear();
+ m_size = 0;
+ }
+
+ IdSetDenseIterator<T> begin() const {
+ return IdSetDenseIterator<T>{this, 0, last()};
+ }
+
+ IdSetDenseIterator<T> end() const {
+ return IdSetDenseIterator<T>{this, last(), last()};
+ }
+
+ }; // class IdSetDense
+
+ /**
+ * IdSet implementation for small Id sets. It writes the Ids
+ * into a vector and uses linear search.
+ */
+ template <typename T>
+ class IdSetSmall : public IdSet<T> {
+
+ std::vector<T> m_data;
+
+ public:
+
+ /**
+ * Add the given Id to the set.
+ */
+ void set(T id) override final {
+ m_data.push_back(id);
+ }
+
+ /**
+ * Is the Id in the set? Uses linear search.
+ *
+ * @param id The Id to check.
+ */
+ bool get(T id) const noexcept override final {
+ const auto it = std::find(m_data.cbegin(), m_data.cend(), id);
+ return it != m_data.cend();
+ }
+
+ /**
+ * Is the Id in the set? Uses a binary search. For larger sets
+ * this might be more efficient than calling get(), the set
+ * must be sorted.
+ *
+ * @param id The Id to check.
+ * @pre You must have called sort_unique() before calling this
+ * or be sure there are no duplicates and the Ids have been
+ * set in order.
+ */
+ bool get_binary_search(T id) const noexcept {
+ return std::binary_search(m_data.cbegin(), m_data.cend(), id);
+ }
+
+ /**
+ * Is the set empty?
+ */
+ bool empty() const noexcept override final {
+ return m_data.empty();
+ }
+
+ /**
+ * Clear the set.
+ */
+ void clear() override final {
+ m_data.clear();
+ }
+
+ /**
+ * Sort the internal vector and remove any duplicates. Call this
+ * before using size(), get_binary_search() or using an iterator.
+ */
+ void sort_unique() {
+ std::sort(m_data.begin(), m_data.end());
+ const auto last = std::unique(m_data.begin(), m_data.end());
+ m_data.erase(last, m_data.end());
+
+ }
+
+ /**
+ * The number of Ids stored in the set.
+ *
+ * @pre You must have called sort_unique() before calling this
+ * or be sure there are no duplicates.
+ */
+ size_t size() const noexcept {
+ return m_data.size();
+ }
+
+ /// Iterator type. There is no non-const iterator.
+ using const_iterator = typename std::vector<T>::const_iterator;
+
+ const_iterator begin() const noexcept {
+ return m_data.cbegin();
+ }
+
+ const_iterator end() const noexcept {
+ return m_data.cend();
+ }
+
+ const_iterator cbegin() const noexcept {
+ return m_data.cbegin();
+ }
+
+ const_iterator cend() const noexcept {
+ return m_data.cend();
+ }
+
+ }; // class IdSetSmall
+
+ template <template<typename> class IdSetType>
+ class NWRIdSet {
+
+ using id_set_type = IdSetType<osmium::unsigned_object_id_type>;
+
+ id_set_type m_sets[3];
+
+ public:
+
+ id_set_type& operator()(osmium::item_type type) noexcept {
+ return m_sets[osmium::item_type_to_nwr_index(type)];
+ }
+
+ const id_set_type& operator()(osmium::item_type type) const noexcept {
+ return m_sets[osmium::item_type_to_nwr_index(type)];
+ }
+
+ }; // class NWRIdSet
+
+ } // namespace index
+
+} // namespace osmium
+
+#endif // OSMIUM_INDEX_ID_SET_HPP
diff --git a/include/osmium/index/index.hpp b/include/osmium/index/index.hpp
index c3deead..65871f2 100644
--- a/include/osmium/index/index.hpp
+++ b/include/osmium/index/index.hpp
@@ -35,7 +35,6 @@ DEALINGS IN THE SOFTWARE.
#include <cstddef>
#include <limits>
-#include <sstream>
#include <stdexcept>
#include <string>
@@ -57,6 +56,10 @@ namespace osmium {
std::runtime_error(what) {
}
+ explicit not_found(uint64_t id) :
+ std::runtime_error(std::string{"id "} + std::to_string(id) + " not found") {
+ }
+
}; // struct not_found
/**
@@ -64,13 +67,6 @@ namespace osmium {
*/
namespace index {
- template <typename TKey>
- OSMIUM_NORETURN void not_found_error(TKey key) {
- std::stringstream s;
- s << "id " << key << " not found";
- throw not_found(s.str());
- }
-
/**
* Some of the index classes need an "empty" value that can
* never appear in real data. This function must return this
diff --git a/include/osmium/index/map.hpp b/include/osmium/index/map.hpp
index 1d2d5aa..d26a4aa 100644
--- a/include/osmium/index/map.hpp
+++ b/include/osmium/index/map.hpp
@@ -48,6 +48,18 @@ DEALINGS IN THE SOFTWARE.
namespace osmium {
+ struct map_factory_error : public std::runtime_error {
+
+ explicit map_factory_error(const char* message) :
+ std::runtime_error(message) {
+ }
+
+ explicit map_factory_error(const std::string& message) :
+ std::runtime_error(message) {
+ }
+
+ }; // struct map_factory_error
+
namespace index {
/**
@@ -148,14 +160,14 @@ namespace osmium {
// default implementation is empty
}
- // This function could usually be const in derived classes,
+ // 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_list(const int /*fd*/) {
throw std::runtime_error("can't dump as list");
}
- // This function could usually be const in derived classes,
+ // 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*/) {
@@ -188,13 +200,6 @@ namespace osmium {
MapFactory(MapFactory&&) = delete;
MapFactory& operator=(MapFactory&&) = delete;
- OSMIUM_NORETURN static void error(const std::string& map_type_name) {
- std::string error_message {"Support for map type '"};
- error_message += map_type_name;
- error_message += "' not compiled into this binary.";
- throw std::runtime_error(error_message);
- }
-
public:
static MapFactory<id_type, value_type>& instance() {
@@ -226,7 +231,7 @@ namespace osmium {
std::vector<std::string> config = osmium::split_string(config_string, ',');
if (config.empty()) {
- throw std::runtime_error("Need non-empty map type name.");
+ throw map_factory_error{"Need non-empty map type name"};
}
auto it = m_callbacks.find(config[0]);
@@ -234,7 +239,7 @@ namespace osmium {
return std::unique_ptr<map_type>((it->second)(config));
}
- error(config[0]);
+ throw map_factory_error{std::string{"Support for map type '"} + config[0] + "' not compiled into this binary"};
}
}; // class MapFactory
diff --git a/include/osmium/index/map/dummy.hpp b/include/osmium/index/map/dummy.hpp
index 98d082b..529ad25 100644
--- a/include/osmium/index/map/dummy.hpp
+++ b/include/osmium/index/map/dummy.hpp
@@ -63,7 +63,7 @@ namespace osmium {
}
const TValue get(const TId id) const final {
- not_found_error(id);
+ throw osmium::not_found{id};
}
size_t size() const final {
diff --git a/include/osmium/index/map/sparse_mem_map.hpp b/include/osmium/index/map/sparse_mem_map.hpp
index 1e3c58c..43fea36 100644
--- a/include/osmium/index/map/sparse_mem_map.hpp
+++ b/include/osmium/index/map/sparse_mem_map.hpp
@@ -79,7 +79,7 @@ namespace osmium {
const TValue get(const TId id) const final {
auto it = m_elements.find(id);
if (it == m_elements.end()) {
- not_found_error(id);
+ throw osmium::not_found{id};
}
return it->second;
}
diff --git a/include/osmium/index/map/sparse_mem_table.hpp b/include/osmium/index/map/sparse_mem_table.hpp
index 241a64f..68f5797 100644
--- a/include/osmium/index/map/sparse_mem_table.hpp
+++ b/include/osmium/index/map/sparse_mem_table.hpp
@@ -99,10 +99,10 @@ namespace osmium {
const TValue get(const TId id) const final {
if (id >= m_elements.size()) {
- not_found_error(id);
+ throw osmium::not_found{id};
}
if (m_elements[id] == osmium::index::empty_value<TValue>()) {
- not_found_error(id);
+ throw osmium::not_found{id};
}
return m_elements[id];
}
diff --git a/include/osmium/io/compression.hpp b/include/osmium/io/compression.hpp
index e7f93bd..a38bba6 100644
--- a/include/osmium/io/compression.hpp
+++ b/include/osmium/io/compression.hpp
@@ -145,10 +145,11 @@ namespace osmium {
private:
- using compression_map_type = std::map<const osmium::io::file_compression,
- std::tuple<create_compressor_type,
- create_decompressor_type_fd,
- create_decompressor_type_buffer>>;
+ using callbacks_type = std::tuple<create_compressor_type,
+ create_decompressor_type_fd,
+ create_decompressor_type_buffer>;
+
+ using compression_map_type = std::map<const osmium::io::file_compression, callbacks_type>;
compression_map_type m_callbacks;
@@ -160,11 +161,17 @@ namespace osmium {
CompressionFactory(CompressionFactory&&) = delete;
CompressionFactory& operator=(CompressionFactory&&) = delete;
- OSMIUM_NORETURN void error(osmium::io::file_compression compression) {
- std::string error_message {"Support for compression '"};
+ const callbacks_type& find_callbacks(osmium::io::file_compression compression) const {
+ const auto it = m_callbacks.find(compression);
+
+ if (it != m_callbacks.end()) {
+ return it->second;
+ }
+
+ std::string error_message{"Support for compression '"};
error_message += as_string(compression);
- error_message += "' not compiled into this binary.";
- throw unsupported_file_format_error(error_message);
+ error_message += "' not compiled into this binary";
+ throw unsupported_file_format_error{error_message};
}
public:
@@ -189,36 +196,21 @@ namespace osmium {
}
template <typename... TArgs>
- std::unique_ptr<osmium::io::Compressor> create_compressor(osmium::io::file_compression compression, TArgs&&... args) {
- auto it = m_callbacks.find(compression);
-
- if (it != m_callbacks.end()) {
- return std::unique_ptr<osmium::io::Compressor>(std::get<0>(it->second)(std::forward<TArgs>(args)...));
- }
-
- error(compression);
+ std::unique_ptr<osmium::io::Compressor> create_compressor(osmium::io::file_compression compression, TArgs&&... args) const {
+ const auto callbacks = find_callbacks(compression);
+ return std::unique_ptr<osmium::io::Compressor>(std::get<0>(callbacks)(std::forward<TArgs>(args)...));
}
- std::unique_ptr<osmium::io::Decompressor> create_decompressor(osmium::io::file_compression compression, int fd) {
- auto it = m_callbacks.find(compression);
-
- if (it != m_callbacks.end()) {
- auto p = std::unique_ptr<osmium::io::Decompressor>(std::get<1>(it->second)(fd));
- p->set_file_size(osmium::util::file_size(fd));
- return p;
- }
-
- error(compression);
+ std::unique_ptr<osmium::io::Decompressor> create_decompressor(osmium::io::file_compression compression, int fd) const {
+ const auto callbacks = find_callbacks(compression);
+ auto p = std::unique_ptr<osmium::io::Decompressor>(std::get<1>(callbacks)(fd));
+ p->set_file_size(osmium::util::file_size(fd));
+ return p;
}
- std::unique_ptr<osmium::io::Decompressor> create_decompressor(osmium::io::file_compression compression, const char* buffer, size_t size) {
- auto it = m_callbacks.find(compression);
-
- if (it != m_callbacks.end()) {
- return std::unique_ptr<osmium::io::Decompressor>(std::get<2>(it->second)(buffer, size));
- }
-
- error(compression);
+ std::unique_ptr<osmium::io::Decompressor> create_decompressor(osmium::io::file_compression compression, const char* buffer, size_t size) const {
+ const auto callbacks = find_callbacks(compression);
+ return std::unique_ptr<osmium::io::Decompressor>(std::get<2>(callbacks)(buffer, size));
}
}; // class CompressionFactory
diff --git a/include/osmium/io/detail/input_format.hpp b/include/osmium/io/detail/input_format.hpp
index 98081e3..67b05a8 100644
--- a/include/osmium/io/detail/input_format.hpp
+++ b/include/osmium/io/detail/input_format.hpp
@@ -55,12 +55,17 @@ namespace osmium {
namespace detail {
+ struct reader_options {
+ osmium::osm_entity_bits::type read_which_entities = osm_entity_bits::all;
+ osmium::io::read_meta read_metadata = read_meta::yes;
+ };
+
class Parser {
future_buffer_queue_type& m_output_queue;
std::promise<osmium::io::Header>& m_header_promise;
queue_wrapper<std::string> m_input_queue;
- osmium::osm_entity_bits::type m_read_types;
+ reader_options m_options;
bool m_header_is_done;
protected:
@@ -73,11 +78,15 @@ namespace osmium {
return m_input_queue.has_reached_end_of_data();
}
- osmium::osm_entity_bits::type read_types() const {
- return m_read_types;
+ osmium::osm_entity_bits::type read_types() const noexcept {
+ return m_options.read_which_entities;
+ }
+
+ osmium::io::read_meta read_metadata() const noexcept {
+ return m_options.read_metadata;
}
- bool header_is_done() const {
+ bool header_is_done() const noexcept {
return m_header_is_done;
}
@@ -111,11 +120,11 @@ namespace osmium {
Parser(future_string_queue_type& input_queue,
future_buffer_queue_type& output_queue,
std::promise<osmium::io::Header>& header_promise,
- osmium::osm_entity_bits::type read_types) :
+ osmium::io::detail::reader_options options) :
m_output_queue(output_queue),
m_header_promise(header_promise),
m_input_queue(input_queue),
- m_read_types(read_types),
+ m_options(options),
m_header_is_done(false) {
}
@@ -157,7 +166,7 @@ namespace osmium {
using create_parser_type = std::function<std::unique_ptr<Parser>(future_string_queue_type&,
future_buffer_queue_type&,
std::promise<osmium::io::Header>& header_promise,
- osmium::osm_entity_bits::type read_which_entities)>;
+ osmium::io::detail::reader_options options)>;
private:
diff --git a/include/osmium/io/detail/o5m_input_format.hpp b/include/osmium/io/detail/o5m_input_format.hpp
index d642879..de4595e 100644
--- a/include/osmium/io/detail/o5m_input_format.hpp
+++ b/include/osmium/io/detail/o5m_input_format.hpp
@@ -80,7 +80,7 @@ namespace osmium {
struct o5m_error : public io_error {
explicit o5m_error(const char* what) :
- io_error(std::string("o5m format error: ") + what) {
+ io_error(std::string{"o5m format error: "} + what) {
}
}; // struct o5m_error
@@ -135,7 +135,7 @@ namespace osmium {
const char* get(uint64_t index) const {
if (m_table.empty() || index == 0 || index > number_of_entries) {
- throw o5m_error("reference to non-existing string in table");
+ throw o5m_error{"reference to non-existing string in table"};
}
auto entry = (current_entry + number_of_entries - index) % number_of_entries;
return &m_table[entry * entry_size];
@@ -191,7 +191,7 @@ namespace osmium {
static const unsigned char header_magic[] = { 0xff, 0xe0, 0x04, 'o', '5' };
if (std::strncmp(reinterpret_cast<const char*>(header_magic), m_data, sizeof(header_magic))) {
- throw o5m_error("wrong header magic");
+ throw o5m_error{"wrong header magic"};
}
m_data += sizeof(header_magic);
@@ -203,7 +203,7 @@ namespace osmium {
} else if (*m_data == 'c') { // o5c change file
m_header.set_has_multiple_object_versions(true);
} else {
- throw o5m_error("wrong header magic");
+ throw o5m_error{"wrong header magic"};
}
m_data++;
@@ -211,7 +211,7 @@ namespace osmium {
void check_file_format_version() {
if (*m_data != '2') {
- throw o5m_error("wrong header magic");
+ throw o5m_error{"wrong header magic"};
}
m_data++;
@@ -219,7 +219,7 @@ namespace osmium {
void decode_header() {
if (! ensure_bytes_available(7)) { // overall length of header
- throw o5m_error("file too short (incomplete header info)");
+ throw o5m_error{"file too short (incomplete header info)"};
}
check_header_magic();
@@ -260,7 +260,7 @@ namespace osmium {
if (**dataptr == 0x00) { // get inline string
(*dataptr)++;
if (*dataptr == end) {
- throw o5m_error("string format error");
+ throw o5m_error{"string format error"};
}
return *dataptr;
} else { // get from reference table
@@ -277,7 +277,7 @@ namespace osmium {
auto uid = protozero::decode_varint(&data, end);
if (data == end) {
- throw o5m_error("missing user name");
+ throw o5m_error{"missing user name"};
}
const char* user = ++data;
@@ -290,7 +290,7 @@ namespace osmium {
while (*data++) {
if (data == end) {
- throw o5m_error("no null byte in user name");
+ throw o5m_error{"no null byte in user name"};
}
}
@@ -302,24 +302,24 @@ namespace osmium {
return std::make_pair(static_cast_with_assert<osmium::user_id_type>(uid), user);
}
- void decode_tags(osmium::builder::Builder* builder, const char** dataptr, const char* const end) {
- osmium::builder::TagListBuilder tl_builder(m_buffer, builder);
+ void decode_tags(osmium::builder::Builder& parent, const char** dataptr, const char* const end) {
+ osmium::builder::TagListBuilder builder{parent};
- while(*dataptr != end) {
+ while (*dataptr != end) {
bool update_pointer = (**dataptr == 0x00);
const char* data = decode_string(dataptr, end);
const char* start = data;
while (*data++) {
if (data == end) {
- throw o5m_error("no null byte in tag key");
+ throw o5m_error{"no null byte in tag key"};
}
}
const char* value = data;
while (*data++) {
if (data == end) {
- throw o5m_error("no null byte in tag value");
+ throw o5m_error{"no null byte in tag value"};
}
}
@@ -328,7 +328,7 @@ namespace osmium {
*dataptr = data;
}
- tl_builder.add_tag(start, value);
+ builder.add_tag(start, value);
}
}
@@ -357,50 +357,46 @@ namespace osmium {
}
void decode_node(const char* data, const char* const end) {
- osmium::builder::NodeBuilder builder(m_buffer);
- osmium::Node& node = builder.object();
+ osmium::builder::NodeBuilder builder{m_buffer};
- node.set_id(m_delta_id.update(zvarint(&data, end)));
+ builder.set_id(m_delta_id.update(zvarint(&data, end)));
- builder.add_user(decode_info(node, &data, end));
+ builder.set_user(decode_info(builder.object(), &data, end));
if (data == end) {
// no location, object is deleted
- builder.object().set_visible(false);
- builder.object().set_location(osmium::Location{});
+ builder.set_visible(false);
+ builder.set_location(osmium::Location{});
} else {
auto lon = m_delta_lon.update(zvarint(&data, end));
auto lat = m_delta_lat.update(zvarint(&data, end));
- builder.object().set_location(osmium::Location{lon, lat});
+ builder.set_location(osmium::Location{lon, lat});
if (data != end) {
- decode_tags(&builder, &data, end);
+ decode_tags(builder, &data, end);
}
}
-
- m_buffer.commit();
}
void decode_way(const char* data, const char* const end) {
- osmium::builder::WayBuilder builder(m_buffer);
- osmium::Way& way = builder.object();
+ osmium::builder::WayBuilder builder{m_buffer};
- way.set_id(m_delta_id.update(zvarint(&data, end)));
+ builder.set_id(m_delta_id.update(zvarint(&data, end)));
- builder.add_user(decode_info(way, &data, end));
+ builder.set_user(decode_info(builder.object(), &data, end));
if (data == end) {
// no reference section, object is deleted
- builder.object().set_visible(false);
+ builder.set_visible(false);
} else {
auto reference_section_length = protozero::decode_varint(&data, end);
if (reference_section_length > 0) {
const char* const end_refs = data + reference_section_length;
if (end_refs > end) {
- throw o5m_error("way nodes ref section too long");
+ throw o5m_error{"way nodes ref section too long"};
}
- osmium::builder::WayNodeListBuilder wn_builder(m_buffer, &builder);
+ osmium::builder::WayNodeListBuilder wn_builder{builder};
while (data < end_refs) {
wn_builder.add_node_ref(m_delta_way_node_id.update(zvarint(&data, end)));
@@ -408,16 +404,14 @@ namespace osmium {
}
if (data != end) {
- decode_tags(&builder, &data, end);
+ decode_tags(builder, &data, end);
}
}
-
- m_buffer.commit();
}
osmium::item_type decode_member_type(char c) {
if (c < '0' || c > '2') {
- throw o5m_error("unknown member type");
+ throw o5m_error{"unknown member type"};
}
return osmium::nwr_index_to_item_type(c - '0');
}
@@ -429,13 +423,13 @@ namespace osmium {
auto member_type = decode_member_type(*data++);
if (data == end) {
- throw o5m_error("missing role");
+ throw o5m_error{"missing role"};
}
const char* role = data;
while (*data++) {
if (data == end) {
- throw o5m_error("no null byte in role");
+ throw o5m_error{"no null byte in role"};
}
}
@@ -448,30 +442,29 @@ namespace osmium {
}
void decode_relation(const char* data, const char* const end) {
- osmium::builder::RelationBuilder builder(m_buffer);
- osmium::Relation& relation = builder.object();
+ osmium::builder::RelationBuilder builder{m_buffer};
- relation.set_id(m_delta_id.update(zvarint(&data, end)));
+ builder.set_id(m_delta_id.update(zvarint(&data, end)));
- builder.add_user(decode_info(relation, &data, end));
+ builder.set_user(decode_info(builder.object(), &data, end));
if (data == end) {
// no reference section, object is deleted
- builder.object().set_visible(false);
+ builder.set_visible(false);
} else {
auto reference_section_length = protozero::decode_varint(&data, end);
if (reference_section_length > 0) {
const char* const end_refs = data + reference_section_length;
if (end_refs > end) {
- throw o5m_error("relation format error");
+ throw o5m_error{"relation format error"};
}
- osmium::builder::RelationMemberListBuilder rml_builder(m_buffer, &builder);
+ osmium::builder::RelationMemberListBuilder rml_builder{builder};
while (data < end_refs) {
auto delta_id = zvarint(&data, end);
if (data == end) {
- throw o5m_error("relation member format error");
+ throw o5m_error{"relation member format error"};
}
auto type_role = decode_role(&data, end);
auto i = osmium::item_type_to_nwr_index(type_role.first);
@@ -481,11 +474,9 @@ namespace osmium {
}
if (data != end) {
- decode_tags(&builder, &data, end);
+ decode_tags(builder, &data, end);
}
}
-
- m_buffer.commit();
}
void decode_bbox(const char* data, const char* const end) {
@@ -537,11 +528,11 @@ namespace osmium {
try {
length = protozero::decode_varint(&m_data, m_end);
} catch (const protozero::end_of_buffer_exception&) {
- throw o5m_error("premature end of file");
+ throw o5m_error{"premature end of file"};
}
if (! ensure_bytes_available(length)) {
- throw o5m_error("premature end of file");
+ throw o5m_error{"premature end of file"};
}
switch (ds_type) {
@@ -549,18 +540,21 @@ namespace osmium {
mark_header_as_done();
if (read_types() & osmium::osm_entity_bits::node) {
decode_node(m_data, m_data + length);
+ m_buffer.commit();
}
break;
case dataset_type::way:
mark_header_as_done();
if (read_types() & osmium::osm_entity_bits::way) {
decode_way(m_data, m_data + length);
+ m_buffer.commit();
}
break;
case dataset_type::relation:
mark_header_as_done();
if (read_types() & osmium::osm_entity_bits::relation) {
decode_relation(m_data, m_data + length);
+ m_buffer.commit();
}
break;
case dataset_type::bounding_box:
@@ -598,8 +592,8 @@ namespace osmium {
O5mParser(future_string_queue_type& input_queue,
future_buffer_queue_type& output_queue,
std::promise<osmium::io::Header>& header_promise,
- osmium::osm_entity_bits::type read_types) :
- Parser(input_queue, output_queue, header_promise, read_types),
+ osmium::io::detail::reader_options options) :
+ Parser(input_queue, output_queue, header_promise, options),
m_header(),
m_buffer(buffer_size),
m_input(),
@@ -625,8 +619,8 @@ namespace osmium {
[](future_string_queue_type& input_queue,
future_buffer_queue_type& output_queue,
std::promise<osmium::io::Header>& header_promise,
- osmium::osm_entity_bits::type read_which_entities) {
- return std::unique_ptr<Parser>(new O5mParser(input_queue, output_queue, header_promise, read_which_entities));
+ osmium::io::detail::reader_options options) {
+ return std::unique_ptr<Parser>(new O5mParser(input_queue, output_queue, header_promise, options));
});
// dummy function to silence the unused variable warning from above
diff --git a/include/osmium/io/detail/opl_input_format.hpp b/include/osmium/io/detail/opl_input_format.hpp
index 15a31f3..1bd8b07 100644
--- a/include/osmium/io/detail/opl_input_format.hpp
+++ b/include/osmium/io/detail/opl_input_format.hpp
@@ -82,8 +82,8 @@ namespace osmium {
OPLParser(future_string_queue_type& input_queue,
future_buffer_queue_type& output_queue,
std::promise<osmium::io::Header>& header_promise,
- osmium::osm_entity_bits::type read_types) :
- Parser(input_queue, output_queue, header_promise, read_types) {
+ osmium::io::detail::reader_options options) :
+ Parser(input_queue, output_queue, header_promise, options) {
set_header_value(osmium::io::Header{});
}
@@ -137,8 +137,8 @@ namespace osmium {
[](future_string_queue_type& input_queue,
future_buffer_queue_type& output_queue,
std::promise<osmium::io::Header>& header_promise,
- osmium::osm_entity_bits::type read_which_entities) {
- return std::unique_ptr<Parser>(new OPLParser(input_queue, output_queue, header_promise, read_which_entities));
+ osmium::io::detail::reader_options options) {
+ return std::unique_ptr<Parser>(new OPLParser(input_queue, output_queue, header_promise, options));
});
// 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 97c5927..ee35b36 100644
--- a/include/osmium/io/detail/opl_parser_functions.hpp
+++ b/include/osmium/io/detail/opl_parser_functions.hpp
@@ -365,9 +365,8 @@ namespace osmium {
inline void opl_parse_node(const char** data, osmium::memory::Buffer& buffer) {
osmium::builder::NodeBuilder builder{buffer};
- osmium::Node& node = builder.object();
- node.set_id(opl_parse_id(data));
+ builder.set_id(opl_parse_id(data));
const char* tags_begin = nullptr;
@@ -382,19 +381,19 @@ namespace osmium {
++(*data);
switch (c) {
case 'v':
- node.set_version(opl_parse_version(data));
+ builder.set_version(opl_parse_version(data));
break;
case 'd':
- node.set_visible(opl_parse_visible(data));
+ builder.set_visible(opl_parse_visible(data));
break;
case 'c':
- node.set_changeset(opl_parse_changeset_id(data));
+ builder.set_changeset(opl_parse_changeset_id(data));
break;
case 't':
- node.set_timestamp(opl_parse_timestamp(data));
+ builder.set_timestamp(opl_parse_timestamp(data));
break;
case 'i':
- node.set_uid(opl_parse_uid(data));
+ builder.set_uid(opl_parse_uid(data));
break;
case 'u':
opl_parse_string(data, user);
@@ -422,23 +421,20 @@ namespace osmium {
}
if (location.valid()) {
- node.set_location(location);
+ builder.set_location(location);
}
- builder.add_user(user);
+ builder.set_user(user);
if (tags_begin) {
opl_parse_tags(tags_begin, buffer, &builder);
}
-
- buffer.commit();
}
inline void opl_parse_way(const char** data, osmium::memory::Buffer& buffer) {
osmium::builder::WayBuilder builder{buffer};
- osmium::Way& way = builder.object();
- way.set_id(opl_parse_id(data));
+ builder.set_id(opl_parse_id(data));
const char* tags_begin = nullptr;
@@ -455,19 +451,19 @@ namespace osmium {
++(*data);
switch (c) {
case 'v':
- way.set_version(opl_parse_version(data));
+ builder.set_version(opl_parse_version(data));
break;
case 'd':
- way.set_visible(opl_parse_visible(data));
+ builder.set_visible(opl_parse_visible(data));
break;
case 'c':
- way.set_changeset(opl_parse_changeset_id(data));
+ builder.set_changeset(opl_parse_changeset_id(data));
break;
case 't':
- way.set_timestamp(opl_parse_timestamp(data));
+ builder.set_timestamp(opl_parse_timestamp(data));
break;
case 'i':
- way.set_uid(opl_parse_uid(data));
+ builder.set_uid(opl_parse_uid(data));
break;
case 'u':
opl_parse_string(data, user);
@@ -488,15 +484,13 @@ namespace osmium {
}
}
- builder.add_user(user);
+ builder.set_user(user);
if (tags_begin) {
opl_parse_tags(tags_begin, buffer, &builder);
}
opl_parse_way_nodes(nodes_begin, nodes_end, buffer, &builder);
-
- buffer.commit();
}
inline void opl_parse_relation_members(const char* s, const char* e, osmium::memory::Buffer& buffer, osmium::builder::RelationBuilder* parent_builder = nullptr) {
@@ -536,9 +530,8 @@ namespace osmium {
inline void opl_parse_relation(const char** data, osmium::memory::Buffer& buffer) {
osmium::builder::RelationBuilder builder{buffer};
- osmium::Relation& relation = builder.object();
- relation.set_id(opl_parse_id(data));
+ builder.set_id(opl_parse_id(data));
const char* tags_begin = nullptr;
@@ -555,19 +548,19 @@ namespace osmium {
++(*data);
switch (c) {
case 'v':
- relation.set_version(opl_parse_version(data));
+ builder.set_version(opl_parse_version(data));
break;
case 'd':
- relation.set_visible(opl_parse_visible(data));
+ builder.set_visible(opl_parse_visible(data));
break;
case 'c':
- relation.set_changeset(opl_parse_changeset_id(data));
+ builder.set_changeset(opl_parse_changeset_id(data));
break;
case 't':
- relation.set_timestamp(opl_parse_timestamp(data));
+ builder.set_timestamp(opl_parse_timestamp(data));
break;
case 'i':
- relation.set_uid(opl_parse_uid(data));
+ builder.set_uid(opl_parse_uid(data));
break;
case 'u':
opl_parse_string(data, user);
@@ -588,7 +581,7 @@ namespace osmium {
}
}
- builder.add_user(user);
+ builder.set_user(user);
if (tags_begin) {
opl_parse_tags(tags_begin, buffer, &builder);
@@ -597,15 +590,12 @@ namespace osmium {
if (members_begin != members_end) {
opl_parse_relation_members(members_begin, members_end, buffer, &builder);
}
-
- buffer.commit();
}
inline void opl_parse_changeset(const char** data, osmium::memory::Buffer& buffer) {
osmium::builder::ChangesetBuilder builder{buffer};
- osmium::Changeset& changeset = builder.object();
- changeset.set_id(opl_parse_changeset_id(data));
+ builder.set_id(opl_parse_changeset_id(data));
const char* tags_begin = nullptr;
@@ -621,19 +611,19 @@ namespace osmium {
++(*data);
switch (c) {
case 'k':
- changeset.set_num_changes(opl_parse_int<osmium::num_changes_type>(data));
+ builder.set_num_changes(opl_parse_int<osmium::num_changes_type>(data));
break;
case 's':
- changeset.set_created_at(opl_parse_timestamp(data));
+ builder.set_created_at(opl_parse_timestamp(data));
break;
case 'e':
- changeset.set_closed_at(opl_parse_timestamp(data));
+ builder.set_closed_at(opl_parse_timestamp(data));
break;
case 'd':
- changeset.set_num_comments(opl_parse_int<osmium::num_comments_type>(data));
+ builder.set_num_comments(opl_parse_int<osmium::num_comments_type>(data));
break;
case 'i':
- changeset.set_uid(opl_parse_uid(data));
+ builder.set_uid(opl_parse_uid(data));
break;
case 'u':
opl_parse_string(data, user);
@@ -672,17 +662,17 @@ namespace osmium {
}
if (location1.valid() && location2.valid()) {
- changeset.bounds().extend(location1);
- changeset.bounds().extend(location2);
+ osmium::Box box;
+ box.extend(location1);
+ box.extend(location2);
+ builder.set_bounds(box);
}
- builder.add_user(user);
+ builder.set_user(user);
if (tags_begin) {
opl_parse_tags(tags_begin, buffer, &builder);
}
-
- buffer.commit();
}
inline bool opl_parse_line(uint64_t line_count,
@@ -702,6 +692,7 @@ namespace osmium {
if (read_types & osmium::osm_entity_bits::node) {
++data;
opl_parse_node(&data, buffer);
+ buffer.commit();
return true;
}
break;
@@ -709,6 +700,7 @@ namespace osmium {
if (read_types & osmium::osm_entity_bits::way) {
++data;
opl_parse_way(&data, buffer);
+ buffer.commit();
return true;
}
break;
@@ -716,6 +708,7 @@ namespace osmium {
if (read_types & osmium::osm_entity_bits::relation) {
++data;
opl_parse_relation(&data, buffer);
+ buffer.commit();
return true;
}
break;
@@ -723,6 +716,7 @@ namespace osmium {
if (read_types & osmium::osm_entity_bits::changeset) {
++data;
opl_parse_changeset(&data, buffer);
+ buffer.commit();
return true;
}
break;
diff --git a/include/osmium/io/detail/pbf_decoder.hpp b/include/osmium/io/detail/pbf_decoder.hpp
index 5df191d..5164ce3 100644
--- a/include/osmium/io/detail/pbf_decoder.hpp
+++ b/include/osmium/io/detail/pbf_decoder.hpp
@@ -50,6 +50,7 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/io/detail/pbf.hpp> // IWYU pragma: export
#include <osmium/io/detail/protobuf_tags.hpp>
#include <osmium/io/detail/zlib.hpp>
+#include <osmium/io/file_format.hpp>
#include <osmium/io/header.hpp>
#include <osmium/memory/buffer.hpp>
#include <osmium/osm/box.hpp>
@@ -94,6 +95,8 @@ namespace osmium {
osmium::memory::Buffer m_buffer { initial_buffer_size };
+ osmium::io::read_meta m_read_metadata;
+
void decode_stringtable(const data_view& data) {
if (!m_stringtable.empty()) {
throw osmium::pbf_error("more than one stringtable in pbf file");
@@ -143,13 +146,19 @@ namespace osmium {
case OSMFormat::PrimitiveGroup::repeated_Node_nodes:
if (m_read_types & osmium::osm_entity_bits::node) {
decode_node(pbf_primitive_group.get_view());
+ m_buffer.commit();
} else {
pbf_primitive_group.skip();
}
break;
case OSMFormat::PrimitiveGroup::optional_DenseNodes_dense:
if (m_read_types & osmium::osm_entity_bits::node) {
- decode_dense_nodes(pbf_primitive_group.get_view());
+ if (m_read_metadata == osmium::io::read_meta::yes) {
+ decode_dense_nodes(pbf_primitive_group.get_view());
+ } else {
+ decode_dense_nodes_without_metadata(pbf_primitive_group.get_view());
+ }
+ m_buffer.commit();
} else {
pbf_primitive_group.skip();
}
@@ -157,6 +166,7 @@ namespace osmium {
case OSMFormat::PrimitiveGroup::repeated_Way_ways:
if (m_read_types & osmium::osm_entity_bits::way) {
decode_way(pbf_primitive_group.get_view());
+ m_buffer.commit();
} else {
pbf_primitive_group.skip();
}
@@ -164,6 +174,7 @@ namespace osmium {
case OSMFormat::PrimitiveGroup::repeated_Relation_relations:
if (m_read_types & osmium::osm_entity_bits::relation) {
decode_relation(pbf_primitive_group.get_view());
+ m_buffer.commit();
} else {
pbf_primitive_group.skip();
}
@@ -221,9 +232,9 @@ namespace osmium {
using kv_type = protozero::iterator_range<protozero::pbf_reader::const_uint32_iterator>;
- void build_tag_list(osmium::builder::Builder& builder, const kv_type& keys, const kv_type& vals) {
+ void build_tag_list(osmium::builder::Builder& parent, const kv_type& keys, const kv_type& vals) {
if (!keys.empty()) {
- osmium::builder::TagListBuilder tl_builder(m_buffer, &builder);
+ osmium::builder::TagListBuilder builder{parent};
auto kit = keys.begin();
auto vit = vals.begin();
while (kit != keys.end()) {
@@ -233,7 +244,7 @@ namespace osmium {
}
const auto& k = m_stringtable.at(*kit++);
const auto& v = m_stringtable.at(*vit++);
- tl_builder.add_tag(k.first, k.second, v.first, v.second);
+ builder.add_tag(k.first, k.second, v.first, v.second);
}
}
}
@@ -243,7 +254,7 @@ namespace osmium {
}
void decode_node(const data_view& data) {
- osmium::builder::NodeBuilder builder(m_buffer);
+ osmium::builder::NodeBuilder builder{m_buffer};
osmium::Node& node = builder.object();
kv_type keys;
@@ -266,7 +277,11 @@ namespace osmium {
vals = pbf_node.get_packed_uint32();
break;
case OSMFormat::Node::optional_Info_info:
- user = decode_info(pbf_node.get_view(), builder.object());
+ if (m_read_metadata == osmium::io::read_meta::yes) {
+ user = decode_info(pbf_node.get_view(), builder.object());
+ } else {
+ pbf_node.skip();
+ }
break;
case OSMFormat::Node::required_sint64_lat:
lat = pbf_node.get_sint64();
@@ -290,15 +305,13 @@ namespace osmium {
));
}
- builder.add_user(user.first, user.second);
+ builder.set_user(user.first, user.second);
build_tag_list(builder, keys, vals);
-
- m_buffer.commit();
}
void decode_way(const data_view& data) {
- osmium::builder::WayBuilder builder(m_buffer);
+ osmium::builder::WayBuilder builder{m_buffer};
kv_type keys;
kv_type vals;
@@ -321,7 +334,11 @@ namespace osmium {
vals = pbf_way.get_packed_uint32();
break;
case OSMFormat::Way::optional_Info_info:
- user = decode_info(pbf_way.get_view(), builder.object());
+ if (m_read_metadata == osmium::io::read_meta::yes) {
+ user = decode_info(pbf_way.get_view(), builder.object());
+ } else {
+ pbf_way.skip();
+ }
break;
case OSMFormat::Way::packed_sint64_refs:
refs = pbf_way.get_packed_sint64();
@@ -337,10 +354,10 @@ namespace osmium {
}
}
- builder.add_user(user.first, user.second);
+ builder.set_user(user.first, user.second);
if (!refs.empty()) {
- osmium::builder::WayNodeListBuilder wnl_builder(m_buffer, &builder);
+ osmium::builder::WayNodeListBuilder wnl_builder{builder};
osmium::util::DeltaDecode<int64_t> ref;
if (lats.empty()) {
for (const auto& ref_value : refs) {
@@ -363,12 +380,10 @@ namespace osmium {
}
build_tag_list(builder, keys, vals);
-
- m_buffer.commit();
}
void decode_relation(const data_view& data) {
- osmium::builder::RelationBuilder builder(m_buffer);
+ osmium::builder::RelationBuilder builder{m_buffer};
kv_type keys;
kv_type vals;
@@ -391,7 +406,11 @@ namespace osmium {
vals = pbf_relation.get_packed_uint32();
break;
case OSMFormat::Relation::optional_Info_info:
- user = decode_info(pbf_relation.get_view(), builder.object());
+ if (m_read_metadata == osmium::io::read_meta::yes) {
+ user = decode_info(pbf_relation.get_view(), builder.object());
+ } else {
+ pbf_relation.skip();
+ }
break;
case OSMFormat::Relation::packed_int32_roles_sid:
roles = pbf_relation.get_packed_int32();
@@ -407,10 +426,10 @@ namespace osmium {
}
}
- builder.add_user(user.first, user.second);
+ builder.set_user(user.first, user.second);
if (!refs.empty()) {
- osmium::builder::RelationMemberListBuilder rml_builder(m_buffer, &builder);
+ osmium::builder::RelationMemberListBuilder rml_builder{builder};
osmium::util::DeltaDecode<int64_t> ref;
while (!roles.empty() && !refs.empty() && !types.empty()) {
const auto& r = m_stringtable.at(roles.front());
@@ -431,8 +450,84 @@ namespace osmium {
}
build_tag_list(builder, keys, vals);
+ }
+
+ void build_tag_list_from_dense_nodes(osmium::builder::NodeBuilder& builder, protozero::pbf_reader::const_int32_iterator& it, protozero::pbf_reader::const_int32_iterator last) {
+ osmium::builder::TagListBuilder tl_builder{builder};
+ 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
+ }
+ const auto& v = m_stringtable.at(*it++);
+ tl_builder.add_tag(k.first, k.second, v.first, v.second);
+ }
+
+ if (it != last) {
+ ++it;
+ }
+ }
+
+ void decode_dense_nodes_without_metadata(const data_view& data) {
+ protozero::iterator_range<protozero::pbf_reader::const_sint64_iterator> ids;
+ protozero::iterator_range<protozero::pbf_reader::const_sint64_iterator> lats;
+ protozero::iterator_range<protozero::pbf_reader::const_sint64_iterator> lons;
+
+ protozero::iterator_range<protozero::pbf_reader::const_int32_iterator> tags;
+
+ 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:
+ ids = pbf_dense_nodes.get_packed_sint64();
+ break;
+ case OSMFormat::DenseNodes::packed_sint64_lat:
+ lats = pbf_dense_nodes.get_packed_sint64();
+ break;
+ case OSMFormat::DenseNodes::packed_sint64_lon:
+ lons = pbf_dense_nodes.get_packed_sint64();
+ break;
+ case OSMFormat::DenseNodes::packed_int32_keys_vals:
+ tags = pbf_dense_nodes.get_packed_int32();
+ break;
+ default:
+ pbf_dense_nodes.skip();
+ }
+ }
+
+ osmium::util::DeltaDecode<int64_t> dense_id;
+ osmium::util::DeltaDecode<int64_t> dense_latitude;
+ osmium::util::DeltaDecode<int64_t> dense_longitude;
+
+ auto tag_it = tags.begin();
+
+ while (!ids.empty()) {
+ if (lons.empty() ||
+ lats.empty()) {
+ // this is against the spec, must have same number of elements
+ throw osmium::pbf_error("PBF format error");
+ }
+
+ osmium::builder::NodeBuilder builder{m_buffer};
+ osmium::Node& node = builder.object();
+
+ node.set_id(dense_id.update(ids.front()));
+ ids.drop_front();
+
+ const auto lon = dense_longitude.update(lons.front());
+ lons.drop_front();
+ const auto lat = dense_latitude.update(lats.front());
+ lats.drop_front();
+ builder.object().set_location(osmium::Location(
+ convert_pbf_coordinate(lon),
+ convert_pbf_coordinate(lat)
+ ));
+
+ if (tag_it != tags.end()) {
+ build_tag_list_from_dense_nodes(builder, tag_it, tags.end());
+ }
+ }
- m_buffer.commit();
}
void decode_dense_nodes(const data_view& data) {
@@ -522,7 +617,7 @@ namespace osmium {
bool visible = true;
- osmium::builder::NodeBuilder builder(m_buffer);
+ osmium::builder::NodeBuilder builder{m_buffer};
osmium::Node& node = builder.object();
node.set_id(dense_id.update(ids.front()));
@@ -569,9 +664,7 @@ namespace osmium {
const auto& u = m_stringtable.at(dense_user_sid.update(user_sids.front()));
user_sids.drop_front();
- builder.add_user(u.first, u.second);
- } else {
- builder.add_user("");
+ builder.set_user(u.first, u.second);
}
// even if the node isn't visible, there's still a record
@@ -588,31 +681,18 @@ namespace osmium {
}
if (tag_it != tags.end()) {
- osmium::builder::TagListBuilder tl_builder(m_buffer, &builder);
- while (tag_it != tags.end() && *tag_it != 0) {
- const auto& k = m_stringtable.at(*tag_it++);
- if (tag_it == tags.end()) {
- throw osmium::pbf_error("PBF format error"); // this is against the spec, keys/vals must come in pairs
- }
- const auto& v = m_stringtable.at(*tag_it++);
- tl_builder.add_tag(k.first, k.second, v.first, v.second);
- }
-
- if (tag_it != tags.end()) {
- ++tag_it;
- }
+ build_tag_list_from_dense_nodes(builder, tag_it, tags.end());
}
-
- m_buffer.commit();
}
}
public:
- PBFPrimitiveBlockDecoder(const data_view& data, osmium::osm_entity_bits::type read_types) :
+ PBFPrimitiveBlockDecoder(const data_view& data, osmium::osm_entity_bits::type read_types, osmium::io::read_meta read_metadata) :
m_data(data),
- m_read_types(read_types) {
+ m_read_types(read_types),
+ m_read_metadata(read_metadata) {
}
PBFPrimitiveBlockDecoder(const PBFPrimitiveBlockDecoder&) = delete;
@@ -789,12 +869,14 @@ namespace osmium {
std::shared_ptr<std::string> m_input_buffer;
osmium::osm_entity_bits::type m_read_types;
+ osmium::io::read_meta m_read_metadata;
public:
- PBFDataBlobDecoder(std::string&& input_buffer, osmium::osm_entity_bits::type read_types) :
+ PBFDataBlobDecoder(std::string&& input_buffer, osmium::osm_entity_bits::type read_types, osmium::io::read_meta read_metadata) :
m_input_buffer(std::make_shared<std::string>(std::move(input_buffer))),
- m_read_types(read_types) {
+ m_read_types(read_types),
+ m_read_metadata(read_metadata) {
}
PBFDataBlobDecoder(const PBFDataBlobDecoder&) = default;
@@ -807,7 +889,7 @@ namespace osmium {
osmium::memory::Buffer operator()() {
std::string output;
- PBFPrimitiveBlockDecoder decoder(decode_blob(*m_input_buffer, output), m_read_types);
+ 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 1253447..31e778a 100644
--- a/include/osmium/io/detail/pbf_input_format.hpp
+++ b/include/osmium/io/detail/pbf_input_format.hpp
@@ -180,7 +180,7 @@ namespace osmium {
while (const auto size = check_type_and_get_blob_size("OSMData")) {
std::string input_buffer = read_from_input_queue_with_check(size);
- PBFDataBlobDecoder data_blob_parser{ std::move(input_buffer), read_types() };
+ 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)));
@@ -195,8 +195,8 @@ namespace osmium {
PBFParser(future_string_queue_type& input_queue,
future_buffer_queue_type& output_queue,
std::promise<osmium::io::Header>& header_promise,
- osmium::osm_entity_bits::type read_types) :
- Parser(input_queue, output_queue, header_promise, read_types),
+ osmium::io::detail::reader_options options) :
+ Parser(input_queue, output_queue, header_promise, options),
m_input_buffer() {
}
@@ -221,8 +221,8 @@ namespace osmium {
[](future_string_queue_type& input_queue,
future_buffer_queue_type& output_queue,
std::promise<osmium::io::Header>& header_promise,
- osmium::osm_entity_bits::type read_which_entities) {
- return std::unique_ptr<Parser>(new PBFParser(input_queue, output_queue, header_promise, read_which_entities));
+ osmium::io::detail::reader_options options) {
+ return std::unique_ptr<Parser>(new PBFParser(input_queue, output_queue, header_promise, options));
});
// dummy function to silence the unused variable warning from above
diff --git a/include/osmium/io/detail/queue_util.hpp b/include/osmium/io/detail/queue_util.hpp
index bc47020..021ea7d 100644
--- a/include/osmium/io/detail/queue_util.hpp
+++ b/include/osmium/io/detail/queue_util.hpp
@@ -33,10 +33,10 @@ DEALINGS IN THE SOFTWARE.
*/
-#include <algorithm>
#include <exception>
#include <future>
#include <string>
+#include <utility>
#include <osmium/memory/buffer.hpp>
#include <osmium/thread/queue.hpp>
@@ -63,13 +63,6 @@ namespace osmium {
* This type of queue contains OSM file data in the form it is
* stored on disk, ie encoded as XML, PBF, etc.
* The "end of file" is marked by an empty string.
- */
- using string_queue_type = osmium::thread::Queue<std::string>;
-
- /**
- * This type of queue contains OSM file data in the form it is
- * stored on disk, ie encoded as XML, PBF, etc.
- * The "end of file" is marked by an empty string.
* The strings are wrapped in a std::future so that they can also
* transport exceptions. The future also helps with keeping the
* data in order.
@@ -95,11 +88,11 @@ namespace osmium {
add_to_queue<T>(queue, T{});
}
- inline bool at_end_of_data(const std::string& data) {
+ inline bool at_end_of_data(const std::string& data) noexcept {
return data.empty();
}
- inline bool at_end_of_data(osmium::memory::Buffer& buffer) {
+ inline bool at_end_of_data(osmium::memory::Buffer& buffer) noexcept {
return !buffer;
}
diff --git a/include/osmium/io/detail/xml_input_format.hpp b/include/osmium/io/detail/xml_input_format.hpp
index d8c57d8..242ef9b 100644
--- a/include/osmium/io/detail/xml_input_format.hpp
+++ b/include/osmium/io/detail/xml_input_format.hpp
@@ -80,8 +80,8 @@ namespace osmium {
XML_Error error_code;
std::string error_string;
- explicit xml_error(XML_Parser parser) :
- io_error(std::string("XML parsing error at line ")
+ explicit xml_error(const XML_Parser& parser) :
+ io_error(std::string{"XML parsing error at line "}
+ std::to_string(XML_GetCurrentLineNumber(parser))
+ ", column "
+ std::to_string(XML_GetCurrentColumnNumber(parser))
@@ -117,7 +117,7 @@ namespace osmium {
}
explicit format_version_error(const char* v) :
- io_error(std::string("Can not read file with version ") + v),
+ io_error(std::string{"Can not read file with version "} + v),
version(v) {
}
@@ -201,7 +201,7 @@ namespace osmium {
static void entity_declaration_handler(void*,
const XML_Char*, int, const XML_Char*, int, const XML_Char*,
const XML_Char*, const XML_Char*, const XML_Char*) {
- throw osmium::xml_error("XML entities are not supported");
+ throw osmium::xml_error{"XML entities are not supported"};
}
public:
@@ -209,7 +209,7 @@ namespace osmium {
explicit ExpatXMLParser(T* callback_object) :
m_parser(XML_ParserCreate(nullptr)) {
if (!m_parser) {
- throw osmium::io_error("Internal error: Can not create parser");
+ throw osmium::io_error{"Internal error: Can not create parser"};
}
XML_SetUserData(m_parser, callback_object);
XML_SetElementHandler(m_parser, start_element_wrapper, end_element_wrapper);
@@ -229,7 +229,7 @@ namespace osmium {
void operator()(const std::string& data, bool last) {
if (XML_Parse(m_parser, data.data(), static_cast_with_assert<int>(data.size()), last) == XML_STATUS_ERROR) {
- throw osmium::xml_error(m_parser);
+ throw osmium::xml_error{m_parser};
}
}
@@ -271,37 +271,32 @@ namespace osmium {
return user;
}
- void init_changeset(osmium::builder::ChangesetBuilder* builder, const XML_Char** attrs) {
- const char* user = "";
- osmium::Changeset& new_changeset = builder->object();
+ void init_changeset(osmium::builder::ChangesetBuilder& builder, const XML_Char** attrs) {
+ osmium::Box box;
- osmium::Location min;
- osmium::Location max;
- check_attributes(attrs, [&min, &max, &user, &new_changeset](const XML_Char* name, const XML_Char* value) {
+ check_attributes(attrs, [&builder, &box](const XML_Char* name, const XML_Char* value) {
if (!std::strcmp(name, "min_lon")) {
- min.set_lon(value);
+ box.bottom_left().set_lon(value);
} else if (!std::strcmp(name, "min_lat")) {
- min.set_lat(value);
+ box.bottom_left().set_lat(value);
} else if (!std::strcmp(name, "max_lon")) {
- max.set_lon(value);
+ box.top_right().set_lon(value);
} else if (!std::strcmp(name, "max_lat")) {
- max.set_lat(value);
+ box.top_right().set_lat(value);
} else if (!std::strcmp(name, "user")) {
- user = value;
+ builder.set_user(value);
} else {
- new_changeset.set_attribute(name, value);
+ builder.set_attribute(name, value);
}
});
- new_changeset.bounds().extend(min);
- new_changeset.bounds().extend(max);
-
- builder->add_user(user);
+ builder.set_bounds(box);
}
- void get_tag(osmium::builder::Builder* builder, const XML_Char** attrs) {
+ void get_tag(osmium::builder::Builder& builder, const XML_Char** attrs) {
const char* k = "";
const char* v = "";
+
check_attributes(attrs, [&k, &v](const XML_Char* name, const XML_Char* value) {
if (name[0] == 'k' && name[1] == 0) {
k = value;
@@ -309,8 +304,9 @@ namespace osmium {
v = value;
}
});
+
if (!m_tl_builder) {
- m_tl_builder = std::unique_ptr<osmium::builder::TagListBuilder>(new osmium::builder::TagListBuilder(m_buffer, builder));
+ m_tl_builder.reset(new osmium::builder::TagListBuilder{builder});
}
m_tl_builder->add_tag(k, v);
}
@@ -330,17 +326,17 @@ namespace osmium {
if (!std::strcmp(name, "version")) {
m_header.set("version", value);
if (std::strcmp(value, "0.6")) {
- throw osmium::format_version_error(value);
+ throw osmium::format_version_error{value};
}
} else if (!std::strcmp(name, "generator")) {
m_header.set("generator", value);
}
});
if (m_header.get("version") == "") {
- throw osmium::format_version_error();
+ throw osmium::format_version_error{};
}
} else {
- throw osmium::xml_error(std::string("Unknown top-level element: ") + element);
+ throw osmium::xml_error{std::string{"Unknown top-level element: "} + element};
}
m_context = context::top;
break;
@@ -349,8 +345,8 @@ namespace osmium {
if (!std::strcmp(element, "node")) {
mark_header_as_done();
if (read_types() & osmium::osm_entity_bits::node) {
- m_node_builder = std::unique_ptr<osmium::builder::NodeBuilder>(new osmium::builder::NodeBuilder(m_buffer));
- m_node_builder->add_user(init_object(m_node_builder->object(), attrs));
+ m_node_builder.reset(new osmium::builder::NodeBuilder{m_buffer});
+ m_node_builder->set_user(init_object(m_node_builder->object(), attrs));
m_context = context::node;
} else {
m_context = context::ignored_node;
@@ -358,8 +354,8 @@ namespace osmium {
} else if (!std::strcmp(element, "way")) {
mark_header_as_done();
if (read_types() & osmium::osm_entity_bits::way) {
- m_way_builder = std::unique_ptr<osmium::builder::WayBuilder>(new osmium::builder::WayBuilder(m_buffer));
- m_way_builder->add_user(init_object(m_way_builder->object(), attrs));
+ m_way_builder.reset(new osmium::builder::WayBuilder{m_buffer});
+ m_way_builder->set_user(init_object(m_way_builder->object(), attrs));
m_context = context::way;
} else {
m_context = context::ignored_way;
@@ -367,8 +363,8 @@ namespace osmium {
} else if (!std::strcmp(element, "relation")) {
mark_header_as_done();
if (read_types() & osmium::osm_entity_bits::relation) {
- m_relation_builder = std::unique_ptr<osmium::builder::RelationBuilder>(new osmium::builder::RelationBuilder(m_buffer));
- m_relation_builder->add_user(init_object(m_relation_builder->object(), attrs));
+ m_relation_builder.reset(new osmium::builder::RelationBuilder{m_buffer});
+ m_relation_builder->set_user(init_object(m_relation_builder->object(), attrs));
m_context = context::relation;
} else {
m_context = context::ignored_relation;
@@ -376,8 +372,8 @@ namespace osmium {
} else if (!std::strcmp(element, "changeset")) {
mark_header_as_done();
if (read_types() & osmium::osm_entity_bits::changeset) {
- m_changeset_builder = std::unique_ptr<osmium::builder::ChangesetBuilder>(new osmium::builder::ChangesetBuilder(m_buffer));
- init_changeset(m_changeset_builder.get(), attrs);
+ m_changeset_builder.reset(new osmium::builder::ChangesetBuilder{m_buffer});
+ init_changeset(*m_changeset_builder, attrs);
m_context = context::changeset;
} else {
m_context = context::ignored_changeset;
@@ -407,7 +403,7 @@ namespace osmium {
m_last_context = context::node;
m_context = context::in_object;
if (!std::strcmp(element, "tag")) {
- get_tag(m_node_builder.get(), attrs);
+ get_tag(*m_node_builder, attrs);
}
break;
case context::way:
@@ -417,7 +413,7 @@ namespace osmium {
m_tl_builder.reset();
if (!m_wnl_builder) {
- m_wnl_builder = std::unique_ptr<osmium::builder::WayNodeListBuilder>(new osmium::builder::WayNodeListBuilder(m_buffer, m_way_builder.get()));
+ m_wnl_builder.reset(new osmium::builder::WayNodeListBuilder{*m_way_builder});
}
NodeRef nr;
@@ -433,7 +429,7 @@ namespace osmium {
m_wnl_builder->add_node_ref(nr);
} else if (!std::strcmp(element, "tag")) {
m_wnl_builder.reset();
- get_tag(m_way_builder.get(), attrs);
+ get_tag(*m_way_builder, attrs);
}
break;
case context::relation:
@@ -443,7 +439,7 @@ namespace osmium {
m_tl_builder.reset();
if (!m_rml_builder) {
- m_rml_builder = std::unique_ptr<osmium::builder::RelationMemberListBuilder>(new osmium::builder::RelationMemberListBuilder(m_buffer, m_relation_builder.get()));
+ m_rml_builder.reset(new osmium::builder::RelationMemberListBuilder{*m_relation_builder});
}
item_type type = item_type::undefined;
@@ -459,15 +455,15 @@ namespace osmium {
}
});
if (type != item_type::node && type != item_type::way && type != item_type::relation) {
- throw osmium::xml_error("Unknown type on relation member");
+ throw osmium::xml_error{"Unknown type on relation member"};
}
if (ref == 0) {
- throw osmium::xml_error("Missing ref on relation member");
+ throw osmium::xml_error{"Missing ref on relation member"};
}
m_rml_builder->add_member(type, ref, role);
} else if (!std::strcmp(element, "tag")) {
m_rml_builder.reset();
- get_tag(m_relation_builder.get(), attrs);
+ get_tag(*m_relation_builder, attrs);
}
break;
case context::changeset:
@@ -476,12 +472,12 @@ namespace osmium {
m_context = context::discussion;
m_tl_builder.reset();
if (!m_changeset_discussion_builder) {
- m_changeset_discussion_builder = std::unique_ptr<osmium::builder::ChangesetDiscussionBuilder>(new osmium::builder::ChangesetDiscussionBuilder(m_buffer, m_changeset_builder.get()));
+ m_changeset_discussion_builder.reset(new osmium::builder::ChangesetDiscussionBuilder{*m_changeset_builder});
}
} else if (!std::strcmp(element, "tag")) {
m_context = context::in_object;
m_changeset_discussion_builder.reset();
- get_tag(m_changeset_builder.get(), attrs);
+ get_tag(*m_changeset_builder, attrs);
}
break;
case context::discussion:
@@ -632,8 +628,8 @@ namespace osmium {
XMLParser(future_string_queue_type& input_queue,
future_buffer_queue_type& output_queue,
std::promise<osmium::io::Header>& header_promise,
- osmium::osm_entity_bits::type read_types) :
- Parser(input_queue, output_queue, header_promise, read_types),
+ osmium::io::detail::reader_options options) :
+ Parser(input_queue, output_queue, header_promise, options),
m_context(context::root),
m_last_context(context::root),
m_in_delete_section(false),
@@ -657,7 +653,7 @@ namespace osmium {
ExpatXMLParser<XMLParser> parser(this);
while (!input_done()) {
- std::string data = get_input();
+ const std::string data{get_input()};
parser(data, input_done());
if (read_types() == osmium::osm_entity_bits::nothing && header_is_done()) {
break;
@@ -680,8 +676,8 @@ namespace osmium {
[](future_string_queue_type& input_queue,
future_buffer_queue_type& output_queue,
std::promise<osmium::io::Header>& header_promise,
- osmium::osm_entity_bits::type read_which_entities) {
- return std::unique_ptr<Parser>(new XMLParser(input_queue, output_queue, header_promise, read_which_entities));
+ osmium::io::detail::reader_options options) {
+ return std::unique_ptr<Parser>(new XMLParser{input_queue, output_queue, header_promise, options});
});
// dummy function to silence the unused variable warning from above
diff --git a/include/osmium/io/file_format.hpp b/include/osmium/io/file_format.hpp
index c447cb4..72b4abc 100644
--- a/include/osmium/io/file_format.hpp
+++ b/include/osmium/io/file_format.hpp
@@ -49,6 +49,11 @@ namespace osmium {
debug = 6
};
+ enum class read_meta {
+ no = 0,
+ yes = 1
+ };
+
// avoid g++ false positive
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wreturn-type"
diff --git a/include/osmium/io/header.hpp b/include/osmium/io/header.hpp
index 55ff5c6..abd85f8 100644
--- a/include/osmium/io/header.hpp
+++ b/include/osmium/io/header.hpp
@@ -44,17 +44,37 @@ namespace osmium {
namespace io {
/**
- * Meta information from the header of an OSM file.
- */
+ * Meta information from the header of an OSM file.
+ *
+ * The header can contain any number of bounding boxes, although
+ * usually there is only a single one (or none). PBF files only
+ * allow a single bounding box, but XML files can have multiple ones,
+ * although it is unusual and the semantics are unclear, so it is
+ * discouraged to create files with multiple bounding boxes.
+ *
+ * The header contains a flag telling you whether this file can
+ * contain multiple versions of the same object. This is true for
+ * history files and for change files, but not for normal OSM data
+ * files. Not all OSM file formats can distinguish between those
+ * cases, so the flag might be wrong.
+ *
+ * In addition the header can contain any number of key-value pairs
+ * with additional information. Most often this is used to set the
+ * "generator", the program that generated the file. Depending on
+ * the file format some of these key-value pairs are handled
+ * specially. The the Options parent class for details on how to
+ * set and get those key-value pairs.
+ */
class Header : public osmium::util::Options {
/// Bounding boxes
std::vector<osmium::Box> m_boxes;
/**
- * Are there possibly multiple versions of the same object in this stream of objects?
- * This is true for history files and for change files, but not for normal OSM files.
- */
+ * Are there possibly multiple versions of the same object in
+ * 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;
public:
@@ -65,49 +85,76 @@ namespace osmium {
Options(values) {
}
- Header(const Header&) = default;
- Header& operator=(const Header&) = default;
-
- Header(Header&&) = default;
- Header& operator=(Header&&) = default;
-
- ~Header() = default;
-
+ /**
+ * Get the bounding boxes defined in the header.
+ */
std::vector<osmium::Box>& boxes() noexcept {
return m_boxes;
}
+ /**
+ * Get the bounding boxes defined in the header.
+ */
const std::vector<osmium::Box>& boxes() const noexcept {
return m_boxes;
}
+ /**
+ * Set all the bounding boxes in the header.
+ */
Header& boxes(const std::vector<osmium::Box>& boxes) noexcept {
m_boxes = boxes;
return *this;
}
+ /**
+ * Get the first (or only if there is only one) bounding box.
+ *
+ * Returns an empty, invalid box if there is none.
+ */
osmium::Box box() const {
- return m_boxes.empty() ? osmium::Box() : m_boxes.front();
+ return m_boxes.empty() ? osmium::Box{} : m_boxes.front();
}
+ /**
+ * Join up all the bounding boxes in the header into one and return
+ * it. This method is what you probably want to use unless you want
+ * to handle the possibly multiple bounding boxes yourself.
+ *
+ * Returns an empty, invalid box if there is none.
+ */
osmium::Box joined_boxes() const {
osmium::Box box;
for (const auto& b : m_boxes) {
- box.extend(b.bottom_left());
- box.extend(b.top_right());
+ box.extend(b);
}
return box;
}
+ /**
+ * Add the given bounding box to the list of bounding boxes in the
+ * header.
+ *
+ * @returns The header itself to allow chaining.
+ */
Header& add_box(const osmium::Box& box) {
m_boxes.push_back(box);
return *this;
}
+ /**
+ * Can this file contain multiple versions of the same object?
+ */
bool has_multiple_object_versions() const noexcept {
return m_has_multiple_object_versions;
}
+ /**
+ * Set the flag that tells us whether this file can contain
+ * multiple versions of the same object?
+ *
+ * @returns The header itself to allow chaining.
+ */
Header& set_has_multiple_object_versions(bool value) noexcept {
m_has_multiple_object_versions = value;
return *this;
diff --git a/include/osmium/io/reader.hpp b/include/osmium/io/reader.hpp
index 12f97b8..89c8564 100644
--- a/include/osmium/io/reader.hpp
+++ b/include/osmium/io/reader.hpp
@@ -91,7 +91,6 @@ namespace osmium {
class Reader {
osmium::io::File m_file;
- osmium::osm_entity_bits::type m_read_which_entities;
enum class status {
okay = 0, // normal reading
@@ -118,15 +117,25 @@ namespace osmium {
size_t m_file_size;
+ osmium::io::detail::reader_options m_options;
+
+ void set_option(osmium::osm_entity_bits::type value) noexcept {
+ m_options.read_which_entities = value;
+ }
+
+ void set_option(osmium::io::read_meta value) noexcept {
+ m_options.read_metadata = value;
+ }
+
// This function will run in a separate thread.
static void parser_thread(const osmium::io::File& file,
detail::future_string_queue_type& input_queue,
detail::future_buffer_queue_type& osmdata_queue,
std::promise<osmium::io::Header>&& header_promise,
- osmium::osm_entity_bits::type read_which_entities) {
+ osmium::io::detail::reader_options options) {
std::promise<osmium::io::Header> promise = std::move(header_promise);
const auto creator = detail::ParserFactory::instance().get_creator_function(file);
- const auto parser = creator(input_queue, osmdata_queue, promise, read_which_entities);
+ const auto parser = creator(input_queue, osmdata_queue, promise, options);
parser->parse();
}
@@ -205,15 +214,28 @@ namespace osmium {
/**
* Create new Reader object.
*
- * @param file The file we want to open.
- * @param read_which_entities Which OSM entities (nodes, ways, relations, and/or changesets)
- * should be read from the input file. It can speed the read up
- * significantly if objects that are not needed anyway are not
- * parsed.
+ * @param file The file (contains name and format info) to open.
+ * @param args All further arguments are optional and can appear
+ * in any order:
+ *
+ * * osmium::osm_entities::bits: Which OSM entities (nodes, ways,
+ * relations, and/or changesets) should be read from the
+ * input file. It can speed the read up significantly if
+ * objects that are not needed anyway are not parsed.
+ *
+ * * osmium::io::read_meta: Read meta data or not. The default is
+ * osmium::io::read_meta::yes which means that meta data
+ * is read normally. If you set this to
+ * osmium::io::read_meta::no, meta data (like version, uid,
+ * etc.) is not read possibly speeding up the read. Not all
+ * file formats use this setting.
+ *
+ * @throws osmium::io_error If there was an error.
+ * @throws std::system_error If the file could not be opened.
*/
- explicit Reader(const osmium::io::File& file, osmium::osm_entity_bits::type read_which_entities = osmium::osm_entity_bits::all) :
+ template <typename... TArgs>
+ explicit Reader(const osmium::io::File& file, TArgs&&... args) :
m_file(file.check()),
- m_read_which_entities(read_which_entities),
m_status(status::okay),
m_childpid(0),
m_input_queue(detail::get_input_queue_size(), "raw_input"),
@@ -227,17 +249,24 @@ namespace osmium {
m_header(),
m_thread(),
m_file_size(m_decompressor->file_size()) {
+
+ (void)std::initializer_list<int>{
+ (set_option(args), 0)...
+ };
+
std::promise<osmium::io::Header> header_promise;
m_header_future = header_promise.get_future();
- m_thread = osmium::thread::thread_handler{parser_thread, std::ref(m_file), std::ref(m_input_queue), std::ref(m_osmdata_queue), std::move(header_promise), read_which_entities};
+ m_thread = osmium::thread::thread_handler{parser_thread, std::ref(m_file), std::ref(m_input_queue), std::ref(m_osmdata_queue), std::move(header_promise), m_options};
}
- explicit Reader(const std::string& filename, osmium::osm_entity_bits::type read_types = osmium::osm_entity_bits::all) :
- Reader(osmium::io::File(filename), read_types) {
+ template <typename... TArgs>
+ explicit Reader(const std::string& filename, TArgs&&... args) :
+ Reader(osmium::io::File(filename), std::forward<TArgs>(args)...) {
}
- explicit Reader(const char* filename, osmium::osm_entity_bits::type read_types = osmium::osm_entity_bits::all) :
- Reader(osmium::io::File(filename), read_types) {
+ template <typename... TArgs>
+ explicit Reader(const char* filename, TArgs&&... args) :
+ Reader(osmium::io::File(filename), std::forward<TArgs>(args)...) {
}
Reader(const Reader&) = delete;
@@ -304,7 +333,7 @@ namespace osmium {
try {
if (m_header_future.valid()) {
m_header = m_header_future.get();
- if (m_read_which_entities == osmium::osm_entity_bits::nothing) {
+ if (m_options.read_which_entities == osmium::osm_entity_bits::nothing) {
m_status = status::eof;
}
}
@@ -330,7 +359,7 @@ namespace osmium {
osmium::memory::Buffer buffer;
if (m_status != status::okay ||
- m_read_which_entities == osmium::osm_entity_bits::nothing) {
+ m_options.read_which_entities == osmium::osm_entity_bits::nothing) {
throw io_error("Can not read from reader when in status 'closed', 'eof', or 'error'");
}
diff --git a/include/osmium/memory/buffer.hpp b/include/osmium/memory/buffer.hpp
index 8c246db..bcf0bd0 100644
--- a/include/osmium/memory/buffer.hpp
+++ b/include/osmium/memory/buffer.hpp
@@ -113,6 +113,9 @@ namespace osmium {
size_t m_capacity;
size_t m_written;
size_t m_committed;
+#ifndef NDEBUG
+ uint8_t m_builder_count{0};
+#endif
auto_grow m_auto_grow {auto_grow::no};
std::function<void(Buffer&)> m_full;
@@ -216,13 +219,28 @@ namespace osmium {
~Buffer() = default;
+#ifndef NDEBUG
+ void increment_builder_count() noexcept {
+ ++m_builder_count;
+ }
+
+ void decrement_builder_count() noexcept {
+ assert(m_builder_count > 0);
+ --m_builder_count;
+ }
+
+ uint8_t builder_count() const noexcept {
+ return m_builder_count;
+ }
+#endif
+
/**
* Return a pointer to data inside the buffer.
*
* @pre The buffer must be valid.
*/
unsigned char* data() const noexcept {
- assert(m_data);
+ assert(m_data && "This must be a valid buffer");
return m_data;
}
@@ -258,7 +276,7 @@ namespace osmium {
* @pre The buffer must be valid.
*/
bool is_aligned() const noexcept {
- assert(m_data);
+ assert(m_data && "This must be a valid buffer");
return (m_written % align_bytes == 0) && (m_committed % align_bytes == 0);
}
@@ -283,7 +301,7 @@ namespace osmium {
* than the difference between committed() and capacity().
*/
OSMIUM_DEPRECATED void set_full_callback(std::function<void(Buffer&)> full) {
- assert(m_data);
+ assert(m_data && "This must be a valid buffer");
m_full = full;
}
@@ -292,7 +310,6 @@ namespace osmium {
* This works only with internally memory-managed buffers.
* If the given size is not larger than the current capacity,
* nothing is done.
- * Already written but not committed data is discarded.
*
* @pre The buffer must be valid.
*
@@ -305,7 +322,7 @@ namespace osmium {
* @throws std::bad_alloc if there isn't enough memory available.
*/
void grow(size_t size) {
- assert(m_data);
+ 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.");
}
@@ -325,15 +342,18 @@ namespace osmium {
/**
* Mark currently written bytes in the buffer as committed.
*
- * @pre The buffer must be valid and aligned properly (as indicated
+ * @pre The buffer must be valid.
+ * @pre The buffer must be aligned properly (as indicated
* by is_aligned().
+ * @pre No builder can be open on this buffer.
*
* @returns Number of committed bytes before this commit. Can be
* used as an offset into the buffer to get to the
* object being committed by this call.
*/
size_t commit() {
- assert(m_data);
+ 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;
@@ -345,9 +365,11 @@ namespace osmium {
* Roll back changes in buffer to last committed state.
*
* @pre The buffer must be valid.
+ * @pre No builder can be open on this buffer.
*/
void rollback() {
- assert(m_data);
+ assert(m_data && "This must be a valid buffer");
+ assert(m_builder_count == 0 && "Make sure there are no Builder objects still in scope");
m_written = m_committed;
}
@@ -356,9 +378,12 @@ namespace osmium {
*
* No-op on an invalid buffer.
*
+ * @pre No builder can be open on this buffer.
+ *
* @returns Number of bytes in the buffer before it was cleared.
*/
size_t clear() {
+ assert(m_builder_count == 0 && "Make sure there are no Builder objects still in scope");
const size_t committed = m_committed;
m_written = 0;
m_committed = 0;
@@ -377,7 +402,7 @@ namespace osmium {
*/
template <typename T>
T& get(const size_t offset) const {
- assert(m_data);
+ assert(m_data && "This must be a valid buffer");
return *reinterpret_cast<T*>(&m_data[offset]);
}
@@ -415,7 +440,7 @@ namespace osmium {
* no callback defined and the buffer isn't auto-growing.
*/
unsigned char* reserve_space(const size_t size) {
- assert(m_data);
+ assert(m_data && "This must be a valid buffer");
// try to flush the buffer empty first.
if (m_written + size > m_capacity && m_full) {
m_full(*this);
@@ -455,7 +480,7 @@ namespace osmium {
*/
template <typename T>
T& add_item(const T& item) {
- assert(m_data);
+ assert(m_data && "This must be a valid buffer");
unsigned char* target = reserve_space(item.padded_size());
std::copy_n(reinterpret_cast<const unsigned char*>(&item), item.padded_size(), target);
return *reinterpret_cast<T*>(target);
@@ -465,6 +490,7 @@ namespace osmium {
* Add committed contents of the given buffer to this buffer.
*
* @pre The buffer must be valid.
+ * @pre No builder can be open on this buffer.
*
* Note that you have to eventually call commit() to actually
* commit this data.
@@ -472,7 +498,9 @@ namespace osmium {
* @param buffer The source of the copy. Must be valid.
*/
void add_buffer(const Buffer& buffer) {
- assert(m_data && buffer);
+ assert(m_data && "This must be a valid buffer");
+ assert(buffer && "Buffer parameter must be a valid buffer");
+ assert(m_builder_count == 0 && "Make sure there are no Builder objects still in scope");
unsigned char* target = reserve_space(buffer.committed());
std::copy_n(buffer.data(), buffer.committed(), target);
}
@@ -482,11 +510,13 @@ namespace osmium {
* you can use std::back_inserter.
*
* @pre The buffer must be valid.
+ * @pre No builder can be open on this buffer.
*
* @param item The item to be added.
*/
void push_back(const osmium::memory::Item& item) {
- assert(m_data);
+ assert(m_data && "This must be a valid buffer");
+ assert(m_builder_count == 0 && "Make sure there are no Builder objects still in scope");
add_item(item);
commit();
}
@@ -537,7 +567,7 @@ namespace osmium {
*/
template <typename T>
t_iterator<T> begin() {
- assert(m_data);
+ assert(m_data && "This must be a valid buffer");
return t_iterator<T>(m_data, m_data + m_committed);
}
@@ -550,7 +580,7 @@ namespace osmium {
* @returns Iterator to first OSMEntity in the buffer.
*/
iterator begin() {
- assert(m_data);
+ assert(m_data && "This must be a valid buffer");
return iterator(m_data, m_data + m_committed);
}
@@ -565,7 +595,7 @@ namespace osmium {
*/
template <typename T>
t_iterator<T> get_iterator(size_t offset) {
- assert(m_data);
+ assert(m_data && "This must be a valid buffer");
return t_iterator<T>(m_data + offset, m_data + m_committed);
}
@@ -579,7 +609,7 @@ namespace osmium {
* buffer.
*/
iterator get_iterator(size_t offset) {
- assert(m_data);
+ assert(m_data && "This must be a valid buffer");
return iterator(m_data + offset, m_data + m_committed);
}
@@ -593,7 +623,7 @@ namespace osmium {
*/
template <typename T>
t_iterator<T> end() {
- assert(m_data);
+ assert(m_data && "This must be a valid buffer");
return t_iterator<T>(m_data + m_committed, m_data + m_committed);
}
@@ -606,40 +636,40 @@ namespace osmium {
* @returns End iterator.
*/
iterator end() {
- assert(m_data);
+ assert(m_data && "This must be a valid buffer");
return iterator(m_data + m_committed, m_data + m_committed);
}
template <typename T>
t_const_iterator<T> cbegin() const {
- assert(m_data);
+ assert(m_data && "This must be a valid buffer");
return t_const_iterator<T>(m_data, m_data + m_committed);
}
const_iterator cbegin() const {
- assert(m_data);
+ assert(m_data && "This must be a valid buffer");
return const_iterator(m_data, m_data + m_committed);
}
template <typename T>
t_const_iterator<T> get_iterator(size_t offset) const {
- assert(m_data);
+ 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 {
- assert(m_data);
+ assert(m_data && "This must be a valid buffer");
return const_iterator(m_data + offset, m_data + m_committed);
}
template <typename T>
t_const_iterator<T> cend() const {
- assert(m_data);
+ assert(m_data && "This must be a valid buffer");
return t_const_iterator<T>(m_data + m_committed, m_data + m_committed);
}
const_iterator cend() const {
- assert(m_data);
+ assert(m_data && "This must be a valid buffer");
return const_iterator(m_data + m_committed, m_data + m_committed);
}
@@ -698,7 +728,7 @@ namespace osmium {
*/
template <typename TCallbackClass>
void purge_removed(TCallbackClass* callback) {
- assert(m_data);
+ assert(m_data && "This must be a valid buffer");
if (begin() == end()) {
return;
}
diff --git a/include/osmium/memory/collection.hpp b/include/osmium/memory/collection.hpp
index 2a2c040..fb413ff 100644
--- a/include/osmium/memory/collection.hpp
+++ b/include/osmium/memory/collection.hpp
@@ -46,9 +46,9 @@ namespace osmium {
template <typename TMember>
class CollectionIterator {
- // This data_type is either 'unsigned char*' or 'const unsigned char*' depending
- // on whether TMember is const. This allows this class to be used as an iterator and
- // as a const_iterator.
+ // This data_type is either 'unsigned char*' or 'const unsigned
+ // char*' depending on whether TMember is const. This allows this
+ // class to be used as an iterator and as a const_iterator.
using data_type = typename std::conditional<std::is_const<TMember>::value, const unsigned char*, unsigned char*>::type;
data_type m_data;
@@ -92,11 +92,11 @@ namespace osmium {
return m_data;
}
- TMember& operator*() const {
+ TMember& operator*() const noexcept {
return *reinterpret_cast<TMember*>(m_data);
}
- TMember* operator->() const {
+ TMember* operator->() const noexcept {
return reinterpret_cast<TMember*>(m_data);
}
@@ -118,9 +118,12 @@ namespace osmium {
public:
- using iterator = CollectionIterator<TMember>;
- using const_iterator = CollectionIterator<const TMember>;
- using value_type = TMember;
+ using value_type = TMember;
+ using reference = TMember&;
+ using const_reference = const TMember&;
+ using iterator = CollectionIterator<TMember>;
+ using const_iterator = CollectionIterator<const TMember>;
+ using size_type = size_t;
static constexpr osmium::item_type itemtype = TCollectionItemType;
@@ -128,31 +131,45 @@ namespace osmium {
Item(sizeof(Collection<TMember, TCollectionItemType>), TCollectionItemType) {
}
- bool empty() const {
+ /**
+ * Does this collection contain any items?
+ *
+ * Complexity: Constant.
+ */
+ bool empty() const noexcept {
return sizeof(Collection<TMember, TCollectionItemType>) == byte_size();
}
- iterator begin() {
+ /**
+ * Returns the number of items in this collection.
+ *
+ * Complexity: Linear in the number of items.
+ */
+ size_type size() const noexcept {
+ return static_cast<size_type>(std::distance(begin(), end()));
+ }
+
+ iterator begin() noexcept {
return iterator(data() + sizeof(Collection<TMember, TCollectionItemType>));
}
- iterator end() {
+ iterator end() noexcept {
return iterator(data() + byte_size());
}
- const_iterator cbegin() const {
+ const_iterator cbegin() const noexcept {
return const_iterator(data() + sizeof(Collection<TMember, TCollectionItemType>));
}
- const_iterator cend() const {
+ const_iterator cend() const noexcept {
return const_iterator(data() + byte_size());
}
- const_iterator begin() const {
+ const_iterator begin() const noexcept {
return cbegin();
}
- const_iterator end() const {
+ const_iterator end() const noexcept {
return cend();
}
diff --git a/include/osmium/memory/item.hpp b/include/osmium/memory/item.hpp
index 2df33c7..b72ca4d 100644
--- a/include/osmium/memory/item.hpp
+++ b/include/osmium/memory/item.hpp
@@ -59,9 +59,9 @@ namespace osmium {
using item_size_type = uint32_t;
// align datastructures to this many bytes
- constexpr item_size_type align_bytes = 8;
+ constexpr const item_size_type align_bytes = 8;
- inline std::size_t padded_length(std::size_t length) noexcept {
+ 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/osm/area.hpp b/include/osmium/osm/area.hpp
index 490fbe9..d146e97 100644
--- a/include/osmium/osm/area.hpp
+++ b/include/osmium/osm/area.hpp
@@ -50,7 +50,8 @@ DEALINGS IN THE SOFTWARE.
namespace osmium {
namespace builder {
- template <class T> class ObjectBuilder;
+ template <typename TDerived, typename T>
+ class OSMObjectBuilder;
} // namespace builder
/**
@@ -117,7 +118,8 @@ namespace osmium {
*/
class Area : public OSMObject {
- friend class osmium::builder::ObjectBuilder<osmium::Area>;
+ template <typename TDerived, typename T>
+ friend class osmium::builder::OSMObjectBuilder;
Area() :
OSMObject(sizeof(Area), osmium::item_type::area) {
@@ -130,6 +132,8 @@ namespace osmium {
/**
* Was this area created from a way? (In contrast to areas
* created from a relation and their members.)
+ *
+ * Complexity: Constant.
*/
bool from_way() const noexcept {
return (positive_id() & 0x1) == 0;
@@ -137,6 +141,8 @@ namespace osmium {
/**
* Return the Id of the way or relation this area was created from.
+ *
+ * Complexity: Constant.
*/
osmium::object_id_type orig_id() const noexcept {
return osmium::area_id_to_object_id(id());
@@ -145,6 +151,8 @@ namespace osmium {
/**
* Count the number of outer and inner rings of this area.
*
+ * Complexity: Linear in the number of rings.
+ *
* @returns Pair (number outer rings, number inner rings)
*/
std::pair<size_t, size_t> num_rings() const {
diff --git a/include/osmium/osm/changeset.hpp b/include/osmium/osm/changeset.hpp
index 8a503ca..828a2c2 100644
--- a/include/osmium/osm/changeset.hpp
+++ b/include/osmium/osm/changeset.hpp
@@ -51,7 +51,7 @@ namespace osmium {
namespace builder {
class ChangesetDiscussionBuilder;
- template <typename T> class ObjectBuilder;
+ class ChangesetBuilder;
} // namespace builder
class Changeset;
@@ -129,20 +129,12 @@ namespace osmium {
class ChangesetDiscussion : public osmium::memory::Collection<ChangesetComment, osmium::item_type::changeset_discussion> {
- friend class osmium::builder::ObjectBuilder<osmium::Changeset>;
-
public:
- using size_type = size_t;
-
ChangesetDiscussion() :
osmium::memory::Collection<ChangesetComment, osmium::item_type::changeset_discussion>() {
}
- size_type size() const noexcept {
- return static_cast<size_type>(std::distance(begin(), end()));
- }
-
}; // class ChangesetDiscussion
static_assert(sizeof(ChangesetDiscussion) % osmium::memory::align_bytes == 0, "Class osmium::ChangesetDiscussion has wrong size to be aligned properly!");
@@ -156,7 +148,7 @@ namespace osmium {
*/
class Changeset : public osmium::OSMEntity {
- friend class osmium::builder::ObjectBuilder<osmium::Changeset>;
+ friend class osmium::builder::ChangesetBuilder;
osmium::Box m_bounds;
osmium::Timestamp m_created_at;
@@ -173,10 +165,14 @@ namespace osmium {
OSMEntity(sizeof(Changeset), osmium::item_type::changeset) {
}
- void set_user_size(string_size_type size) {
+ void set_user_size(string_size_type size) noexcept {
m_user_size = size;
}
+ string_size_type user_size() const noexcept {
+ return m_user_size;
+ }
+
unsigned char* subitems_position() {
return data() + osmium::memory::padded_length(sizeof(Changeset) + m_user_size);
}
diff --git a/include/osmium/osm/crc.hpp b/include/osmium/osm/crc.hpp
index 2abeac4..bf057fd 100644
--- a/include/osmium/osm/crc.hpp
+++ b/include/osmium/osm/crc.hpp
@@ -100,15 +100,15 @@ namespace osmium {
return m_crc;
}
- void update_bool(const bool value) {
+ void update_bool(const bool value) noexcept {
m_crc.process_byte(value);
}
- void update_int8(const uint8_t value) {
+ void update_int8(const uint8_t value) noexcept {
m_crc.process_byte(value);
}
- void update_int16(const uint16_t value) {
+ void update_int16(const uint16_t value) noexcept {
#if __BYTE_ORDER == __LITTLE_ENDIAN
m_crc.process_bytes(&value, sizeof(uint16_t));
#else
@@ -117,7 +117,7 @@ namespace osmium {
#endif
}
- void update_int32(const uint32_t value) {
+ void update_int32(const uint32_t value) noexcept {
#if __BYTE_ORDER == __LITTLE_ENDIAN
m_crc.process_bytes(&value, sizeof(uint32_t));
#else
@@ -126,7 +126,7 @@ namespace osmium {
#endif
}
- void update_int64(const uint64_t value) {
+ void update_int64(const uint64_t value) noexcept {
#if __BYTE_ORDER == __LITTLE_ENDIAN
m_crc.process_bytes(&value, sizeof(uint64_t));
#else
@@ -135,57 +135,57 @@ namespace osmium {
#endif
}
- void update_string(const char* str) {
+ void update_string(const char* str) noexcept {
while (*str) {
m_crc.process_byte(*str++);
}
}
- void update(const Timestamp& timestamp) {
+ void update(const Timestamp& timestamp) noexcept {
update_int32(uint32_t(timestamp));
}
- void update(const osmium::Location& location) {
+ void update(const osmium::Location& location) noexcept {
update_int32(location.x());
update_int32(location.y());
}
- void update(const osmium::Box& box) {
+ void update(const osmium::Box& box) noexcept {
update(box.bottom_left());
update(box.top_right());
}
- void update(const NodeRef& node_ref) {
+ void update(const NodeRef& node_ref) noexcept {
update_int64(node_ref.ref());
update(node_ref.location());
}
- void update(const NodeRefList& node_refs) {
+ void update(const NodeRefList& node_refs) noexcept {
for (const NodeRef& node_ref : node_refs) {
update(node_ref);
}
}
- void update(const TagList& tags) {
+ void update(const TagList& tags) noexcept {
for (const Tag& tag : tags) {
update_string(tag.key());
update_string(tag.value());
}
}
- void update(const osmium::RelationMember& member) {
+ void update(const osmium::RelationMember& member) noexcept {
update_int64(member.ref());
update_int16(uint16_t(member.type()));
update_string(member.role());
}
- void update(const osmium::RelationMemberList& members) {
+ void update(const osmium::RelationMemberList& members) noexcept {
for (const RelationMember& member : members) {
update(member);
}
}
- void update(const osmium::OSMObject& object) {
+ void update(const osmium::OSMObject& object) noexcept {
update_int64(object.id());
update_bool(object.visible());
update_int32(object.version());
@@ -195,22 +195,22 @@ namespace osmium {
update(object.tags());
}
- void update(const osmium::Node& node) {
+ void update(const osmium::Node& node) noexcept {
update(static_cast<const osmium::OSMObject&>(node));
update(node.location());
}
- void update(const osmium::Way& way) {
+ void update(const osmium::Way& way) noexcept {
update(static_cast<const osmium::OSMObject&>(way));
update(way.nodes());
}
- void update(const osmium::Relation& relation) {
+ void update(const osmium::Relation& relation) noexcept {
update(static_cast<const osmium::OSMObject&>(relation));
update(relation.members());
}
- void update(const osmium::Area& area) {
+ void update(const osmium::Area& area) noexcept {
update(static_cast<const osmium::OSMObject&>(area));
for (const auto& subitem : area) {
if (subitem.type() == osmium::item_type::outer_ring ||
@@ -220,7 +220,7 @@ namespace osmium {
}
}
- void update(const osmium::ChangesetDiscussion& discussion) {
+ void update(const osmium::ChangesetDiscussion& discussion) noexcept {
for (const auto& comment : discussion) {
update(comment.date());
update_int32(comment.uid());
@@ -229,7 +229,7 @@ namespace osmium {
}
}
- void update(const osmium::Changeset& changeset) {
+ void update(const osmium::Changeset& changeset) noexcept {
update_int64(changeset.id());
update(changeset.created_at());
update(changeset.closed_at());
diff --git a/include/osmium/osm/entity_bits.hpp b/include/osmium/osm/entity_bits.hpp
index b8e9ddb..05afe3b 100644
--- a/include/osmium/osm/entity_bits.hpp
+++ b/include/osmium/osm/entity_bits.hpp
@@ -60,7 +60,9 @@ namespace osmium {
* assert(! (entities & osmium::osm_entity_bits::changeset));
* @endcode
*/
- enum type : unsigned char {
+ enum type : unsigned char { // this should have been an enum class
+ // but now we can't change it any more
+ // without breaking lots of code
nothing = 0x00,
node = 0x01,
@@ -75,21 +77,21 @@ namespace osmium {
}; // enum type
- inline type operator|(const type lhs, const type rhs) noexcept {
- return static_cast<type>(static_cast<int>(lhs) | static_cast<int> (rhs));
+ inline constexpr type operator|(const type lhs, const type rhs) noexcept {
+ return static_cast<type>(static_cast<int>(lhs) | static_cast<int>(rhs));
}
- inline type& operator|=(type& lhs, const type rhs) noexcept {
- lhs = lhs | rhs;
- return lhs;
+ inline constexpr type operator&(const type lhs, const type rhs) noexcept {
+ return static_cast<type>(static_cast<int>(lhs) & static_cast<int>(rhs));
}
- inline type operator&(const type lhs, const type rhs) noexcept {
- return static_cast<type>(static_cast<int>(lhs) & static_cast<int> (rhs));
+ inline constexpr type operator~(const type value) noexcept {
+ return all & static_cast<type>(~static_cast<int>(value));
}
- inline type operator~(const type value) noexcept {
- return static_cast<type>(~static_cast<int>(value));
+ inline type& operator|=(type& lhs, const type rhs) noexcept {
+ lhs = lhs | rhs;
+ return lhs;
}
inline type operator&=(type& lhs, const type rhs) noexcept {
@@ -104,7 +106,7 @@ namespace osmium {
* changeset.
*/
inline type from_item_type(osmium::item_type item_type) noexcept {
- auto ut = static_cast<std::underlying_type<osmium::item_type>::type>(item_type);
+ const auto ut = static_cast<std::underlying_type<osmium::item_type>::type>(item_type);
assert(ut <= 0x05);
if (ut == 0) {
return nothing;
diff --git a/include/osmium/osm/location.hpp b/include/osmium/osm/location.hpp
index c5da620..d208717 100644
--- a/include/osmium/osm/location.hpp
+++ b/include/osmium/osm/location.hpp
@@ -86,23 +86,31 @@ namespace osmium {
++str;
}
- // there has to be at least one digit
- if (*str >= '0' && *str <= '9') {
- result = *str - '0';
- ++str;
- } else {
- goto error;
- }
+ if (*str != '.') {
+ // there has to be at least one digit
+ if (*str >= '0' && *str <= '9') {
+ result = *str - '0';
+ ++str;
+ } else {
+ goto error;
+ }
- // optional additional digits before decimal point
- while (*str >= '0' && *str <= '9' && max_digits > 0) {
- result = result * 10 + (*str - '0');
- ++str;
- --max_digits;
- }
+ // optional additional digits before decimal point
+ while (*str >= '0' && *str <= '9' && max_digits > 0) {
+ result = result * 10 + (*str - '0');
+ ++str;
+ --max_digits;
+ }
- if (max_digits == 0) {
- goto error;
+ if (max_digits == 0) {
+ goto error;
+ }
+ } else {
+ // need at least one digit after decimal dot if there was no
+ // digit before decimal dot
+ if (*(str + 1) < '0' || *(str + 1) > '9') {
+ goto error;
+ }
}
// optional decimal point
@@ -163,18 +171,20 @@ namespace osmium {
}
if (scale < 0) {
- result = 0;
+ for (; scale < 0 && result > 0; ++scale) {
+ result /= 10;
+ }
} else {
for (; scale > 0; --scale) {
result *= 10;
}
+ }
- result = (result + 5) / 10 * sign;
+ result = (result + 5) / 10 * sign;
- if (result > std::numeric_limits<int32_t>::max() ||
- result < std::numeric_limits<int32_t>::min()) {
- goto error;
- }
+ if (result > std::numeric_limits<int32_t>::max() ||
+ result < std::numeric_limits<int32_t>::min()) {
+ goto error;
}
*data = str;
diff --git a/include/osmium/osm/node.hpp b/include/osmium/osm/node.hpp
index 677ffc7..f3df5e9 100644
--- a/include/osmium/osm/node.hpp
+++ b/include/osmium/osm/node.hpp
@@ -41,12 +41,14 @@ DEALINGS IN THE SOFTWARE.
namespace osmium {
namespace builder {
- template <typename T> class ObjectBuilder;
+ template <typename TDerived, typename T>
+ class OSMObjectBuilder;
} // namespace builder
class Node : public OSMObject {
- friend class osmium::builder::ObjectBuilder<osmium::Node>;
+ template <typename TDerived, typename T>
+ friend class osmium::builder::OSMObjectBuilder;
osmium::Location m_location;
@@ -62,7 +64,7 @@ namespace osmium {
return m_location;
}
- Node& set_location(const osmium::Location& location) {
+ Node& set_location(const osmium::Location& location) noexcept {
m_location = location;
return *this;
}
diff --git a/include/osmium/osm/node_ref_list.hpp b/include/osmium/osm/node_ref_list.hpp
index 6cfdf22..f430b63 100644
--- a/include/osmium/osm/node_ref_list.hpp
+++ b/include/osmium/osm/node_ref_list.hpp
@@ -52,12 +52,23 @@ namespace osmium {
public:
+ using value_type = NodeRef;
+ using reference = NodeRef&;
+ using const_reference = const NodeRef&;
+ using iterator = NodeRef*;
+ using const_iterator = const NodeRef*;
+ using const_reverse_iterator = std::reverse_iterator<const NodeRef*>;
+ using difference_type = std::ptrdiff_t;
+ using size_type = std::size_t;
+
explicit NodeRefList(osmium::item_type itemtype) noexcept :
osmium::memory::Item(sizeof(NodeRefList), itemtype) {
}
/**
* Checks whether the collection is empty.
+ *
+ * Complexity: Constant.
*/
bool empty() const noexcept {
return sizeof(NodeRefList) == byte_size();
@@ -65,8 +76,10 @@ namespace osmium {
/**
* Returns the number of NodeRefs in the collection.
+ *
+ * Complexity: Constant.
*/
- size_t size() const noexcept {
+ size_type size() const noexcept {
const auto size_node_refs = byte_size() - sizeof(NodeRefList);
assert(size_node_refs % sizeof(NodeRef) == 0);
return size_node_refs / sizeof(NodeRef);
@@ -75,11 +88,13 @@ namespace osmium {
/**
* Access specified element.
*
+ * Complexity: Constant.
+ *
* @pre @code n < size() @endcode
*
* @param n Get the n-th element of the collection.
*/
- const NodeRef& operator[](size_t n) const noexcept {
+ const NodeRef& operator[](size_type n) const noexcept {
assert(n < size());
const NodeRef* node_ref = &*(cbegin());
return node_ref[n];
@@ -88,6 +103,8 @@ namespace osmium {
/**
* Access the first element.
*
+ * Complexity: Constant.
+ *
* @pre @code !empty() @endcode
*/
const NodeRef& front() const noexcept {
@@ -98,6 +115,8 @@ namespace osmium {
/**
* Access the last element.
*
+ * Complexity: Constant.
+ *
* @pre @code !empty() @endcode
*/
const NodeRef& back() const noexcept {
@@ -109,6 +128,8 @@ namespace osmium {
* Checks whether the first and last node in the collection have the
* same ID. The locations are not checked.
*
+ * Complexity: Constant.
+ *
* @pre @code !empty() @endcode
*/
bool is_closed() const noexcept {
@@ -119,6 +140,8 @@ namespace osmium {
* Checks whether the first and last node in the collection have the
* same ID. The locations are not checked.
*
+ * Complexity: Constant.
+ *
* @pre @code !empty() @endcode
*/
bool ends_have_same_id() const noexcept {
@@ -129,6 +152,8 @@ namespace osmium {
* Checks whether the first and last node in the collection have the
* same location. The IDs are not checked.
*
+ * Complexity: Constant.
+ *
* @pre @code !empty() @endcode
* @pre @code front().location() && back().location() @endcode
*/
@@ -137,10 +162,6 @@ namespace osmium {
return front().location() == back().location();
}
- using iterator = NodeRef*;
- using const_iterator = const NodeRef*;
- using const_reverse_iterator = std::reverse_iterator<const NodeRef*>;
-
/// Returns an iterator to the beginning.
iterator begin() noexcept {
return iterator(data() + sizeof(NodeRefList));
diff --git a/include/osmium/osm/object.hpp b/include/osmium/osm/object.hpp
index caa6fbc..01fe249 100644
--- a/include/osmium/osm/object.hpp
+++ b/include/osmium/osm/object.hpp
@@ -52,11 +52,19 @@ DEALINGS IN THE SOFTWARE.
namespace osmium {
+ namespace builder {
+ template <typename TDerived, typename T>
+ class OSMObjectBuilder;
+ } // namespace builder
+
/**
* OSMObject (Node, Way, Relation, or Area).
*/
class OSMObject : public osmium::OSMEntity {
+ template <typename TDerived, typename T>
+ friend class osmium::builder::OSMObjectBuilder;
+
object_id_type m_id;
bool m_deleted : 1;
object_version_type m_version : 31;
diff --git a/include/osmium/osm/relation.hpp b/include/osmium/osm/relation.hpp
index 2aa9caa..8c09680 100644
--- a/include/osmium/osm/relation.hpp
+++ b/include/osmium/osm/relation.hpp
@@ -43,11 +43,14 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/osm/item_type.hpp>
#include <osmium/osm/object.hpp>
#include <osmium/osm/types.hpp>
+#include <osmium/util/compatibility.hpp>
namespace osmium {
namespace builder {
- template <typename> class ObjectBuilder;
+ template <typename TDerived, typename T>
+ class OSMObjectBuilder;
+
class RelationMemberListBuilder;
} // namespace builder
@@ -109,7 +112,8 @@ namespace osmium {
return m_ref;
}
- RelationMember& ref(object_id_type ref) noexcept {
+ /// @deprecated Use set_ref() instead.
+ OSMIUM_DEPRECATED RelationMember& ref(object_id_type ref) noexcept {
m_ref = ref;
return *this;
}
@@ -149,23 +153,18 @@ namespace osmium {
public:
- using size_type = size_t;
-
RelationMemberList() :
osmium::memory::Collection<RelationMember, osmium::item_type::relation_member_list>() {
}
- size_type size() const noexcept {
- return static_cast<size_type>(std::distance(begin(), end()));
- }
-
}; // class RelationMemberList
static_assert(sizeof(RelationMemberList) % osmium::memory::align_bytes == 0, "Class osmium::RelationMemberList has wrong size to be aligned properly!");
class Relation : public OSMObject {
- friend class osmium::builder::ObjectBuilder<osmium::Relation>;
+ template <typename TDerived, typename T>
+ friend class osmium::builder::OSMObjectBuilder;
Relation() noexcept :
OSMObject(sizeof(Relation), osmium::item_type::relation) {
diff --git a/include/osmium/osm/tag.hpp b/include/osmium/osm/tag.hpp
index cd2a913..e2537ce 100644
--- a/include/osmium/osm/tag.hpp
+++ b/include/osmium/osm/tag.hpp
@@ -86,12 +86,14 @@ namespace osmium {
}; // class Tag
- inline bool operator==(const Tag& a, const Tag& b) {
- return !std::strcmp(a.key(), b.key()) && !std::strcmp(a.value(), b.value());
+ inline bool operator==(const Tag& lhs, const Tag& rhs) {
+ return !std::strcmp(lhs.key(), rhs.key()) &&
+ !std::strcmp(lhs.value(), rhs.value());
}
- inline bool operator<(const Tag& a, const Tag& b) {
- return (!std::strcmp(a.key(), b.key()) && (std::strcmp(a.value(), b.value()) < 0)) || (std::strcmp(a.key(), b.key()) < 0);
+ inline bool operator<(const Tag& lhs, const Tag& rhs) {
+ const auto c = std::strcmp(lhs.key(), rhs.key());
+ return (c == 0 ? std::strcmp(lhs.value(), rhs.value()) : c) < 0;
}
/**
@@ -112,20 +114,11 @@ namespace osmium {
public:
- using size_type = size_t;
-
TagList() :
osmium::memory::Collection<Tag, osmium::item_type::tag_list>() {
}
/**
- * Returns the number of tags in this tag list.
- */
- size_type size() const noexcept {
- return static_cast<size_type>(std::distance(begin(), end()));
- }
-
- /**
* Get tag value for the given tag key. If the key is not set, returns
* the default_value.
*
diff --git a/include/osmium/osm/way.hpp b/include/osmium/osm/way.hpp
index f6713fe..e4415ef 100644
--- a/include/osmium/osm/way.hpp
+++ b/include/osmium/osm/way.hpp
@@ -44,7 +44,8 @@ DEALINGS IN THE SOFTWARE.
namespace osmium {
namespace builder {
- template <typename T> class ObjectBuilder;
+ template <typename TDerived, typename T>
+ class OSMObjectBuilder;
} // namespace builder
/**
@@ -66,7 +67,8 @@ namespace osmium {
class Way : public OSMObject {
- friend class osmium::builder::ObjectBuilder<osmium::Way>;
+ template <typename TDerived, typename T>
+ friend class osmium::builder::OSMObjectBuilder;
Way() noexcept :
OSMObject(sizeof(Way), osmium::item_type::way) {
diff --git a/include/osmium/relations/collector.hpp b/include/osmium/relations/collector.hpp
index b8455b4..53f6de9 100644
--- a/include/osmium/relations/collector.hpp
+++ b/include/osmium/relations/collector.hpp
@@ -40,6 +40,7 @@ DEALINGS IN THE SOFTWARE.
#include <functional>
#include <iomanip>
#include <iostream>
+#include <utility>
#include <vector>
#include <osmium/osm/item_type.hpp>
@@ -353,7 +354,7 @@ namespace osmium {
member_meta(member.type()).emplace_back(member.ref(), m_relations.size(), n);
relation_meta.increment_need_members();
} else {
- member.ref(0); // set member id to zero to indicate we are not interested
+ member.set_ref(0); // set member id to zero to indicate we are not interested
}
++n;
}
@@ -494,12 +495,65 @@ namespace osmium {
return m_members_buffer;
}
+ /**
+ * Is the given member available in the members buffer?
+ *
+ * If you also need the offset of the object, use
+ * get_availability_and_offset() instead, it is more efficient
+ * that way.
+ *
+ * @param type Item type
+ * @param id Object Id
+ * @returns True if the object is available, false otherwise.
+ */
+ bool is_available(osmium::item_type type, osmium::object_id_type id) {
+ const auto range = find_member_meta(type, id);
+ assert(!range.empty());
+ return range.begin()->is_available();
+ }
+
+ /**
+ * Get offset of a member in the members buffer.
+ *
+ * @pre The member must be available. If you are not sure, call
+ * get_availability_and_offset() instead.
+ * @param type Item type
+ * @param id Object Id
+ * @returns The offset of the object in the members buffer.
+ */
size_t get_offset(osmium::item_type type, osmium::object_id_type id) {
const auto range = find_member_meta(type, id);
assert(!range.empty());
+ assert(range.begin()->is_available());
return range.begin()->buffer_offset();
}
+ /**
+ * Checks whether a member is available in the members buffer
+ * and returns its offset.
+ *
+ * If the member is not available, the boolean returned as the
+ * first element in the pair is false. In that case the offset
+ * in the second element is undefined.
+ *
+ * If the member is available, the boolean returned as the first
+ * element in the pair is true and the second element of the
+ * pair contains the offset into the members buffer.
+ *
+ * @param type Item type
+ * @param id Object Id
+ * @returns Pair of bool (showing availability) and the offset.
+ */
+ std::pair<bool, size_t> get_availability_and_offset(osmium::item_type type, osmium::object_id_type id) {
+ const auto range = find_member_meta(type, id);
+ assert(!range.empty());
+ if (range.begin()->is_available()) {
+ return std::make_pair(true, range.begin()->buffer_offset());
+ } else {
+ return std::make_pair(false, 0);
+ }
+ }
+
template <typename TIter>
void read_relations(TIter begin, TIter end) {
HandlerPass1 handler(*static_cast<TCollector*>(this));
@@ -525,7 +579,7 @@ namespace osmium {
/**
* Decide whether to purge removed members and then do it.
*
- * Currently the purging is done every thousand calls.
+ * Currently the purging is done every 10000 calls.
* This could probably be improved upon.
*/
void possibly_purge_removed_members() {
diff --git a/include/osmium/relations/detail/member_meta.hpp b/include/osmium/relations/detail/member_meta.hpp
index b28dca1..7624a60 100644
--- a/include/osmium/relations/detail/member_meta.hpp
+++ b/include/osmium/relations/detail/member_meta.hpp
@@ -35,6 +35,7 @@ DEALINGS IN THE SOFTWARE.
#include <cstddef>
#include <iosfwd>
+#include <limits>
#include <osmium/osm/types.hpp>
@@ -71,24 +72,44 @@ namespace osmium {
/**
* Offset in the buffer where the object is stored.
+ *
+ * The default value is one that will never be valid, so it is
+ * easier to catch problems.
*/
- size_t m_buffer_offset { 0 };
+ size_t m_buffer_offset = std::numeric_limits<size_t>::max();
+ /**
+ * Has this member been found in the input data.
+ */
+ bool m_available = false;
+
+ /**
+ * Marks this member as removed. It can not be used any more.
+ */
bool m_removed = false;
public:
/**
- * Create new MemberMeta. The variant with zeros for relation_pos and
- * member_pos is used to create dummy MemberMeta that can be compared
- * to the MemberMeta in the vectors using the equal_range algorithm.
+ * Create new MemberMeta.
*/
- explicit MemberMeta(osmium::object_id_type member_id, size_t relation_pos=0, size_t member_pos=0) noexcept :
+ explicit MemberMeta(osmium::object_id_type member_id, size_t relation_pos, size_t member_pos) noexcept :
m_member_id(member_id),
m_relation_pos(relation_pos),
m_member_pos(member_pos) {
}
+ /**
+ * Create new MemberMeta. This constructor is used to create
+ * dummy MemberMeta objects that can be compared to the
+ * MemberMetas in a vector using the equal_range algorithm.
+ */
+ explicit MemberMeta(osmium::object_id_type member_id) noexcept :
+ m_member_id(member_id),
+ m_relation_pos(0),
+ m_member_pos(0) {
+ }
+
osmium::object_id_type member_id() const noexcept {
return m_member_id;
}
@@ -107,6 +128,11 @@ namespace osmium {
void set_buffer_offset(size_t offset) noexcept {
m_buffer_offset = offset;
+ m_available = true;
+ }
+
+ bool is_available() const noexcept {
+ return m_available;
}
bool removed() const noexcept {
@@ -124,8 +150,8 @@ namespace osmium {
* Used to sort a vector of MemberMeta objects and to later find
* them using binary search.
*/
- inline bool operator<(const MemberMeta& a, const MemberMeta& b) noexcept {
- return a.member_id() < b.member_id();
+ inline bool operator<(const MemberMeta& lhs, const MemberMeta& rhs) noexcept {
+ return lhs.member_id() < rhs.member_id();
}
template <typename TChar, typename TTraits>
diff --git a/include/osmium/thread/queue.hpp b/include/osmium/thread/queue.hpp
index 6f4f7b1..5ae9108 100644
--- a/include/osmium/thread/queue.hpp
+++ b/include/osmium/thread/queue.hpp
@@ -51,7 +51,7 @@ namespace osmium {
namespace thread {
- static const std::chrono::milliseconds full_queue_sleep_duration { 10 }; // XXX
+ static const std::chrono::milliseconds max_wait{10};
/**
* A thread-safe queue.
@@ -70,9 +70,12 @@ namespace osmium {
std::queue<T> m_queue;
- /// Used to signal readers when data is available in the queue.
+ /// Used to signal consumers when data is available in the queue.
std::condition_variable m_data_available;
+ /// Used to signal producers when queue is not full.
+ std::condition_variable m_space_available;
+
#ifdef OSMIUM_DEBUG_QUEUE_SIZE
/// The largest size the queue has been so far.
size_t m_largest_size;
@@ -109,7 +112,8 @@ namespace osmium {
m_name(name),
m_mutex(),
m_queue(),
- m_data_available()
+ m_data_available(),
+ m_space_available()
#ifdef OSMIUM_DEBUG_QUEUE_SIZE
,
m_largest_size(0),
@@ -123,13 +127,20 @@ namespace osmium {
~Queue() {
#ifdef OSMIUM_DEBUG_QUEUE_SIZE
- std::cerr << "queue '" << m_name << "' with max_size=" << m_max_size << " had largest size " << m_largest_size << " and was full " << m_full_counter << " times in " << m_push_counter << " push() calls and was empty " << m_empty_counter << " times in " << m_pop_counter << " pop() calls\n";
+ std::cerr << "queue '" << m_name
+ << "' with max_size=" << m_max_size
+ << " had largest size " << m_largest_size
+ << " and was full " << m_full_counter
+ << " times in " << m_push_counter
+ << " push() calls and was empty " << m_empty_counter
+ << " times in " << m_pop_counter
+ << " pop() calls\n";
#endif
}
/**
- * Push an element onto the queue. If the queue has a max size, this
- * call will block if the queue is full.
+ * Push an element onto the queue. If the queue has a max size,
+ * this call will block if the queue is full.
*/
void push(T value) {
#ifdef OSMIUM_DEBUG_QUEUE_SIZE
@@ -137,13 +148,16 @@ namespace osmium {
#endif
if (m_max_size) {
while (size() >= m_max_size) {
- std::this_thread::sleep_for(full_queue_sleep_duration);
+ std::unique_lock<std::mutex> lock{m_mutex};
+ m_space_available.wait_for(lock, max_wait, [this] {
+ return m_queue.size() < m_max_size;
+ });
#ifdef OSMIUM_DEBUG_QUEUE_SIZE
++m_full_counter;
#endif
}
}
- std::lock_guard<std::mutex> lock(m_mutex);
+ std::lock_guard<std::mutex> lock{m_mutex};
m_queue.push(std::move(value));
#ifdef OSMIUM_DEBUG_QUEUE_SIZE
if (m_largest_size < m_queue.size()) {
@@ -157,7 +171,7 @@ namespace osmium {
#ifdef OSMIUM_DEBUG_QUEUE_SIZE
++m_pop_counter;
#endif
- std::unique_lock<std::mutex> lock(m_mutex);
+ std::unique_lock<std::mutex> lock{m_mutex};
#ifdef OSMIUM_DEBUG_QUEUE_SIZE
if (m_queue.empty()) {
++m_empty_counter;
@@ -169,6 +183,10 @@ namespace osmium {
if (!m_queue.empty()) {
value = std::move(m_queue.front());
m_queue.pop();
+ lock.unlock();
+ if (m_max_size) {
+ m_space_available.notify_one();
+ }
}
}
@@ -176,25 +194,30 @@ namespace osmium {
#ifdef OSMIUM_DEBUG_QUEUE_SIZE
++m_pop_counter;
#endif
- std::lock_guard<std::mutex> lock(m_mutex);
- if (m_queue.empty()) {
+ {
+ std::lock_guard<std::mutex> lock{m_mutex};
+ if (m_queue.empty()) {
#ifdef OSMIUM_DEBUG_QUEUE_SIZE
- ++m_empty_counter;
+ ++m_empty_counter;
#endif
- return false;
+ return false;
+ }
+ value = std::move(m_queue.front());
+ m_queue.pop();
+ }
+ if (m_max_size) {
+ m_space_available.notify_one();
}
- value = std::move(m_queue.front());
- m_queue.pop();
return true;
}
bool empty() const {
- std::lock_guard<std::mutex> lock(m_mutex);
+ std::lock_guard<std::mutex> lock{m_mutex};
return m_queue.empty();
}
size_t size() const {
- std::lock_guard<std::mutex> lock(m_mutex);
+ std::lock_guard<std::mutex> lock{m_mutex};
return m_queue.size();
}
diff --git a/include/osmium/util/progress_bar.hpp b/include/osmium/util/progress_bar.hpp
index 814aa2c..0e528fc 100644
--- a/include/osmium/util/progress_bar.hpp
+++ b/include/osmium/util/progress_bar.hpp
@@ -172,6 +172,18 @@ namespace osmium {
}
}
+ /**
+ * Removes the progress bar. Call this before doing any other output.
+ * The next time update() is called, the progress bar will be visible
+ * again.
+ */
+ void remove() {
+ if (m_enable) {
+ std::cerr << spc() << " \r";
+ m_prev_percent = 100 + 1;
+ }
+ }
+
}; // class ProgressBar
} // namespace osmium
diff --git a/include/osmium/version.hpp b/include/osmium/version.hpp
index 6f3b0a3..09c5762 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 9
+#define LIBOSMIUM_VERSION_MINOR 10
#define LIBOSMIUM_VERSION_PATCH 0
-#define LIBOSMIUM_VERSION_STRING "2.9.0"
+#define LIBOSMIUM_VERSION_STRING "2.10.0"
#endif // OSMIUM_VERSION_HPP
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 6230cde..051574e 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -112,12 +112,6 @@ if(NOT Threads_FOUND)
set(Threads_FOUND FALSE)
endif()
-if(GEOS_FOUND AND PROJ_FOUND)
- set(GEOS_AND_PROJ_FOUND TRUE)
-else()
- set(GEOS_AND_PROJ_FOUND FALSE)
-endif()
-
#-----------------------------------------------------------------------------
#
@@ -127,45 +121,45 @@ endif()
add_unit_test(area test_area_id)
add_unit_test(area test_node_ref_segment)
-add_unit_test(basic test_area)
-add_unit_test(basic test_box)
-add_unit_test(basic test_changeset)
-add_unit_test(basic test_crc)
-add_unit_test(basic test_entity_bits)
-add_unit_test(basic test_location)
-add_unit_test(basic test_node)
-add_unit_test(basic test_node_ref)
-add_unit_test(basic test_object_comparisons)
-add_unit_test(basic test_relation)
-add_unit_test(basic test_timestamp)
-add_unit_test(basic test_types_from_string)
-add_unit_test(basic test_way)
-
-add_unit_test(buffer test_buffer_basics)
-add_unit_test(buffer test_buffer_node)
-add_unit_test(buffer test_buffer_purge)
+add_unit_test(osm test_area)
+add_unit_test(osm test_box)
+add_unit_test(osm test_changeset)
+add_unit_test(osm test_crc)
+add_unit_test(osm test_entity_bits)
+add_unit_test(osm test_location)
+add_unit_test(osm test_node)
+add_unit_test(osm test_node_ref)
+add_unit_test(osm test_object_comparisons)
+add_unit_test(osm test_relation)
+add_unit_test(osm test_timestamp)
+add_unit_test(osm test_types_from_string)
+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(builder test_attr)
-
-add_unit_test(geom test_factory_with_projection
- ENABLE_IF ${GEOS_AND_PROJ_FOUND}
- LIBS ${GEOS_LIBRARY} ${PROJ_LIBRARY})
+add_unit_test(builder test_object_builder)
add_unit_test(geom test_crs ENABLE_IF ${PROJ_FOUND} LIBS ${PROJ_LIBRARY})
add_unit_test(geom test_exception)
+add_unit_test(geom test_factory_with_projection ENABLE_IF ${PROJ_FOUND} LIBS ${PROJ_LIBRARY})
add_unit_test(geom test_geojson)
add_unit_test(geom test_geos ENABLE_IF ${GEOS_FOUND} LIBS ${GEOS_LIBRARY})
-add_unit_test(geom test_geos_wkb ENABLE_IF ${GEOS_FOUND} LIBS ${GEOS_LIBRARY})
add_unit_test(geom test_mercator)
add_unit_test(geom test_ogr ENABLE_IF ${GDAL_FOUND} LIBS ${GDAL_LIBRARY})
+add_unit_test(geom test_ogr_wkb ENABLE_IF ${GDAL_FOUND} LIBS ${GDAL_LIBRARY})
add_unit_test(geom test_projection ENABLE_IF ${PROJ_FOUND} LIBS ${PROJ_LIBRARY})
-add_unit_test(geom test_tile ENABLE_IF ${GEOS_FOUND})
+add_unit_test(geom test_tile)
add_unit_test(geom test_wkb)
add_unit_test(geom test_wkt)
+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)
+add_unit_test(io test_compression_factory)
add_unit_test(io test_bzip2 ENABLE_IF ${BZIP2_FOUND} LIBS ${BZIP2_LIBRARIES})
add_unit_test(io test_file_formats)
add_unit_test(io test_reader LIBS "${OSMIUM_XML_LIBRARIES};${OSMIUM_PBF_LIBRARIES}")
diff --git a/test/data-tests/testdata-xml.cpp b/test/data-tests/testdata-xml.cpp
index 0d2739a..eb984f8 100644
--- a/test/data-tests/testdata-xml.cpp
+++ b/test/data-tests/testdata-xml.cpp
@@ -83,7 +83,7 @@ header_buffer_type parse_xml(std::string input) {
osmium::io::detail::add_to_queue(input_queue, std::move(input));
osmium::io::detail::add_to_queue(input_queue, std::string{});
- osmium::io::detail::XMLParser parser{input_queue, output_queue, header_promise, osmium::osm_entity_bits::all};
+ osmium::io::detail::XMLParser parser{input_queue, output_queue, header_promise, osmium::io::detail::reader_options{}};
parser.parse();
header_buffer_type result;
diff --git a/test/examples/CMakeLists.txt b/test/examples/CMakeLists.txt
new file mode 100644
index 0000000..90bf76e
--- /dev/null
+++ b/test/examples/CMakeLists.txt
@@ -0,0 +1,21 @@
+#-----------------------------------------------------------------------------
+#
+# CMake Config
+#
+# Libosmium example tests
+#
+#-----------------------------------------------------------------------------
+
+message(STATUS "Configuring example tests")
+
+file(GLOB _dirs RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/t/*)
+
+foreach(_dir ${_dirs})
+ message(STATUS " adding test: ${_dir}")
+ add_subdirectory("${_dir}")
+endforeach()
+
+message(STATUS "Configuring example tests - done")
+
+
+#-----------------------------------------------------------------------------
diff --git a/test/examples/t/pub_names/CMakeLists.txt b/test/examples/t/pub_names/CMakeLists.txt
new file mode 100644
index 0000000..9a68ae8
--- /dev/null
+++ b/test/examples/t/pub_names/CMakeLists.txt
@@ -0,0 +1,7 @@
+
+add_test(NAME examples_pub_names
+ COMMAND osmium_pub_names ${CMAKE_CURRENT_SOURCE_DIR}/pubs.osm)
+
+set_tests_properties(examples_pub_names PROPERTIES
+ PASS_REGULAR_EXPRESSION "^Im Holze\n$")
+
diff --git a/test/examples/t/pub_names/pubs.osm b/test/examples/t/pub_names/pubs.osm
new file mode 100644
index 0000000..ee54226
--- /dev/null
+++ b/test/examples/t/pub_names/pubs.osm
@@ -0,0 +1,7 @@
+<?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="amenity" v="pub"/>
+ <tag k="name" v="Im Holze"/>
+ </node>
+</osm>
diff --git a/test/examples/t/road_length/CMakeLists.txt b/test/examples/t/road_length/CMakeLists.txt
new file mode 100644
index 0000000..6323f07
--- /dev/null
+++ b/test/examples/t/road_length/CMakeLists.txt
@@ -0,0 +1,8 @@
+
+add_test(NAME examples_road_length
+ COMMAND osmium_road_length ${CMAKE_CURRENT_SOURCE_DIR}/road.osm)
+
+set_tests_properties(examples_road_length PROPERTIES
+ PASS_REGULAR_EXPRESSION "^Length: 0\\.405.*km\n$"
+)
+
diff --git a/test/examples/t/road_length/road.osm b/test/examples/t/road_length/road.osm
new file mode 100644
index 0000000..934ef46
--- /dev/null
+++ b/test/examples/t/road_length/road.osm
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<osm version="0.6" generator="CGImap 0.3.3 (31041 thorn-01.openstreetmap.org)" copyright="OpenStreetMap and contributors" attribution="http://www.openstreetmap.org/copyright" license="http://opendatacommons.org/licenses/odbl/1-0/">
+ <node id="5599384" visible="true" version="5" changeset="829716" timestamp="2009-03-18T17:16:26Z" user="burts" uid="97529" lat="51.0271601" lon="13.7252197"/>
+ <node id="250384970" visible="true" version="3" changeset="855544" timestamp="2009-01-30T21:58:37Z" user="saftl" uid="7989" lat="51.0288568" lon="13.7248159">
+ <tag k="created_by" v="JOSM"/>
+ </node>
+ <node id="250996316" visible="true" version="5" changeset="838711" timestamp="2009-03-21T13:10:39Z" user="burts" uid="97529" lat="51.0274683" lon="13.7251464"/>
+ <node id="250996321" visible="true" version="3" changeset="855544" timestamp="2009-01-30T21:59:14Z" user="saftl" uid="7989" lat="51.0284283" lon="13.7249179">
+ <tag k="created_by" v="JOSM"/>
+ </node>
+ <node id="252587568" visible="true" version="3" changeset="855544" timestamp="2009-01-30T21:58:45Z" user="saftl" uid="7989" lat="51.0275477" lon="13.7251275">
+ <tag k="created_by" v="JOSM"/>
+ </node>
+ <node id="5599381" visible="true" version="6" changeset="15768585" timestamp="2013-04-18T01:20:26Z" user="Wolle DD" uid="1161559" lat="51.0307642" lon="13.7243263"/>
+ <node id="1122039499" visible="true" version="2" changeset="26063898" timestamp="2014-10-14T04:09:11Z" user="Seandebasti" uid="550560" lat="51.0285248" lon="13.7248970"/>
+ <node id="1122039521" visible="true" version="2" changeset="12753110" timestamp="2012-08-16T17:03:47Z" user="TEAM_CN_TUD" uid="716608" lat="51.0277456" lon="13.7250806"/>
+ <node id="5599382" visible="true" version="6" changeset="8191054" timestamp="2011-05-19T16:19:51Z" user="stw1701" uid="102899" lat="51.0297991" lon="13.7245892"/>
+ <node id="1299329303" visible="true" version="1" changeset="8242335" timestamp="2011-05-25T07:46:01Z" user="bigbug21" uid="15748" lat="51.0290875" lon="13.7247628"/>
+ <node id="1868844753" visible="true" version="2" changeset="13260925" timestamp="2012-09-26T15:26:31Z" user="TEAM_CN_TUD" uid="716608" lat="51.0289617" lon="13.7247917"/>
+ <node id="1868844765" visible="true" version="2" changeset="13260925" timestamp="2012-09-26T15:26:31Z" user="TEAM_CN_TUD" uid="716608" lat="51.0292872" lon="13.7247140"/>
+ <node id="1868844782" visible="true" version="2" changeset="13260925" timestamp="2012-09-26T15:26:31Z" user="TEAM_CN_TUD" uid="716608" lat="51.0295717" lon="13.7246429"/>
+ <node id="1922091528" visible="true" version="2" changeset="13260925" timestamp="2012-09-26T15:26:31Z" user="TEAM_CN_TUD" uid="716608" lat="51.0281700" lon="13.7249813"/>
+ <node id="1953249124" visible="true" version="1" changeset="13418280" timestamp="2012-10-08T20:18:35Z" user="TEAM_CN_TUD" uid="716608" lat="51.0292437" lon="13.7247246"/>
+ <node id="2015120752" visible="true" version="1" changeset="13883494" timestamp="2012-11-15T14:22:31Z" user="TEAM_CN_TUD" uid="716608" lat="51.0293536" lon="13.7246974"/>
+ <node id="2056871900" visible="true" version="1" changeset="14207491" timestamp="2012-12-09T00:03:11Z" user="bigbug21" uid="15748" lat="51.0305821" lon="13.7243895"/>
+ <node id="2458246647" visible="true" version="1" changeset="17836591" timestamp="2013-09-14T17:05:06Z" user="bigbug21" uid="15748" lat="51.0295979" lon="13.7246367"/>
+ <node id="250384969" visible="true" version="4" changeset="17857555" timestamp="2013-09-15T20:17:55Z" user="4b696d" uid="1420318" lat="51.0282021" lon="13.7249734"/>
+ <node id="3128723784" visible="true" version="1" changeset="26063898" timestamp="2014-10-14T04:09:07Z" user="Seandebasti" uid="550560" lat="51.0281018" lon="13.7249973"/>
+ <way id="4428564" visible="true" version="21" changeset="26063898" timestamp="2014-10-14T04:09:13Z" user="Seandebasti" uid="550560">
+ <nd ref="5599381"/>
+ <nd ref="2056871900"/>
+ <nd ref="5599382"/>
+ <nd ref="2458246647"/>
+ <nd ref="1868844782"/>
+ <nd ref="2015120752"/>
+ <nd ref="1868844765"/>
+ <nd ref="1953249124"/>
+ <nd ref="1299329303"/>
+ <nd ref="1868844753"/>
+ <nd ref="250384970"/>
+ <nd ref="1122039499"/>
+ <nd ref="250996321"/>
+ <nd ref="250384969"/>
+ <nd ref="1922091528"/>
+ <nd ref="3128723784"/>
+ <nd ref="1122039521"/>
+ <nd ref="252587568"/>
+ <nd ref="250996316"/>
+ <nd ref="5599384"/>
+ <tag k="highway" v="residential"/>
+ <tag k="lit" v="yes"/>
+ <tag k="maxspeed" v="30"/>
+ <tag k="name" v="Helmholtzstraße"/>
+ <tag k="postal_code" v="01069"/>
+ <tag k="sidewalk" v="both"/>
+ <tag k="smoothness" v="good"/>
+ <tag k="surface" v="asphalt"/>
+ </way>
+</osm>
\ No newline at end of file
diff --git a/test/include/catch.hpp b/test/include/catch.hpp
index 879fc5b..2e6fe8d 100644
--- a/test/include/catch.hpp
+++ b/test/include/catch.hpp
@@ -1,6 +1,6 @@
/*
- * Catch v1.5.6
- * Generated: 2016-06-09 19:20:41.460328
+ * Catch v1.5.8
+ * Generated: 2016-10-26 12:07:30.938259
* ----------------------------------------------------------
* This file has been merged from multiple headers. Please don't edit it directly
* Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved.
@@ -3223,10 +3223,11 @@ namespace Catch {
bool matches( TestCaseInfo const& testCase ) const {
// All patterns in a filter must match for the filter to be a match
- for( std::vector<Ptr<Pattern> >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it )
+ for( std::vector<Ptr<Pattern> >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) {
if( !(*it)->matches( testCase ) )
return false;
- return true;
+ }
+ return true;
}
};
@@ -4719,8 +4720,11 @@ namespace Catch {
std::string line;
while( std::getline( f, line ) ) {
line = trim(line);
- if( !line.empty() && !startsWith( line, "#" ) )
- addTestOrTags( config, "\"" + line + "\"," );
+ if( !line.empty() && !startsWith( line, "#" ) ) {
+ if( !startsWith( line, "\"" ) )
+ line = "\"" + line + "\"";
+ addTestOrTags( config, line + "," );
+ }
}
}
@@ -5368,7 +5372,10 @@ namespace Catch {
++it ) {
matchedTests++;
TestCaseInfo const& testCaseInfo = it->getTestCaseInfo();
- Catch::cout() << testCaseInfo.name << std::endl;
+ if( startsWith( testCaseInfo.name, "#" ) )
+ Catch::cout() << "\"" << testCaseInfo.name << "\"" << std::endl;
+ else
+ Catch::cout() << testCaseInfo.name << std::endl;
}
return matchedTests;
}
@@ -6454,7 +6461,7 @@ namespace Catch {
namespace Catch {
struct RandomNumberGenerator {
- typedef int result_type;
+ typedef std::ptrdiff_t result_type;
result_type operator()( result_type n ) const { return std::rand() % n; }
@@ -7571,7 +7578,7 @@ namespace Catch {
return os;
}
- Version libraryVersion( 1, 5, 6, "", 0 );
+ Version libraryVersion( 1, 5, 8, "", 0 );
}
@@ -7802,8 +7809,11 @@ namespace Catch {
bool contains( std::string const& s, std::string const& infix ) {
return s.find( infix ) != std::string::npos;
}
+ char toLowerCh(char c) {
+ return static_cast<char>( ::tolower( c ) );
+ }
void toLowerInPlace( std::string& s ) {
- std::transform( s.begin(), s.end(), s.begin(), ::tolower );
+ std::transform( s.begin(), s.end(), s.begin(), toLowerCh );
}
std::string toLower( std::string const& s ) {
std::string lc = s;
@@ -8951,9 +8961,10 @@ namespace Catch {
break;
default:
- // Escape control chars - based on contribution by @espenalb in PR #465
+ // Escape control chars - based on contribution by @espenalb in PR #465 and
+ // by @mrpi PR #588
if ( ( c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' )
- os << "&#x" << std::uppercase << std::hex << static_cast<int>( c );
+ os << "&#x" << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << static_cast<int>( c ) << ';';
else
os << c;
}
@@ -9008,13 +9019,20 @@ namespace Catch {
: m_tagIsOpen( false ),
m_needsNewline( false ),
m_os( &Catch::cout() )
- {}
+ {
+ // We encode control characters, which requires
+ // XML 1.1
+ // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0
+ *m_os << "<?xml version=\"1.1\" encoding=\"UTF-8\"?>\n";
+ }
XmlWriter( std::ostream& os )
: m_tagIsOpen( false ),
m_needsNewline( false ),
m_os( &os )
- {}
+ {
+ *m_os << "<?xml version=\"1.1\" encoding=\"UTF-8\"?>\n";
+ }
~XmlWriter() {
while( !m_tags.empty() )
@@ -9181,7 +9199,7 @@ namespace Catch {
virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE {
StreamingReporterBase::testCaseStarting(testInfo);
- m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) );
+ m_xml.startElement( "TestCase" ).writeAttribute( "name", testInfo.name );
if ( m_config->showDurations() == ShowDurations::Always )
m_testCaseTimer.start();
@@ -9243,7 +9261,7 @@ namespace Catch {
.writeText( assertionResult.getMessage() );
break;
case ResultWas::FatalErrorCondition:
- m_xml.scopedElement( "Fatal Error Condition" )
+ m_xml.scopedElement( "FatalErrorCondition" )
.writeAttribute( "filename", assertionResult.getSourceInfo().file )
.writeAttribute( "line", assertionResult.getSourceInfo().line )
.writeText( assertionResult.getMessage() );
diff --git a/test/t/basic/test_entity_bits.cpp b/test/t/basic/test_entity_bits.cpp
deleted file mode 100644
index 13de94b..0000000
--- a/test/t/basic/test_entity_bits.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-#include "catch.hpp"
-
-#include <osmium/osm/entity_bits.hpp>
-
-TEST_CASE("entity_bits") {
-
- SECTION("can_be_set_and_checked") {
- osmium::osm_entity_bits::type entities = osmium::osm_entity_bits::node | osmium::osm_entity_bits::way;
- REQUIRE(entities == (osmium::osm_entity_bits::node | osmium::osm_entity_bits::way));
-
- entities |= osmium::osm_entity_bits::relation;
- REQUIRE((entities & osmium::osm_entity_bits::object));
-
- entities |= osmium::osm_entity_bits::area;
- REQUIRE(entities == osmium::osm_entity_bits::object);
-
- REQUIRE(! (entities & osmium::osm_entity_bits::changeset));
-
- entities &= osmium::osm_entity_bits::node;
- REQUIRE((entities & osmium::osm_entity_bits::node));
- REQUIRE(! (entities & osmium::osm_entity_bits::way));
- REQUIRE(entities == osmium::osm_entity_bits::node);
-
- REQUIRE(osmium::osm_entity_bits::nothing == osmium::osm_entity_bits::from_item_type(osmium::item_type::undefined));
- REQUIRE(osmium::osm_entity_bits::node == osmium::osm_entity_bits::from_item_type(osmium::item_type::node));
- REQUIRE(osmium::osm_entity_bits::way == osmium::osm_entity_bits::from_item_type(osmium::item_type::way));
- REQUIRE(osmium::osm_entity_bits::relation == osmium::osm_entity_bits::from_item_type(osmium::item_type::relation));
- REQUIRE(osmium::osm_entity_bits::changeset == osmium::osm_entity_bits::from_item_type(osmium::item_type::changeset));
- REQUIRE(osmium::osm_entity_bits::area == osmium::osm_entity_bits::from_item_type(osmium::item_type::area));
- }
-
-}
diff --git a/test/t/builder/test_object_builder.cpp b/test/t/builder/test_object_builder.cpp
new file mode 100644
index 0000000..5b12564
--- /dev/null
+++ b/test/t/builder/test_object_builder.cpp
@@ -0,0 +1,444 @@
+
+#include "catch.hpp"
+
+#include <osmium/builder/osm_object_builder.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/osm.hpp>
+
+TEST_CASE("create objects using builder") {
+ osmium::memory::Buffer buffer{1024*10};
+ std::string user;
+
+ SECTION("complete node with tags") {
+ SECTION("user length 0") {
+ user = "";
+ }
+ SECTION("user length 1") {
+ user = "1";
+ }
+ SECTION("user length 2") {
+ user = "12";
+ }
+ SECTION("user length 3") {
+ user = "123";
+ }
+ SECTION("user length 4") {
+ user = "1234";
+ }
+ SECTION("user length 5") {
+ user = "12345";
+ }
+ SECTION("user length 6") {
+ user = "123456";
+ }
+ SECTION("user length 7") {
+ user = "1234567";
+ }
+ SECTION("user length 8") {
+ user = "12345678";
+ }
+ SECTION("user length 9") {
+ user = "123456789";
+ }
+ SECTION("user length 10") {
+ user = "1234567890";
+ }
+ SECTION("user length 11") {
+ user = "12345678901";
+ }
+ SECTION("user length 12") {
+ user = "123456789012";
+ }
+ SECTION("user length 13") {
+ user = "1234567890123";
+ }
+ SECTION("user length 14") {
+ user = "12345678901234";
+ }
+ SECTION("user length 15") {
+ user = "123456789012345";
+ }
+ SECTION("user length 16") {
+ user = "1234567890123456";
+ }
+ SECTION("user length 17") {
+ user = "12345678901234567";
+ }
+ SECTION("user length 18") {
+ user = "123456789012345678";
+ }
+
+ osmium::Location loc{1.2, 3.4};
+
+ {
+ osmium::builder::NodeBuilder builder{buffer};
+
+ builder.set_id(17)
+ .set_visible(true)
+ .set_version(1)
+ .set_changeset(123)
+ .set_uid(555)
+ .set_timestamp("2015-07-01T00:00:01Z")
+ .set_location(loc)
+ .set_user(user);
+
+ builder.add_tags({{"highway", "primary"}, {"oneway", "yes"}});
+ }
+
+ const auto& node = buffer.get<osmium::Node>(buffer.commit());
+
+ REQUIRE(node.id() == 17);
+ REQUIRE(node.version() == 1);
+ REQUIRE(node.changeset() == 123);
+ REQUIRE(node.uid() == 555);
+ REQUIRE(node.timestamp() == osmium::Timestamp{"2015-07-01T00:00:01Z"});
+ REQUIRE(node.location() == loc);
+
+ REQUIRE(user == node.user());
+
+ REQUIRE(node.tags().size() == 2);
+ }
+
+ SECTION("complete way with tags") {
+ SECTION("user length 0") {
+ user = "";
+ }
+ SECTION("user length 1") {
+ user = "1";
+ }
+ SECTION("user length 2") {
+ user = "12";
+ }
+ SECTION("user length 3") {
+ user = "123";
+ }
+ SECTION("user length 4") {
+ user = "1234";
+ }
+ SECTION("user length 5") {
+ user = "12345";
+ }
+ SECTION("user length 6") {
+ user = "123456";
+ }
+ SECTION("user length 7") {
+ user = "1234567";
+ }
+ SECTION("user length 8") {
+ user = "12345678";
+ }
+ SECTION("user length 9") {
+ user = "123456789";
+ }
+ SECTION("user length 10") {
+ user = "1234567890";
+ }
+ SECTION("user length 11") {
+ user = "12345678901";
+ }
+ SECTION("user length 12") {
+ user = "123456789012";
+ }
+ SECTION("user length 13") {
+ user = "1234567890123";
+ }
+ SECTION("user length 14") {
+ user = "12345678901234";
+ }
+ SECTION("user length 15") {
+ user = "123456789012345";
+ }
+ SECTION("user length 16") {
+ user = "1234567890123456";
+ }
+ SECTION("user length 17") {
+ user = "12345678901234567";
+ }
+ SECTION("user length 18") {
+ user = "123456789012345678";
+ }
+
+ {
+ osmium::builder::WayBuilder builder{buffer};
+
+ builder.set_id(17)
+ .set_visible(true)
+ .set_version(1)
+ .set_changeset(123)
+ .set_uid(555)
+ .set_timestamp("2015-07-01T00:00:01Z")
+ .set_user(user);
+
+ builder.add_tags({{"highway", "primary"}, {"oneway", "yes"}});
+ }
+
+ const auto& way = buffer.get<osmium::Way>(buffer.commit());
+
+ REQUIRE(way.id() == 17);
+ REQUIRE(way.version() == 1);
+ REQUIRE(way.changeset() == 123);
+ REQUIRE(way.uid() == 555);
+ REQUIRE(way.timestamp() == osmium::Timestamp{"2015-07-01T00:00:01Z"});
+
+ REQUIRE(user == way.user());
+
+ REQUIRE(way.tags().size() == 2);
+ }
+
+ SECTION("complete relation with tags") {
+ SECTION("user length 0") {
+ user = "";
+ }
+ SECTION("user length 1") {
+ user = "1";
+ }
+ SECTION("user length 2") {
+ user = "12";
+ }
+ SECTION("user length 3") {
+ user = "123";
+ }
+ SECTION("user length 4") {
+ user = "1234";
+ }
+ SECTION("user length 5") {
+ user = "12345";
+ }
+ SECTION("user length 6") {
+ user = "123456";
+ }
+ SECTION("user length 7") {
+ user = "1234567";
+ }
+ SECTION("user length 8") {
+ user = "12345678";
+ }
+ SECTION("user length 9") {
+ user = "123456789";
+ }
+ SECTION("user length 10") {
+ user = "1234567890";
+ }
+ SECTION("user length 11") {
+ user = "12345678901";
+ }
+ SECTION("user length 12") {
+ user = "123456789012";
+ }
+ SECTION("user length 13") {
+ user = "1234567890123";
+ }
+ SECTION("user length 14") {
+ user = "12345678901234";
+ }
+ SECTION("user length 15") {
+ user = "123456789012345";
+ }
+ SECTION("user length 16") {
+ user = "1234567890123456";
+ }
+ SECTION("user length 17") {
+ user = "12345678901234567";
+ }
+ SECTION("user length 18") {
+ user = "123456789012345678";
+ }
+
+ {
+ osmium::builder::RelationBuilder builder{buffer};
+
+ builder.set_id(17)
+ .set_visible(true)
+ .set_version(1)
+ .set_changeset(123)
+ .set_uid(555)
+ .set_timestamp("2015-07-01T00:00:01Z")
+ .set_user(user);
+
+ builder.add_tags({{"highway", "primary"}, {"oneway", "yes"}});
+ }
+
+ const auto& relation = buffer.get<osmium::Relation>(buffer.commit());
+
+ REQUIRE(relation.id() == 17);
+ REQUIRE(relation.version() == 1);
+ REQUIRE(relation.changeset() == 123);
+ REQUIRE(relation.uid() == 555);
+ REQUIRE(relation.timestamp() == osmium::Timestamp{"2015-07-01T00:00:01Z"});
+
+ REQUIRE(user == relation.user());
+
+ REQUIRE(relation.tags().size() == 2);
+ }
+
+ SECTION("complete changeset with tags") {
+ osmium::Location bl{-1.2, -3.4};
+ osmium::Location tr{1.2, 3.4};
+
+ SECTION("user length 0") {
+ user = "";
+ }
+ SECTION("user length 1") {
+ user = "1";
+ }
+ SECTION("user length 2") {
+ user = "12";
+ }
+ SECTION("user length 3") {
+ user = "123";
+ }
+ SECTION("user length 4") {
+ user = "1234";
+ }
+ SECTION("user length 5") {
+ user = "12345";
+ }
+ SECTION("user length 6") {
+ user = "123456";
+ }
+ SECTION("user length 7") {
+ user = "1234567";
+ }
+ SECTION("user length 8") {
+ user = "12345678";
+ }
+ SECTION("user length 9") {
+ user = "123456789";
+ }
+ SECTION("user length 10") {
+ user = "1234567890";
+ }
+ SECTION("user length 11") {
+ user = "12345678901";
+ }
+ SECTION("user length 12") {
+ user = "123456789012";
+ }
+ SECTION("user length 13") {
+ user = "1234567890123";
+ }
+ SECTION("user length 14") {
+ user = "12345678901234";
+ }
+ SECTION("user length 15") {
+ user = "123456789012345";
+ }
+ SECTION("user length 16") {
+ user = "1234567890123456";
+ }
+ SECTION("user length 17") {
+ user = "12345678901234567";
+ }
+ SECTION("user length 18") {
+ user = "123456789012345678";
+ }
+
+ {
+ osmium::builder::ChangesetBuilder builder{buffer};
+
+ builder.set_id(17)
+ .set_uid(222)
+ .set_created_at(osmium::Timestamp{"2016-07-03T01:23:45Z"})
+ .set_closed_at(osmium::Timestamp{"2016-07-03T01:23:48Z"})
+ .set_num_changes(3)
+ .set_num_comments(2)
+ .set_bounds(osmium::Box{bl, tr})
+ .set_user(user);
+ }
+
+ const auto& changeset = buffer.get<osmium::Changeset>(buffer.commit());
+
+ REQUIRE(changeset.id() == 17);
+ REQUIRE(changeset.uid() == 222);
+ REQUIRE(changeset.created_at() == osmium::Timestamp{"2016-07-03T01:23:45Z"});
+ REQUIRE(changeset.closed_at() == osmium::Timestamp{"2016-07-03T01:23:48Z"});
+ REQUIRE(changeset.num_changes() == 3);
+ REQUIRE(changeset.num_comments() == 2);
+
+ const auto& box = changeset.bounds();
+ REQUIRE(box.bottom_left() == bl);
+ REQUIRE(box.top_right() == tr);
+
+ REQUIRE(user == changeset.user());
+ }
+
+}
+
+TEST_CASE("no call to set_user on node") {
+ osmium::memory::Buffer buffer{1024*10};
+
+ {
+ osmium::builder::NodeBuilder builder{buffer};
+ }
+
+ const auto& node = buffer.get<osmium::Node>(buffer.commit());
+
+ REQUIRE(*node.user() == '\0');
+}
+
+TEST_CASE("set_user with length on node") {
+ osmium::memory::Buffer buffer{1024*10};
+ std::string user = "userx";
+
+ {
+ osmium::builder::NodeBuilder builder{buffer};
+ builder.set_user(user.c_str(), 4);
+ }
+
+ const auto& node = buffer.get<osmium::Node>(buffer.commit());
+
+ REQUIRE(std::string{"user"} == node.user());
+}
+
+TEST_CASE("no call to set_user on way") {
+ osmium::memory::Buffer buffer{1024*10};
+
+ {
+ osmium::builder::WayBuilder builder{buffer};
+ }
+
+ const auto& way = buffer.get<osmium::Way>(buffer.commit());
+
+ REQUIRE(*way.user() == '\0');
+}
+
+TEST_CASE("set_user with length on way") {
+ osmium::memory::Buffer buffer{1024*10};
+ std::string user = "userx";
+
+ {
+ osmium::builder::WayBuilder builder{buffer};
+ builder.set_user(user.c_str(), 4);
+ }
+
+ const auto& way = buffer.get<osmium::Way>(buffer.commit());
+
+ REQUIRE(std::string{"user"} == way.user());
+}
+
+TEST_CASE("no call to set_user on changeset") {
+ osmium::memory::Buffer buffer{1024*10};
+
+ {
+ osmium::builder::ChangesetBuilder builder{buffer};
+ }
+
+ const auto& changeset = buffer.get<osmium::Changeset>(buffer.commit());
+
+ REQUIRE(*changeset.user() == '\0');
+}
+
+TEST_CASE("set_user with length on changeset") {
+ osmium::memory::Buffer buffer{1024*10};
+ std::string user = "userx";
+
+ {
+ osmium::builder::ChangesetBuilder builder{buffer};
+ builder.set_user(user.c_str(), 4);
+ }
+
+ const auto& changeset = buffer.get<osmium::Changeset>(buffer.commit());
+
+ REQUIRE(std::string{"user"} == changeset.user());
+}
+
diff --git a/test/t/geom/helper.hpp b/test/t/geom/helper.hpp
deleted file mode 100644
index e0cefe6..0000000
--- a/test/t/geom/helper.hpp
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef TEST_GEOM_HELPER_HPP
-#define TEST_GEOM_HELPER_HPP
-
-#include <string>
-
-#include <geos/io/WKBWriter.h>
-
-inline std::string geos_to_wkb(const geos::geom::Geometry* geometry) {
- std::stringstream ss;
- geos::io::WKBWriter wkb_writer;
- wkb_writer.writeHEX(*geometry, ss);
- return ss.str();
-}
-
-#endif // TEST_GEOM_HELPER_HPP
diff --git a/test/t/geom/test_crs.cpp b/test/t/geom/test_crs.cpp
index c8fbc09..d8f7c36 100644
--- a/test/t/geom/test_crs.cpp
+++ b/test/t/geom/test_crs.cpp
@@ -5,12 +5,12 @@
#include <osmium/geom/projection.hpp>
TEST_CASE("CRS") {
- osmium::geom::CRS wgs84{4326};
- osmium::geom::CRS mercator{3857};
+ const osmium::geom::CRS wgs84{4326};
+ const osmium::geom::CRS mercator{3857};
- osmium::geom::Coordinates c{osmium::geom::deg_to_rad(1.2), osmium::geom::deg_to_rad(3.4)};
- auto ct = osmium::geom::transform(wgs84, mercator, c);
- auto c2 = osmium::geom::transform(mercator, wgs84, ct);
+ const osmium::geom::Coordinates c{osmium::geom::deg_to_rad(1.2), osmium::geom::deg_to_rad(3.4)};
+ const auto ct = osmium::geom::transform(wgs84, mercator, c);
+ const auto c2 = osmium::geom::transform(mercator, wgs84, ct);
REQUIRE(c.x == Approx(c2.x));
REQUIRE(c.y == Approx(c2.y));
diff --git a/test/t/geom/test_exception.cpp b/test/t/geom/test_exception.cpp
index fe95043..4122d17 100644
--- a/test/t/geom/test_exception.cpp
+++ b/test/t/geom/test_exception.cpp
@@ -6,11 +6,9 @@
TEST_CASE("Geometry exception") {
- SECTION("geometry_error") {
- osmium::geometry_error e("some error message", "node", 17);
- REQUIRE(e.id() == 17);
- REQUIRE(std::string(e.what()) == "some error message (node_id=17)");
- }
+ osmium::geometry_error e{"some error message", "node", 17};
+ REQUIRE(e.id() == 17);
+ REQUIRE(std::string{e.what()} == "some error message (node_id=17)");
}
diff --git a/test/t/geom/test_factory_with_projection.cpp b/test/t/geom/test_factory_with_projection.cpp
index 42fc864..08efc03 100644
--- a/test/t/geom/test_factory_with_projection.cpp
+++ b/test/t/geom/test_factory_with_projection.cpp
@@ -1,41 +1,21 @@
#include "catch.hpp"
-#include <osmium/geom/geos.hpp>
#include <osmium/geom/mercator_projection.hpp>
#include <osmium/geom/projection.hpp>
#include <osmium/geom/wkb.hpp>
#include <osmium/geom/wkt.hpp>
-#include "helper.hpp"
+TEST_CASE("Projection using MercatorProjection class to WKT") {
+ osmium::geom::WKTFactory<osmium::geom::MercatorProjection> factory{2};
-TEST_CASE("Projection") {
-
- SECTION("point_mercator") {
- osmium::geom::WKTFactory<osmium::geom::MercatorProjection> factory(2);
-
- std::string wkt {factory.create_point(osmium::Location(3.2, 4.2))};
- REQUIRE(std::string {"POINT(356222.37 467961.14)"} == wkt);
- }
-
- SECTION("point_epsg_3857") {
- osmium::geom::WKTFactory<osmium::geom::Projection> factory(osmium::geom::Projection(3857), 2);
-
- std::string wkt {factory.create_point(osmium::Location(3.2, 4.2))};
- REQUIRE(std::string {"POINT(356222.37 467961.14)"} == wkt);
- }
-
- SECTION("wkb_with_parameter") {
- osmium::geom::WKBFactory<osmium::geom::Projection> wkb_factory(osmium::geom::Projection(3857), osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
- osmium::geom::GEOSFactory<osmium::geom::Projection> geos_factory(osmium::geom::Projection(3857));
-
- std::string wkb = wkb_factory.create_point(osmium::Location(3.2, 4.2));
- std::unique_ptr<geos::geom::Point> geos_point = geos_factory.create_point(osmium::Location(3.2, 4.2));
- REQUIRE(geos_to_wkb(geos_point.get()) == wkb);
- }
+ const std::string wkt{factory.create_point(osmium::Location{3.2, 4.2})};
+ REQUIRE(wkt == "POINT(356222.37 467961.14)");
+}
- SECTION("cleanup") {
- // trying to make valgrind happy, but there is still a memory leak in proj library
- pj_deallocate_grids();
- }
+TEST_CASE("Projection using Projection class to WKT") {
+ osmium::geom::WKTFactory<osmium::geom::Projection> factory{osmium::geom::Projection{3857}, 2};
+ const std::string wkt{factory.create_point(osmium::Location{3.2, 4.2})};
+ REQUIRE(wkt == "POINT(356222.37 467961.14)");
}
+
diff --git a/test/t/geom/test_geojson.cpp b/test/t/geom/test_geojson.cpp
index 725be7f..5724936 100644
--- a/test/t/geom/test_geojson.cpp
+++ b/test/t/geom/test_geojson.cpp
@@ -5,162 +5,143 @@
#include "area_helper.hpp"
#include "wnl_helper.hpp"
-TEST_CASE("GeoJSON_Geometry") {
-
-SECTION("point") {
+TEST_CASE("GeoJSON point geometry") {
osmium::geom::GeoJSONFactory<> factory;
- std::string json {factory.create_point(osmium::Location(3.2, 4.2))};
- REQUIRE(std::string{"{\"type\":\"Point\",\"coordinates\":[3.2,4.2]}"} == json);
-}
+ SECTION("point") {
+ const std::string json{factory.create_point(osmium::Location{3.2, 4.2})};
+ REQUIRE(std::string{"{\"type\":\"Point\",\"coordinates\":[3.2,4.2]}"} == json);
+ }
-SECTION("empty_point") {
- osmium::geom::GeoJSONFactory<> factory;
+ SECTION("empty_point") {
+ REQUIRE_THROWS_AS(factory.create_point(osmium::Location{}), osmium::invalid_location);
+ }
- REQUIRE_THROWS_AS(factory.create_point(osmium::Location()), osmium::invalid_location);
}
-SECTION("linestring") {
+TEST_CASE("GeoJSON linestring geometry") {
osmium::geom::GeoJSONFactory<> factory;
+ osmium::memory::Buffer buffer{1000};
- osmium::memory::Buffer buffer(1000);
- auto &wnl = create_test_wnl_okay(buffer);
-
- {
- std::string json {factory.create_linestring(wnl)};
+ SECTION("linestring, default") {
+ const auto& wnl = create_test_wnl_okay(buffer);
+ const std::string json{factory.create_linestring(wnl)};
REQUIRE(std::string{"{\"type\":\"LineString\",\"coordinates\":[[3.2,4.2],[3.5,4.7],[3.6,4.9]]}"} == json);
}
- {
- std::string json {factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward)};
+ SECTION("linestring, unique, backwards") {
+ const auto& wnl = create_test_wnl_okay(buffer);
+ const std::string json{factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward)};
REQUIRE(std::string{"{\"type\":\"LineString\",\"coordinates\":[[3.6,4.9],[3.5,4.7],[3.2,4.2]]}"} == json);
}
- {
- std::string json {factory.create_linestring(wnl, osmium::geom::use_nodes::all)};
+ SECTION("linestring, all") {
+ const auto& wnl = create_test_wnl_okay(buffer);
+ const std::string json{factory.create_linestring(wnl, osmium::geom::use_nodes::all)};
REQUIRE(std::string{"{\"type\":\"LineString\",\"coordinates\":[[3.2,4.2],[3.5,4.7],[3.5,4.7],[3.6,4.9]]}"} == json);
}
- {
- std::string json {factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward)};
+ SECTION("linestring, all, backwards") {
+ const auto& wnl = create_test_wnl_okay(buffer);
+ const std::string json{factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward)};
REQUIRE(std::string{"{\"type\":\"LineString\",\"coordinates\":[[3.6,4.9],[3.5,4.7],[3.5,4.7],[3.2,4.2]]}"} == json);
}
-}
-SECTION("empty_linestring") {
- osmium::geom::GeoJSONFactory<> factory;
+ SECTION("empty_linestring") {
+ const auto& wnl = create_test_wnl_empty(buffer);
- osmium::memory::Buffer buffer(1000);
- 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), osmium::geometry_error);
- REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward), osmium::geometry_error);
- REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::all), osmium::geometry_error);
- REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward), osmium::geometry_error);
-}
+ SECTION("linestring with two same locations") {
+ const auto& wnl = create_test_wnl_same_location(buffer);
-SECTION("linestring_with_two_same_locations") {
- osmium::geom::GeoJSONFactory<> factory;
+ 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);
- osmium::memory::Buffer buffer(1000);
- 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);
+ {
+ const std::string json{factory.create_linestring(wnl, osmium::geom::use_nodes::all)};
+ REQUIRE(std::string{"{\"type\":\"LineString\",\"coordinates\":[[3.5,4.7],[3.5,4.7]]}"} == json);
+ }
- {
- std::string json {factory.create_linestring(wnl, osmium::geom::use_nodes::all)};
- REQUIRE(std::string{"{\"type\":\"LineString\",\"coordinates\":[[3.5,4.7],[3.5,4.7]]}"} == json);
+ {
+ const std::string json{factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward)};
+ REQUIRE(std::string{"{\"type\":\"LineString\",\"coordinates\":[[3.5,4.7],[3.5,4.7]]}"} == json);
+ }
}
- {
- std::string json {factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward)};
- REQUIRE(std::string{"{\"type\":\"LineString\",\"coordinates\":[[3.5,4.7],[3.5,4.7]]}"} == json);
+ SECTION("linestring with undefined location") {
+ const auto& wnl = create_test_wnl_undefined_location(buffer);
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl), osmium::invalid_location);
}
-}
-
-SECTION("linestring_with_undefined_location") {
- osmium::geom::GeoJSONFactory<> factory;
-
- osmium::memory::Buffer buffer(1000);
- auto& wnl = create_test_wnl_undefined_location(buffer);
- REQUIRE_THROWS_AS(factory.create_linestring(wnl), osmium::invalid_location);
}
-SECTION("area_1outer_0inner") {
+TEST_CASE("GeoJSON area geometry") {
osmium::geom::GeoJSONFactory<> factory;
+ osmium::memory::Buffer buffer{1000};
- osmium::memory::Buffer buffer(1000);
- const osmium::Area& area = create_test_area_1outer_0inner(buffer);
+ SECTION("area_1outer_0inner") {
+ const osmium::Area& area = create_test_area_1outer_0inner(buffer);
- REQUIRE(!area.is_multipolygon());
- REQUIRE(std::distance(area.cbegin(), area.cend()) == 2);
- REQUIRE(area.subitems<osmium::OuterRing>().size() == area.num_rings().first);
+ REQUIRE(!area.is_multipolygon());
+ REQUIRE(std::distance(area.cbegin(), area.cend()) == 2);
+ REQUIRE(area.subitems<osmium::OuterRing>().size() == area.num_rings().first);
- {
- std::string json {factory.create_multipolygon(area)};
+ std::string json{factory.create_multipolygon(area)};
REQUIRE(std::string{"{\"type\":\"MultiPolygon\",\"coordinates\":[[[[3.2,4.2],[3.5,4.7],[3.6,4.9],[3.2,4.2]]]]}"} == json);
}
-}
-
-SECTION("area_1outer_1inner") {
- osmium::geom::GeoJSONFactory<> factory;
- osmium::memory::Buffer buffer(1000);
- const osmium::Area& area = create_test_area_1outer_1inner(buffer);
+ SECTION("area_1outer_1inner") {
+ const osmium::Area& area = create_test_area_1outer_1inner(buffer);
- REQUIRE(!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);
+ REQUIRE(!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);
- {
- std::string json {factory.create_multipolygon(area)};
+ std::string json{factory.create_multipolygon(area)};
REQUIRE(std::string{"{\"type\":\"MultiPolygon\",\"coordinates\":[[[[0.1,0.1],[9.1,0.1],[9.1,9.1],[0.1,9.1],[0.1,0.1]],[[1,1],[8,1],[8,8],[1,8],[1,1]]]]}"} == json);
}
-}
-
-SECTION("area_2outer_2inner") {
- osmium::geom::GeoJSONFactory<> factory;
- osmium::memory::Buffer buffer(1000);
- const osmium::Area& area = create_test_area_2outer_2inner(buffer);
-
- REQUIRE(area.is_multipolygon());
- REQUIRE(std::distance(area.cbegin(), area.cend()) == 5);
- REQUIRE(area.subitems<osmium::OuterRing>().size() == area.num_rings().first);
- REQUIRE(area.subitems<osmium::InnerRing>().size() == area.num_rings().second);
-
- int outer_ring=0;
- int inner_ring=0;
- for (const auto& outer : area.outer_rings()) {
- if (outer_ring == 0) {
- REQUIRE(outer.front().ref() == 1);
- } else if (outer_ring == 1) {
- REQUIRE(outer.front().ref() == 100);
- } else {
- REQUIRE(false);
- }
- for (const auto& inner : area.inner_rings(outer)) {
- if (outer_ring == 0 && inner_ring == 0) {
- REQUIRE(inner.front().ref() == 5);
- } else if (outer_ring == 0 && inner_ring == 1) {
- REQUIRE(inner.front().ref() == 10);
+ SECTION("area_2outer_2inner") {
+ const osmium::Area& area = create_test_area_2outer_2inner(buffer);
+
+ REQUIRE(area.is_multipolygon());
+ REQUIRE(std::distance(area.cbegin(), area.cend()) == 5);
+ REQUIRE(area.subitems<osmium::OuterRing>().size() == area.num_rings().first);
+ REQUIRE(area.subitems<osmium::InnerRing>().size() == area.num_rings().second);
+
+ int outer_ring=0;
+ int inner_ring=0;
+ for (const auto& outer : area.outer_rings()) {
+ if (outer_ring == 0) {
+ REQUIRE(outer.front().ref() == 1);
+ } else if (outer_ring == 1) {
+ REQUIRE(outer.front().ref() == 100);
} else {
REQUIRE(false);
}
- ++inner_ring;
+ for (const auto& inner : area.inner_rings(outer)) {
+ if (outer_ring == 0 && inner_ring == 0) {
+ REQUIRE(inner.front().ref() == 5);
+ } else if (outer_ring == 0 && inner_ring == 1) {
+ REQUIRE(inner.front().ref() == 10);
+ } else {
+ REQUIRE(false);
+ }
+ ++inner_ring;
+ }
+ inner_ring = 0;
+ ++outer_ring;
}
- inner_ring = 0;
- ++outer_ring;
- }
- {
- std::string json {factory.create_multipolygon(area)};
+ std::string json{factory.create_multipolygon(area)};
REQUIRE(std::string{"{\"type\":\"MultiPolygon\",\"coordinates\":[[[[0.1,0.1],[9.1,0.1],[9.1,9.1],[0.1,9.1],[0.1,0.1]],[[1,1],[4,1],[4,4],[1,4],[1,1]],[[5,5],[5,7],[7,7],[5,5]]],[[[10,10],[11,10],[11,11],[10,11],[10,10]]]]}"} == json);
}
-}
}
diff --git a/test/t/geom/test_geos.cpp b/test/t/geom/test_geos.cpp
index f74027c..8e7fac4 100644
--- a/test/t/geom/test_geos.cpp
+++ b/test/t/geom/test_geos.cpp
@@ -1,6 +1,10 @@
-#include "catch.hpp"
#include <osmium/geom/geos.hpp>
+
+#ifdef OSMIUM_WITH_GEOS
+
+#include "catch.hpp"
+
#include <osmium/geom/mercator_projection.hpp>
#include "area_helper.hpp"
@@ -9,7 +13,7 @@
TEST_CASE("GEOS geometry factory - create point") {
osmium::geom::GEOSFactory<> factory;
- std::unique_ptr<geos::geom::Point> point {factory.create_point(osmium::Location(3.2, 4.2))};
+ const std::unique_ptr<geos::geom::Point> point{factory.create_point(osmium::Location{3.2, 4.2})};
REQUIRE(3.2 == point->getX());
REQUIRE(4.2 == point->getY());
REQUIRE(4326 == point->getSRID());
@@ -18,7 +22,7 @@ TEST_CASE("GEOS geometry factory - create point") {
TEST_CASE("GEOS geometry factory - create point in web mercator") {
osmium::geom::GEOSFactory<osmium::geom::MercatorProjection> factory;
- std::unique_ptr<geos::geom::Point> point {factory.create_point(osmium::Location(3.2, 4.2))};
+ const std::unique_ptr<geos::geom::Point> point{factory.create_point(osmium::Location{3.2, 4.2})};
REQUIRE(Approx(356222.3705384755l) == point->getX());
REQUIRE(Approx(467961.143605213l) == point->getY());
REQUIRE(3857 == point->getSRID());
@@ -26,9 +30,9 @@ TEST_CASE("GEOS geometry factory - create point in web mercator") {
TEST_CASE("GEOS geometry factory - create point with externally created GEOS factory") {
geos::geom::GeometryFactory geos_factory;
- osmium::geom::GEOSFactory<> factory(geos_factory);
+ osmium::geom::GEOSFactory<> factory{geos_factory};
- std::unique_ptr<geos::geom::Point> point {factory.create_point(osmium::Location(3.2, 4.2))};
+ const std::unique_ptr<geos::geom::Point> point{factory.create_point(osmium::Location{3.2, 4.2})};
REQUIRE(3.2 == point->getX());
REQUIRE(4.2 == point->getY());
REQUIRE(0 == point->getSRID());
@@ -37,45 +41,45 @@ 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{}), osmium::invalid_location);
}
TEST_CASE("GEOS geometry factory - create linestring") {
osmium::geom::GEOSFactory<> factory;
- osmium::memory::Buffer buffer(10000);
- auto &wnl = create_test_wnl_okay(buffer);
+ osmium::memory::Buffer buffer{10000};
+ const auto& wnl = create_test_wnl_okay(buffer);
SECTION("from way node list") {
- std::unique_ptr<geos::geom::LineString> linestring {factory.create_linestring(wnl)};
+ const std::unique_ptr<geos::geom::LineString> linestring{factory.create_linestring(wnl)};
REQUIRE(3 == linestring->getNumPoints());
- std::unique_ptr<geos::geom::Point> p0 = std::unique_ptr<geos::geom::Point>(linestring->getPointN(0));
+ const auto p0 = std::unique_ptr<geos::geom::Point>(linestring->getPointN(0));
REQUIRE(3.2 == p0->getX());
- std::unique_ptr<geos::geom::Point> p2 = std::unique_ptr<geos::geom::Point>(linestring->getPointN(2));
+ const auto p2 = std::unique_ptr<geos::geom::Point>(linestring->getPointN(2));
REQUIRE(3.6 == p2->getX());
}
SECTION("without duplicates and backwards") {
- std::unique_ptr<geos::geom::LineString> linestring {factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward)};
+ const std::unique_ptr<geos::geom::LineString> linestring{factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward)};
REQUIRE(3 == linestring->getNumPoints());
- std::unique_ptr<geos::geom::Point> p0 = std::unique_ptr<geos::geom::Point>(linestring->getPointN(0));
+ const auto p0 = std::unique_ptr<geos::geom::Point>(linestring->getPointN(0));
REQUIRE(3.6 == p0->getX());
- std::unique_ptr<geos::geom::Point> p2 = std::unique_ptr<geos::geom::Point>(linestring->getPointN(2));
+ const auto p2 = std::unique_ptr<geos::geom::Point>(linestring->getPointN(2));
REQUIRE(3.2 == p2->getX());
}
SECTION("with duplicates") {
- std::unique_ptr<geos::geom::LineString> linestring {factory.create_linestring(wnl, osmium::geom::use_nodes::all)};
+ const std::unique_ptr<geos::geom::LineString> linestring{factory.create_linestring(wnl, osmium::geom::use_nodes::all)};
REQUIRE(4 == linestring->getNumPoints());
- std::unique_ptr<geos::geom::Point> p0 = std::unique_ptr<geos::geom::Point>(linestring->getPointN(0));
+ const auto p0 = std::unique_ptr<geos::geom::Point>(linestring->getPointN(0));
REQUIRE(3.2 == p0->getX());
}
SECTION("with duplicates and backwards") {
- std::unique_ptr<geos::geom::LineString> linestring {factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward)};
+ const std::unique_ptr<geos::geom::LineString> linestring{factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward)};
REQUIRE(4 == linestring->getNumPoints());
- std::unique_ptr<geos::geom::Point> p0 = std::unique_ptr<geos::geom::Point>(linestring->getPointN(0));
+ const auto p0 = std::unique_ptr<geos::geom::Point>(linestring->getPointN(0));
REQUIRE(3.6 == p0->getX());
}
}
@@ -83,10 +87,10 @@ TEST_CASE("GEOS geometry factory - create linestring") {
TEST_CASE("GEOS geometry factory - create area with one outer and no inner rings") {
osmium::geom::GEOSFactory<> factory;
- osmium::memory::Buffer buffer(10000);
+ osmium::memory::Buffer buffer{10000};
const osmium::Area& area = create_test_area_1outer_0inner(buffer);
- std::unique_ptr<geos::geom::MultiPolygon> mp {factory.create_multipolygon(area)};
+ const std::unique_ptr<geos::geom::MultiPolygon> mp{factory.create_multipolygon(area)};
REQUIRE(1 == mp->getNumGeometries());
const geos::geom::Polygon* p0 = dynamic_cast<const geos::geom::Polygon*>(mp->getGeometryN(0));
@@ -96,17 +100,17 @@ TEST_CASE("GEOS geometry factory - create area with one outer and no inner rings
const geos::geom::LineString* l0e = p0->getExteriorRing();
REQUIRE(4 == l0e->getNumPoints());
- std::unique_ptr<geos::geom::Point> l0e_p0 = std::unique_ptr<geos::geom::Point>(l0e->getPointN(1));
+ const auto l0e_p0 = std::unique_ptr<geos::geom::Point>(l0e->getPointN(1));
REQUIRE(3.5 == l0e_p0->getX());
}
TEST_CASE("GEOS geometry factory - create area with one outer and one inner ring") {
osmium::geom::GEOSFactory<> factory;
- osmium::memory::Buffer buffer(10000);
+ osmium::memory::Buffer buffer{10000};
const osmium::Area& area = create_test_area_1outer_1inner(buffer);
- std::unique_ptr<geos::geom::MultiPolygon> mp {factory.create_multipolygon(area)};
+ const std::unique_ptr<geos::geom::MultiPolygon> mp{factory.create_multipolygon(area)};
REQUIRE(1 == mp->getNumGeometries());
const geos::geom::Polygon* p0 = dynamic_cast<const geos::geom::Polygon*>(mp->getGeometryN(0));
@@ -123,10 +127,10 @@ TEST_CASE("GEOS geometry factory - create area with one outer and one inner ring
TEST_CASE("GEOS geometry factory - create area with two outer and two inner rings") {
osmium::geom::GEOSFactory<> factory;
- osmium::memory::Buffer buffer(10000);
+ osmium::memory::Buffer buffer{10000};
const osmium::Area& area = create_test_area_2outer_2inner(buffer);
- std::unique_ptr<geos::geom::MultiPolygon> mp {factory.create_multipolygon(area)};
+ const std::unique_ptr<geos::geom::MultiPolygon> mp{factory.create_multipolygon(area)};
REQUIRE(2 == mp->getNumGeometries());
const geos::geom::Polygon* p0 = dynamic_cast<const geos::geom::Polygon*>(mp->getGeometryN(0));
@@ -144,3 +148,5 @@ TEST_CASE("GEOS geometry factory - create area with two outer and two inner ring
REQUIRE(5 == l1e->getNumPoints());
}
+#endif
+
diff --git a/test/t/geom/test_geos_wkb.cpp b/test/t/geom/test_geos_wkb.cpp
deleted file mode 100644
index 1fca63b..0000000
--- a/test/t/geom/test_geos_wkb.cpp
+++ /dev/null
@@ -1,92 +0,0 @@
-#include "catch.hpp"
-
-#include <osmium/geom/geos.hpp>
-#include <osmium/geom/wkb.hpp>
-
-#include "helper.hpp"
-#include "area_helper.hpp"
-#include "wnl_helper.hpp"
-
-TEST_CASE("WKB_Geometry_with_GEOS") {
-
-SECTION("point") {
- osmium::geom::WKBFactory<> wkb_factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
- osmium::geom::GEOSFactory<> geos_factory;
-
- std::string wkb {wkb_factory.create_point(osmium::Location(3.2, 4.2))};
-
- std::unique_ptr<geos::geom::Point> geos_point = geos_factory.create_point(osmium::Location(3.2, 4.2));
- REQUIRE(geos_to_wkb(geos_point.get()) == wkb);
-}
-
-
-SECTION("linestring") {
- osmium::geom::WKBFactory<> wkb_factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
- osmium::geom::GEOSFactory<> geos_factory;
-
- osmium::memory::Buffer buffer(10000);
- auto &wnl = create_test_wnl_okay(buffer);
-
- {
- std::string wkb = wkb_factory.create_linestring(wnl);
- std::unique_ptr<geos::geom::LineString> geos = geos_factory.create_linestring(wnl);
- REQUIRE(geos_to_wkb(geos.get()) == wkb);
- }
-
- {
- std::string wkb = wkb_factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward);
- std::unique_ptr<geos::geom::LineString> geos = geos_factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward);
- REQUIRE(geos_to_wkb(geos.get()) == wkb);
- }
-
- {
- std::string wkb = wkb_factory.create_linestring(wnl, osmium::geom::use_nodes::all);
- std::unique_ptr<geos::geom::LineString> geos = geos_factory.create_linestring(wnl, osmium::geom::use_nodes::all);
- REQUIRE(geos_to_wkb(geos.get()) == wkb);
- }
-
- {
- std::string wkb = wkb_factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward);
- std::unique_ptr<geos::geom::LineString> geos = geos_factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward);
- REQUIRE(geos_to_wkb(geos.get()) == wkb);
- }
-}
-
-SECTION("area_1outer_0inner") {
- osmium::geom::WKBFactory<> wkb_factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
- osmium::geom::GEOSFactory<> geos_factory;
-
- osmium::memory::Buffer buffer(10000);
- const osmium::Area& area = create_test_area_1outer_0inner(buffer);
-
- std::string wkb = wkb_factory.create_multipolygon(area);
- std::unique_ptr<geos::geom::MultiPolygon> geos = geos_factory.create_multipolygon(area);
- REQUIRE(geos_to_wkb(geos.get()) == wkb);
-}
-
-SECTION("area_1outer_1inner") {
- osmium::geom::WKBFactory<> wkb_factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
- osmium::geom::GEOSFactory<> geos_factory;
-
- osmium::memory::Buffer buffer(10000);
- const osmium::Area& area = create_test_area_1outer_1inner(buffer);
-
- std::string wkb = wkb_factory.create_multipolygon(area);
- std::unique_ptr<geos::geom::MultiPolygon> geos = geos_factory.create_multipolygon(area);
- REQUIRE(geos_to_wkb(geos.get()) == wkb);
-}
-
-SECTION("area_2outer_2inner") {
- osmium::geom::WKBFactory<> wkb_factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
- osmium::geom::GEOSFactory<> geos_factory;
-
- osmium::memory::Buffer buffer(10000);
- const osmium::Area& area = create_test_area_2outer_2inner(buffer);
-
- std::string wkb = wkb_factory.create_multipolygon(area);
- std::unique_ptr<geos::geom::MultiPolygon> geos = geos_factory.create_multipolygon(area);
- REQUIRE(geos_to_wkb(geos.get()) == wkb);
-}
-
-}
-
diff --git a/test/t/geom/test_ogr.cpp b/test/t/geom/test_ogr.cpp
index 3490c57..5e03082 100644
--- a/test/t/geom/test_ogr.cpp
+++ b/test/t/geom/test_ogr.cpp
@@ -5,121 +5,115 @@
#include "area_helper.hpp"
#include "wnl_helper.hpp"
-TEST_CASE("OGR_Geometry") {
-
-SECTION("point") {
+TEST_CASE("OGR point geometry") {
osmium::geom::OGRFactory<> factory;
- std::unique_ptr<OGRPoint> point {factory.create_point(osmium::Location(3.2, 4.2))};
- REQUIRE(3.2 == point->getX());
- REQUIRE(4.2 == point->getY());
-}
+ SECTION("point") {
+ std::unique_ptr<OGRPoint> point{factory.create_point(osmium::Location{3.2, 4.2})};
+ REQUIRE(3.2 == point->getX());
+ REQUIRE(4.2 == point->getY());
+ }
-SECTION("empty_point") {
- osmium::geom::OGRFactory<> factory;
+ SECTION("empty_point") {
+ REQUIRE_THROWS_AS(factory.create_point(osmium::Location()), osmium::invalid_location);
+ }
- REQUIRE_THROWS_AS(factory.create_point(osmium::Location()), osmium::invalid_location);
}
-SECTION("linestring") {
+TEST_CASE("OGR linestring geometry") {
osmium::geom::OGRFactory<> factory;
+ osmium::memory::Buffer buffer{10000};
+ const auto& wnl = create_test_wnl_okay(buffer);
- osmium::memory::Buffer buffer(10000);
- auto &wnl = create_test_wnl_okay(buffer);
-
- {
- std::unique_ptr<OGRLineString> linestring {factory.create_linestring(wnl)};
+ SECTION("linestring, default") {
+ std::unique_ptr<OGRLineString> linestring{factory.create_linestring(wnl)};
REQUIRE(3 == linestring->getNumPoints());
REQUIRE(3.2 == linestring->getX(0));
REQUIRE(3.6 == linestring->getX(2));
}
- {
- std::unique_ptr<OGRLineString> linestring {factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward)};
+ SECTION("linestring, unique nodes, backwards") {
+ std::unique_ptr<OGRLineString> linestring{factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward)};
REQUIRE(3 == linestring->getNumPoints());
REQUIRE(3.6 == linestring->getX(0));
REQUIRE(3.2 == linestring->getX(2));
}
- {
- std::unique_ptr<OGRLineString> linestring {factory.create_linestring(wnl, osmium::geom::use_nodes::all)};
+ SECTION("linestring, all nodes") {
+ std::unique_ptr<OGRLineString> linestring{factory.create_linestring(wnl, osmium::geom::use_nodes::all)};
REQUIRE(4 == linestring->getNumPoints());
REQUIRE(3.2 == linestring->getX(0));
}
- {
- std::unique_ptr<OGRLineString> linestring {factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward)};
+ SECTION("linestring, all nodes, backwards") {
+ std::unique_ptr<OGRLineString> linestring{factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward)};
REQUIRE(4 == linestring->getNumPoints());
REQUIRE(3.6 == linestring->getX(0));
}
+
}
-SECTION("area_1outer_0inner") {
+TEST_CASE("OGR area geometry") {
osmium::geom::OGRFactory<> factory;
+ osmium::memory::Buffer buffer{10000};
- osmium::memory::Buffer buffer(10000);
- const osmium::Area& area = create_test_area_1outer_0inner(buffer);
+ SECTION("area_1outer_0inner") {
+ const osmium::Area& area = create_test_area_1outer_0inner(buffer);
- std::unique_ptr<OGRMultiPolygon> mp {factory.create_multipolygon(area)};
- REQUIRE(1 == mp->getNumGeometries());
+ std::unique_ptr<OGRMultiPolygon> mp {factory.create_multipolygon(area)};
+ REQUIRE(1 == mp->getNumGeometries());
- const OGRPolygon* p0 = dynamic_cast<const OGRPolygon*>(mp->getGeometryRef(0));
- REQUIRE(p0);
- REQUIRE(0 == p0->getNumInteriorRings());
+ const OGRPolygon* p0 = dynamic_cast<const OGRPolygon*>(mp->getGeometryRef(0));
+ REQUIRE(p0);
+ REQUIRE(0 == p0->getNumInteriorRings());
- const OGRLineString* l0e = p0->getExteriorRing();
- REQUIRE(4 == l0e->getNumPoints());
-
- REQUIRE(3.5 == l0e->getX(1));
-}
+ const OGRLineString* l0e = p0->getExteriorRing();
+ REQUIRE(4 == l0e->getNumPoints());
-SECTION("area_1outer_1inner") {
- osmium::geom::OGRFactory<> factory;
-
- osmium::memory::Buffer buffer(10000);
- const osmium::Area& area = create_test_area_1outer_1inner(buffer);
+ REQUIRE(3.5 == l0e->getX(1));
+ }
- std::unique_ptr<OGRMultiPolygon> mp {factory.create_multipolygon(area)};
- REQUIRE(1 == mp->getNumGeometries());
+ SECTION("area_1outer_1inner") {
+ const osmium::Area& area = create_test_area_1outer_1inner(buffer);
- const OGRPolygon* p0 = dynamic_cast<const OGRPolygon*>(mp->getGeometryRef(0));
- REQUIRE(p0);
- REQUIRE(1 == p0->getNumInteriorRings());
+ std::unique_ptr<OGRMultiPolygon> mp {factory.create_multipolygon(area)};
+ REQUIRE(1 == mp->getNumGeometries());
- const OGRLineString* l0e = p0->getExteriorRing();
- REQUIRE(5 == l0e->getNumPoints());
+ const OGRPolygon* p0 = dynamic_cast<const OGRPolygon*>(mp->getGeometryRef(0));
+ REQUIRE(p0);
+ REQUIRE(1 == p0->getNumInteriorRings());
- const OGRLineString* l0i0 = p0->getInteriorRing(0);
- REQUIRE(5 == l0i0->getNumPoints());
-}
+ const OGRLineString* l0e = p0->getExteriorRing();
+ REQUIRE(5 == l0e->getNumPoints());
-SECTION("area_2outer_2inner") {
- osmium::geom::OGRFactory<> factory;
+ const OGRLineString* l0i0 = p0->getInteriorRing(0);
+ REQUIRE(5 == l0i0->getNumPoints());
+ }
- osmium::memory::Buffer buffer(10000);
- const osmium::Area& area = create_test_area_2outer_2inner(buffer);
+ SECTION("area_2outer_2inner") {
+ const osmium::Area& area = create_test_area_2outer_2inner(buffer);
- std::unique_ptr<OGRMultiPolygon> mp {factory.create_multipolygon(area)};
- REQUIRE(2 == mp->getNumGeometries());
+ std::unique_ptr<OGRMultiPolygon> mp {factory.create_multipolygon(area)};
+ REQUIRE(2 == mp->getNumGeometries());
- const OGRPolygon* p0 = dynamic_cast<const OGRPolygon*>(mp->getGeometryRef(0));
- REQUIRE(p0);
- REQUIRE(2 == p0->getNumInteriorRings());
+ const OGRPolygon* p0 = dynamic_cast<const OGRPolygon*>(mp->getGeometryRef(0));
+ REQUIRE(p0);
+ REQUIRE(2 == p0->getNumInteriorRings());
- const OGRLineString* l0e = p0->getExteriorRing();
- REQUIRE(5 == l0e->getNumPoints());
+ const OGRLineString* l0e = p0->getExteriorRing();
+ REQUIRE(5 == l0e->getNumPoints());
- const OGRPolygon* p1 = dynamic_cast<const OGRPolygon*>(mp->getGeometryRef(1));
- REQUIRE(p1);
- REQUIRE(0 == p1->getNumInteriorRings());
+ const OGRPolygon* p1 = dynamic_cast<const OGRPolygon*>(mp->getGeometryRef(1));
+ REQUIRE(p1);
+ REQUIRE(0 == p1->getNumInteriorRings());
- const OGRLineString* l1e = p1->getExteriorRing();
- REQUIRE(5 == l1e->getNumPoints());
-}
+ const OGRLineString* l1e = p1->getExteriorRing();
+ REQUIRE(5 == l1e->getNumPoints());
+ }
}
diff --git a/test/t/geom/test_ogr_wkb.cpp b/test/t/geom/test_ogr_wkb.cpp
new file mode 100644
index 0000000..548d143
--- /dev/null
+++ b/test/t/geom/test_ogr_wkb.cpp
@@ -0,0 +1,100 @@
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+#include "catch.hpp"
+
+#include <memory>
+#include <sstream>
+#include <string>
+
+#include <osmium/geom/ogr.hpp>
+#include <osmium/geom/wkb.hpp>
+
+#include "area_helper.hpp"
+#include "wnl_helper.hpp"
+
+std::string to_wkb(const OGRGeometry* geometry) {
+ std::string buffer;
+ buffer.resize(geometry->WkbSize());
+
+ geometry->exportToWkb(wkbNDR, const_cast<unsigned char*>(reinterpret_cast<const unsigned char*>(buffer.data())));
+
+ return buffer;
+}
+
+TEST_CASE("compare WKB point against GDAL/OGR") {
+ osmium::geom::WKBFactory<> wkb_factory{osmium::geom::wkb_type::wkb};
+ osmium::geom::OGRFactory<> ogr_factory;
+
+ osmium::Location loc{3.2, 4.2};
+ const std::string wkb{wkb_factory.create_point(loc)};
+ const std::unique_ptr<OGRPoint> geometry = ogr_factory.create_point(loc);
+ REQUIRE(to_wkb(geometry.get()) == wkb);
+}
+
+TEST_CASE("compare WKB linestring against GDAL/OGR") {
+ osmium::geom::WKBFactory<> wkb_factory{osmium::geom::wkb_type::wkb};
+ osmium::geom::OGRFactory<> ogr_factory;
+ osmium::memory::Buffer buffer{10000};
+
+ const auto& wnl = create_test_wnl_okay(buffer);
+
+ SECTION("linestring") {
+ const std::string wkb{wkb_factory.create_linestring(wnl)};
+ const std::unique_ptr<OGRLineString> geometry = ogr_factory.create_linestring(wnl);
+ REQUIRE(to_wkb(geometry.get()) == wkb);
+ }
+
+ SECTION("linestring, unique nodes, backwards") {
+ const std::string wkb{wkb_factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward)};
+ const std::unique_ptr<OGRLineString> geometry = ogr_factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward);
+ REQUIRE(to_wkb(geometry.get()) == wkb);
+ }
+
+ SECTION("linestring, all nodes, forwards") {
+ const std::string wkb{wkb_factory.create_linestring(wnl, osmium::geom::use_nodes::all)};
+ const std::unique_ptr<OGRLineString> geometry = ogr_factory.create_linestring(wnl, osmium::geom::use_nodes::all);
+ REQUIRE(to_wkb(geometry.get()) == wkb);
+ }
+
+ SECTION("linestring, all nodes, backwards") {
+ const std::string wkb{wkb_factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward)};
+ const std::unique_ptr<OGRLineString> geometry = ogr_factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward);
+ REQUIRE(to_wkb(geometry.get()) == wkb);
+ }
+
+}
+
+TEST_CASE("compare WKB area against GDAL/OGR") {
+ osmium::geom::WKBFactory<> wkb_factory{osmium::geom::wkb_type::wkb};
+ osmium::geom::OGRFactory<> ogr_factory;
+ osmium::memory::Buffer buffer{10000};
+
+ SECTION("area_1outer_0inner") {
+ const osmium::Area& area = create_test_area_1outer_0inner(buffer);
+
+ const std::string wkb{wkb_factory.create_multipolygon(area)};
+ const std::unique_ptr<OGRMultiPolygon> geometry = ogr_factory.create_multipolygon(area);
+ REQUIRE(to_wkb(geometry.get()) == wkb);
+ }
+
+ SECTION("area_1outer_1inner") {
+ const osmium::Area& area = create_test_area_1outer_1inner(buffer);
+
+ const std::string wkb{wkb_factory.create_multipolygon(area)};
+ const std::unique_ptr<OGRMultiPolygon> geometry = ogr_factory.create_multipolygon(area);
+ REQUIRE(to_wkb(geometry.get()) == wkb);
+ }
+
+ SECTION("area_2outer_2inner") {
+ const osmium::Area& area = create_test_area_2outer_2inner(buffer);
+
+ const std::string wkb{wkb_factory.create_multipolygon(area)};
+ const std::unique_ptr<OGRMultiPolygon> geometry = ogr_factory.create_multipolygon(area);
+ REQUIRE(to_wkb(geometry.get()) == wkb);
+ }
+
+}
+
+#endif
+
diff --git a/test/t/geom/test_projection.cpp b/test/t/geom/test_projection.cpp
index 5885410..14df3bf 100644
--- a/test/t/geom/test_projection.cpp
+++ b/test/t/geom/test_projection.cpp
@@ -6,144 +6,121 @@
#include <osmium/geom/mercator_projection.hpp>
#include <osmium/geom/projection.hpp>
-TEST_CASE("Projection") {
-
-SECTION("identity_projection") {
+TEST_CASE("Indentity Projection") {
osmium::geom::IdentityProjection projection;
REQUIRE(4326 == projection.epsg());
REQUIRE("+proj=longlat +datum=WGS84 +no_defs" == projection.proj_string());
}
-SECTION("project_location_4326") {
- osmium::geom::Projection projection(4326);
+TEST_CASE("Projection 4326") {
+ osmium::geom::Projection projection{4326};
REQUIRE(4326 == projection.epsg());
REQUIRE("+init=epsg:4326" == projection.proj_string());
- const osmium::Location loc(1.0, 2.0);
- const osmium::geom::Coordinates c {1.0, 2.0};
+ const osmium::Location loc{1.0, 2.0};
+ const osmium::geom::Coordinates c{1.0, 2.0};
REQUIRE(c == projection(loc));
}
-SECTION("project_location_4326_string") {
- osmium::geom::Projection projection("+init=epsg:4326");
+TEST_CASE("Projection 4326 from init string") {
+ osmium::geom::Projection projection{"+init=epsg:4326"};
REQUIRE(-1 == projection.epsg());
REQUIRE("+init=epsg:4326" == projection.proj_string());
- const osmium::Location loc(1.0, 2.0);
- const osmium::geom::Coordinates c {1.0, 2.0};
+ const osmium::Location loc{1.0, 2.0};
+ const osmium::geom::Coordinates c{1.0, 2.0};
REQUIRE(c == projection(loc));
}
-SECTION("unknown_projection_string") {
- REQUIRE_THROWS_AS(osmium::geom::Projection projection("abc"), osmium::projection_error);
+TEST_CASE("Creating projection from unknown init string") {
+ REQUIRE_THROWS_AS(osmium::geom::Projection projection{"abc"}, osmium::projection_error);
}
-SECTION("unknown_epsg_code") {
- REQUIRE_THROWS_AS(osmium::geom::Projection projection(9999999), osmium::projection_error);
+TEST_CASE("Creating projection from unknown EPSG code") {
+ REQUIRE_THROWS_AS(osmium::geom::Projection projection{9999999}, osmium::projection_error);
}
-SECTION("project_location_3857") {
- osmium::geom::Projection projection(3857);
+TEST_CASE("Projection 3857") {
+ osmium::geom::Projection projection{3857};
REQUIRE(3857 == projection.epsg());
REQUIRE("+init=epsg:3857" == projection.proj_string());
- {
- const osmium::Location loc(0.0, 0.0);
- const osmium::geom::Coordinates c {0.0, 0.0};
+ SECTION("Zero coordinates") {
+ const osmium::Location loc{0.0, 0.0};
+ const osmium::geom::Coordinates c{0.0, 0.0};
REQUIRE(projection(loc).x == Approx(c.x).epsilon(0.1));
REQUIRE(projection(loc).y == Approx(c.y).epsilon(0.1));
}
- {
- const osmium::Location loc(180.0, 0.0);
- const osmium::geom::Coordinates c {20037508.34, 0.0};
+
+ SECTION("Max longitude") {
+ const osmium::Location loc{180.0, 0.0};
+ const osmium::geom::Coordinates c{20037508.34, 0.0};
REQUIRE(projection(loc).x == Approx(c.x).epsilon(0.1));
REQUIRE(projection(loc).y == Approx(c.y).epsilon(0.1));
}
- {
- const osmium::Location loc(180.0, 0.0);
- const osmium::geom::Coordinates c {20037508.34, 0.0};
+
+ SECTION("Min longitude") {
+ const osmium::Location loc{-180.0, 0.0};
+ const osmium::geom::Coordinates c{-20037508.34, 0.0};
REQUIRE(projection(loc).x == Approx(c.x).epsilon(0.1));
REQUIRE(projection(loc).y == Approx(c.y).epsilon(0.1));
}
- {
- const osmium::Location loc(0.0, 85.0511288);
- const osmium::geom::Coordinates c {0.0, 20037508.34};
+
+ SECTION("Max latitude") {
+ const osmium::Location loc{0.0, 85.0511288};
+ const osmium::geom::Coordinates c{0.0, 20037508.34};
REQUIRE(projection(loc).x == Approx(c.x).epsilon(0.1));
REQUIRE(projection(loc).y == Approx(c.y).epsilon(0.1));
}
}
-SECTION("project_location_mercator") {
+TEST_CASE("MercatorProjection") {
osmium::geom::MercatorProjection projection;
- {
- const osmium::Location loc(0.0, 0.0);
- const osmium::geom::Coordinates c {0.0, 0.0};
+ SECTION("Zero coordinates") {
+ const osmium::Location loc{0.0, 0.0};
+ const osmium::geom::Coordinates c{0.0, 0.0};
REQUIRE(projection(loc).x == Approx(c.x).epsilon(0.1));
REQUIRE(projection(loc).y == Approx(c.y).epsilon(0.1));
}
- {
- const osmium::Location loc(180.0, 0.0);
- const osmium::geom::Coordinates c {20037508.34, 0.0};
+
+ SECTION("Max longitude") {
+ const osmium::Location loc{180.0, 0.0};
+ const osmium::geom::Coordinates c{20037508.34, 0.0};
REQUIRE(projection(loc).x == Approx(c.x).epsilon(0.1));
REQUIRE(projection(loc).y == Approx(c.y).epsilon(0.1));
}
- {
- const osmium::Location loc(180.0, 0.0);
- const osmium::geom::Coordinates c {20037508.34, 0.0};
+
+ SECTION("Min longitude") {
+ const osmium::Location loc{-180.0, 0.0};
+ const osmium::geom::Coordinates c{-20037508.34, 0.0};
REQUIRE(projection(loc).x == Approx(c.x).epsilon(0.1));
REQUIRE(projection(loc).y == Approx(c.y).epsilon(0.1));
}
- {
- const osmium::Location loc(0.0, 85.0511288);
- const osmium::geom::Coordinates c {0.0, 20037508.34};
+
+ SECTION("Max latitude") {
+ const osmium::Location loc{0.0, 85.0511288};
+ const osmium::geom::Coordinates c{0.0, 20037508.34};
REQUIRE(projection(loc).x == Approx(c.x).epsilon(0.1));
REQUIRE(projection(loc).y == Approx(c.y).epsilon(0.1));
}
}
-SECTION("compare_mercators") {
+TEST_CASE("Compare mercator implementations") {
osmium::geom::MercatorProjection projection_merc;
- osmium::geom::Projection projection_3857(3857);
- REQUIRE(3857 == projection_3857.epsg());
- REQUIRE("+init=epsg:3857" == projection_3857.proj_string());
-
- {
- const osmium::Location loc(4.2, 27.3);
- REQUIRE(projection_merc(loc).x == Approx(projection_3857(loc).x).epsilon(0.1));
- REQUIRE(projection_merc(loc).y == Approx(projection_3857(loc).y).epsilon(0.1));
- }
- {
- const osmium::Location loc(160.789, -42.42);
- REQUIRE(projection_merc(loc).x == Approx(projection_3857(loc).x).epsilon(0.1));
- REQUIRE(projection_merc(loc).y == Approx(projection_3857(loc).y).epsilon(0.1));
- }
- {
- const osmium::Location loc(-0.001, 0.001);
- REQUIRE(projection_merc(loc).x == Approx(projection_3857(loc).x).epsilon(0.1));
- REQUIRE(projection_merc(loc).y == Approx(projection_3857(loc).y).epsilon(0.1));
+ osmium::geom::Projection projection_3857{3857};
+
+ SECTION("random coordinates") {
+ std::random_device rd;
+ std::mt19937 gen{rd()};
+ std::uniform_real_distribution<> dis_x{-180.0, 180.0};
+ std::uniform_real_distribution<> dis_y{-90.0, 90.0};
+
+ for (int n = 0; n < 10000; ++n) {
+ const osmium::Location loc{dis_x(gen), dis_y(gen)};
+ REQUIRE(projection_merc(loc).x == Approx(projection_3857(loc).x).epsilon(0.1));
+ REQUIRE(projection_merc(loc).y == Approx(projection_3857(loc).y).epsilon(0.1));
+ }
}
- {
- const osmium::Location loc(-85.2, -85.2);
- REQUIRE(projection_merc(loc).x == Approx(projection_3857(loc).x).epsilon(0.1));
- REQUIRE(projection_merc(loc).y == Approx(projection_3857(loc).y).epsilon(0.1));
- }
-}
-
-SECTION("compare_mercators") {
- osmium::geom::MercatorProjection projection_merc;
- osmium::geom::Projection projection_3857(3857);
-
- std::random_device rd;
- std::mt19937 gen(rd());
- std::uniform_real_distribution<> dis_x(-180.0, 180.0);
- std::uniform_real_distribution<> dis_y(-90.0, 90.0);
-
- for (int n = 0; n < 100000; ++n) {
- const osmium::Location loc(dis_x(gen), dis_y(gen));
- REQUIRE(projection_merc(loc).x == Approx(projection_3857(loc).x).epsilon(0.1));
- REQUIRE(projection_merc(loc).y == Approx(projection_3857(loc).y).epsilon(0.1));
- }
-}
}
diff --git a/test/t/geom/test_tile.cpp b/test/t/geom/test_tile.cpp
index 5454fed..953fcc7 100644
--- a/test/t/geom/test_tile.cpp
+++ b/test/t/geom/test_tile.cpp
@@ -4,8 +4,6 @@
#include <osmium/geom/tile.hpp>
-#include "helper.hpp"
-
#include "test_tile_data.hpp"
TEST_CASE("Tile from x0.0 y0.0 at zoom 0") {
diff --git a/test/t/geom/test_wkb.cpp b/test/t/geom/test_wkb.cpp
index d4d9228..66dd42e 100644
--- a/test/t/geom/test_wkb.cpp
+++ b/test/t/geom/test_wkb.cpp
@@ -10,28 +10,28 @@ TEST_CASE("WKB geometry factory (byte-order-dependant), points") {
const osmium::Location loc{3.2, 4.2};
SECTION("point") {
- osmium::geom::WKBFactory<> factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
+ osmium::geom::WKBFactory<> factory{osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex};
const std::string wkb{factory.create_point(loc)};
REQUIRE(wkb == "01010000009A99999999990940CDCCCCCCCCCC1040");
}
SECTION("point in web mercator") {
- osmium::geom::WKBFactory<osmium::geom::MercatorProjection> factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
+ osmium::geom::WKBFactory<osmium::geom::MercatorProjection> factory{osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex};
const std::string wkb{factory.create_point(loc)};
REQUIRE(wkb == "010100000028706E7BF9BD1541B03E0D93E48F1C41");
}
SECTION("point in ewkb") {
- osmium::geom::WKBFactory<> factory(osmium::geom::wkb_type::ewkb, osmium::geom::out_type::hex);
+ osmium::geom::WKBFactory<> factory{osmium::geom::wkb_type::ewkb, osmium::geom::out_type::hex};
const std::string wkb{factory.create_point(loc)};
REQUIRE(wkb == "0101000020E61000009A99999999990940CDCCCCCCCCCC1040");
}
SECTION("point in ewkb in web mercator") {
- osmium::geom::WKBFactory<osmium::geom::MercatorProjection> factory(osmium::geom::wkb_type::ewkb, osmium::geom::out_type::hex);
+ osmium::geom::WKBFactory<osmium::geom::MercatorProjection> factory{osmium::geom::wkb_type::ewkb, osmium::geom::out_type::hex};
const std::string wkb{factory.create_point(loc)};
REQUIRE(wkb == "0101000020110F000028706E7BF9BD1541B03E0D93E48F1C41");
@@ -44,7 +44,7 @@ TEST_CASE("WKB geometry factory (byte-order-dependant)") {
osmium::memory::Buffer buffer{10000};
SECTION("linestring") {
- osmium::geom::WKBFactory<> factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
+ osmium::geom::WKBFactory<> factory{osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex};
const auto& wnl = create_test_wnl_okay(buffer);
{
@@ -69,7 +69,7 @@ TEST_CASE("WKB geometry factory (byte-order-dependant)") {
}
SECTION("linestring as ewkb") {
- osmium::geom::WKBFactory<> factory(osmium::geom::wkb_type::ewkb, osmium::geom::out_type::hex);
+ osmium::geom::WKBFactory<> factory{osmium::geom::wkb_type::ewkb, osmium::geom::out_type::hex};
const auto& wnl = create_test_wnl_okay(buffer);
@@ -78,7 +78,7 @@ TEST_CASE("WKB geometry factory (byte-order-dependant)") {
}
SECTION("linestring with two same locations") {
- osmium::geom::WKBFactory<> factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
+ osmium::geom::WKBFactory<> factory{osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex};
const auto& wnl = create_test_wnl_same_location(buffer);
@@ -102,7 +102,7 @@ TEST_CASE("WKB geometry factory (byte-order-dependant)") {
}
SECTION("linestring with undefined location") {
- osmium::geom::WKBFactory<> factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
+ osmium::geom::WKBFactory<> factory{osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex};
const auto& wnl = create_test_wnl_undefined_location(buffer);
@@ -115,7 +115,7 @@ TEST_CASE("WKB geometry factory (byte-order-dependant)") {
TEST_CASE("WKB geometry (byte-order-independent)") {
- osmium::geom::WKBFactory<> factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
+ 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);
diff --git a/test/t/geom/wnl_helper.hpp b/test/t/geom/wnl_helper.hpp
index 91ac114..68de4c3 100644
--- a/test/t/geom/wnl_helper.hpp
+++ b/test/t/geom/wnl_helper.hpp
@@ -6,7 +6,7 @@
using namespace osmium::builder::attr;
inline const osmium::WayNodeList& create_test_wnl_okay(osmium::memory::Buffer& buffer) {
- auto pos = osmium::builder::add_way_node_list(buffer, _nodes({
+ const auto pos = osmium::builder::add_way_node_list(buffer, _nodes({
{1, {3.2, 4.2}},
{3, {3.5, 4.7}},
{4, {3.5, 4.7}},
@@ -25,7 +25,7 @@ inline const osmium::WayNodeList& create_test_wnl_empty(osmium::memory::Buffer&
}
inline const osmium::WayNodeList& create_test_wnl_same_location(osmium::memory::Buffer& buffer) {
- auto pos = osmium::builder::add_way_node_list(buffer, _nodes({
+ const auto pos = osmium::builder::add_way_node_list(buffer, _nodes({
{1, {3.5, 4.7}},
{2, {3.5, 4.7}}
}));
@@ -34,7 +34,7 @@ inline const osmium::WayNodeList& create_test_wnl_same_location(osmium::memory::
}
inline const osmium::WayNodeList& create_test_wnl_undefined_location(osmium::memory::Buffer& buffer) {
- auto pos = osmium::builder::add_way_node_list(buffer, _nodes({
+ const auto pos = osmium::builder::add_way_node_list(buffer, _nodes({
{1, {3.5, 4.7}},
{2, osmium::Location()}
}));
diff --git a/test/t/index/test_id_set.cpp b/test/t/index/test_id_set.cpp
new file mode 100644
index 0000000..4c24447
--- /dev/null
+++ b/test/t/index/test_id_set.cpp
@@ -0,0 +1,166 @@
+
+#include "catch.hpp"
+
+#include <osmium/index/id_set.hpp>
+#include <osmium/osm/types.hpp>
+
+TEST_CASE("Basic functionality of IdSetDense") {
+ osmium::index::IdSetDense<osmium::unsigned_object_id_type> s;
+
+ REQUIRE_FALSE(s.get(17));
+ REQUIRE_FALSE(s.get(28));
+ REQUIRE(s.empty());
+ REQUIRE(s.size() == 0);
+
+ s.set(17);
+ REQUIRE(s.get(17));
+ REQUIRE_FALSE(s.get(28));
+ REQUIRE_FALSE(s.empty());
+ REQUIRE(s.size() == 1);
+
+ s.set(28);
+ REQUIRE(s.get(17));
+ REQUIRE(s.get(28));
+ REQUIRE_FALSE(s.empty());
+ REQUIRE(s.size() == 2);
+
+ s.set(17);
+ REQUIRE(s.get(17));
+ REQUIRE(s.size() == 2);
+
+ REQUIRE_FALSE(s.check_and_set(17));
+ REQUIRE(s.get(17));
+ REQUIRE(s.size() == 2);
+
+ s.unset(17);
+ REQUIRE_FALSE(s.get(17));
+ REQUIRE(s.size() == 1);
+
+ REQUIRE(s.check_and_set(32));
+ REQUIRE(s.get(32));
+ REQUIRE(s.size() == 2);
+
+ s.clear();
+ REQUIRE(s.empty());
+ REQUIRE(s.size() == 0);
+}
+
+TEST_CASE("Iterating over IdSetDense") {
+ osmium::index::IdSetDense<osmium::unsigned_object_id_type> s;
+ s.set(7);
+ s.set(35);
+ s.set(35);
+ s.set(20);
+ s.set(1LL << 33);
+ s.set(21);
+ s.set((1LL << 27) + 13);
+
+ REQUIRE(s.size() == 6);
+
+ auto it = s.begin();
+ REQUIRE(it != s.end());
+ REQUIRE(*it == 7);
+ ++it;
+ REQUIRE(it != s.end());
+ REQUIRE(*it == 20);
+ ++it;
+ REQUIRE(it != s.end());
+ REQUIRE(*it == 21);
+ ++it;
+ REQUIRE(it != s.end());
+ REQUIRE(*it == 35);
+ ++it;
+ REQUIRE(it != s.end());
+ REQUIRE(*it == (1LL << 27) + 13);
+ ++it;
+ REQUIRE(it != s.end());
+ REQUIRE(*it == 1LL << 33);
+ ++it;
+ REQUIRE(it == s.end());
+}
+
+TEST_CASE("Test with larger Ids") {
+ osmium::index::IdSetDense<osmium::unsigned_object_id_type> s;
+
+ const osmium::unsigned_object_id_type start = 25;
+ const osmium::unsigned_object_id_type end = 100000000;
+ const osmium::unsigned_object_id_type step = 123456;
+
+ for (osmium::unsigned_object_id_type i = start; i < end; i += step) {
+ s.set(i);
+ }
+
+ for (osmium::unsigned_object_id_type i = start; i < end; i += step) {
+ REQUIRE(s.get(i));
+ REQUIRE_FALSE(s.get(i + 1));
+ }
+}
+
+TEST_CASE("Large gap") {
+ osmium::index::IdSetDense<osmium::unsigned_object_id_type> s;
+
+ s.set(3);
+ s.set(1 << 30);
+
+ REQUIRE(s.get(1 << 30));
+ REQUIRE_FALSE(s.get(1 << 29));
+}
+
+TEST_CASE("Basic functionality of IdSetSmall") {
+ osmium::index::IdSetSmall<osmium::unsigned_object_id_type> s;
+
+ REQUIRE_FALSE(s.get(17));
+ REQUIRE_FALSE(s.get(28));
+ REQUIRE(s.empty());
+
+ s.set(17);
+ REQUIRE(s.get(17));
+ REQUIRE_FALSE(s.get(28));
+ REQUIRE_FALSE(s.empty());
+
+ s.set(28);
+ REQUIRE(s.get(17));
+ REQUIRE(s.get(28));
+ REQUIRE_FALSE(s.empty());
+
+ s.clear();
+ REQUIRE(s.empty());
+}
+
+TEST_CASE("Iterating over IdSetSmall") {
+ osmium::index::IdSetSmall<osmium::unsigned_object_id_type> s;
+ s.set(7);
+ s.set(35);
+ s.set(35);
+ s.set(20);
+ s.set(1LL << 33);
+ s.set(21);
+ s.set((1LL << 27) + 13);
+
+ // needs to be called before size() and iterator will work properly
+ s.sort_unique();
+
+ REQUIRE(s.size() == 6);
+
+ auto it = s.begin();
+ REQUIRE(it != s.end());
+ REQUIRE(*it == 7);
+ ++it;
+ REQUIRE(it != s.end());
+ REQUIRE(*it == 20);
+ ++it;
+ REQUIRE(it != s.end());
+ REQUIRE(*it == 21);
+ ++it;
+ REQUIRE(it != s.end());
+ REQUIRE(*it == 35);
+ ++it;
+ REQUIRE(it != s.end());
+ REQUIRE(*it == (1LL << 27) + 13);
+ ++it;
+ REQUIRE(it != s.end());
+ REQUIRE(*it == 1LL << 33);
+ ++it;
+ REQUIRE(it == s.end());
+}
+
diff --git a/test/t/index/test_id_to_location.cpp b/test/t/index/test_id_to_location.cpp
index 810ef3b..36fc074 100644
--- a/test/t/index/test_id_to_location.cpp
+++ b/test/t/index/test_id_to_location.cpp
@@ -15,12 +15,14 @@
#include <osmium/index/node_locations_map.hpp>
+static_assert(osmium::index::empty_value<osmium::Location>() == osmium::Location{}, "Empty value for location is wrong");
+
template <typename TIndex>
void test_func_all(TIndex& index) {
- osmium::unsigned_object_id_type id1 = 12;
- osmium::unsigned_object_id_type id2 = 3;
- osmium::Location loc1{1.2, 4.5};
- osmium::Location loc2{3.5, -7.2};
+ const osmium::unsigned_object_id_type id1 = 12;
+ const osmium::unsigned_object_id_type id2 = 3;
+ 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);
@@ -33,14 +35,16 @@ void test_func_all(TIndex& index) {
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_WITH(index.get(0), "id 0 not found");
+ REQUIRE_THROWS_WITH(index.get(1), "id 1 not found");
}
template <typename TIndex>
void test_func_real(TIndex& index) {
- osmium::unsigned_object_id_type id1 = 12;
- osmium::unsigned_object_id_type id2 = 3;
- osmium::Location loc1{1.2, 4.5};
- osmium::Location loc2{3.5, -7.2};
+ const osmium::unsigned_object_id_type id1 = 12;
+ const osmium::unsigned_object_id_type id2 = 3;
+ const osmium::Location loc1{1.2, 4.5};
+ const osmium::Location loc2{3.5, -7.2};
index.set(id1, loc1);
index.set(id2, loc2);
@@ -66,115 +70,116 @@ void test_func_real(TIndex& index) {
REQUIRE_THROWS_AS(index.get(100), osmium::not_found);
}
-TEST_CASE("IdToLocation") {
-
- SECTION("Dummy") {
- using index_type = osmium::index::map::Dummy<osmium::unsigned_object_id_type, osmium::Location>;
+TEST_CASE("Map Id to location: Dummy") {
+ using index_type = osmium::index::map::Dummy<osmium::unsigned_object_id_type, osmium::Location>;
- index_type index1;
+ index_type index1;
- REQUIRE(0 == index1.size());
- REQUIRE(0 == index1.used_memory());
+ REQUIRE(0 == index1.size());
+ REQUIRE(0 == index1.used_memory());
- test_func_all<index_type>(index1);
+ test_func_all<index_type>(index1);
- REQUIRE(0 == index1.size());
- REQUIRE(0 == index1.used_memory());
- }
+ REQUIRE(0 == index1.size());
+ REQUIRE(0 == index1.used_memory());
+}
- SECTION("DenseMemArray") {
- using index_type = osmium::index::map::DenseMemArray<osmium::unsigned_object_id_type, osmium::Location>;
+TEST_CASE("Map Id to location: DenseMemArray") {
+ using index_type = osmium::index::map::DenseMemArray<osmium::unsigned_object_id_type, osmium::Location>;
- index_type index1;
- index1.reserve(1000);
- test_func_all<index_type>(index1);
+ index_type index1;
+ index1.reserve(1000);
+ test_func_all<index_type>(index1);
- index_type index2;
- index2.reserve(1000);
- test_func_real<index_type>(index2);
- }
+ index_type index2;
+ index2.reserve(1000);
+ test_func_real<index_type>(index2);
+}
#ifdef __linux__
- SECTION("DenseMmapArray") {
- using index_type = osmium::index::map::DenseMmapArray<osmium::unsigned_object_id_type, osmium::Location>;
+TEST_CASE("Map Id to location: DenseMmapArray") {
+ using index_type = osmium::index::map::DenseMmapArray<osmium::unsigned_object_id_type, osmium::Location>;
- index_type index1;
- test_func_all<index_type>(index1);
+ index_type index1;
+ test_func_all<index_type>(index1);
- index_type index2;
- test_func_real<index_type>(index2);
- }
+ index_type index2;
+ test_func_real<index_type>(index2);
+}
#else
# pragma message("not running 'DenseMapMmap' test case on this machine")
#endif
- SECTION("DenseFileArray") {
- using index_type = osmium::index::map::DenseFileArray<osmium::unsigned_object_id_type, osmium::Location>;
+TEST_CASE("Map Id to location: DenseFileArray") {
+ using index_type = osmium::index::map::DenseFileArray<osmium::unsigned_object_id_type, osmium::Location>;
- index_type index1;
- test_func_all<index_type>(index1);
+ index_type index1;
+ test_func_all<index_type>(index1);
- index_type index2;
- test_func_real<index_type>(index2);
- }
+ index_type index2;
+ test_func_real<index_type>(index2);
+}
#ifdef OSMIUM_WITH_SPARSEHASH
- SECTION("SparseMemTable") {
- using index_type = osmium::index::map::SparseMemTable<osmium::unsigned_object_id_type, osmium::Location>;
+TEST_CASE("Map Id to location: SparseMemTable") {
+ using index_type = osmium::index::map::SparseMemTable<osmium::unsigned_object_id_type, osmium::Location>;
- index_type index1;
- test_func_all<index_type>(index1);
+ index_type index1;
+ test_func_all<index_type>(index1);
- index_type index2;
- test_func_real<index_type>(index2);
- }
+ index_type index2;
+ test_func_real<index_type>(index2);
+}
#endif
- SECTION("SparseMemMap") {
- using index_type = osmium::index::map::SparseMemMap<osmium::unsigned_object_id_type, osmium::Location>;
+TEST_CASE("Map Id to location: SparseMemMap") {
+ using index_type = osmium::index::map::SparseMemMap<osmium::unsigned_object_id_type, osmium::Location>;
- index_type index1;
- test_func_all<index_type>(index1);
+ index_type index1;
+ test_func_all<index_type>(index1);
- index_type index2;
- test_func_real<index_type>(index2);
- }
+ index_type index2;
+ test_func_real<index_type>(index2);
+}
- SECTION("SparseMemArray") {
- using index_type = osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, osmium::Location>;
+TEST_CASE("Map Id to location: SparseMemArray") {
+ using index_type = osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, osmium::Location>;
- index_type index1;
+ index_type index1;
- REQUIRE(0 == index1.size());
- REQUIRE(0 == index1.used_memory());
+ REQUIRE(0 == index1.size());
+ REQUIRE(0 == index1.used_memory());
- test_func_all<index_type>(index1);
+ test_func_all<index_type>(index1);
- REQUIRE(2 == index1.size());
+ REQUIRE(2 == index1.size());
- index_type index2;
- test_func_real<index_type>(index2);
- }
+ index_type index2;
+ test_func_real<index_type>(index2);
+}
- SECTION("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();
+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);
+ const std::vector<std::string> map_type_names = map_factory.map_types();
+ REQUIRE(map_type_names.size() >= 5);
- for (const auto& map_type_name : map_type_names) {
- std::unique_ptr<map_type> index1 = map_factory.create_map(map_type_name);
- index1->reserve(1000);
- test_func_all<map_type>(*index1);
+ 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_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");
- std::unique_ptr<map_type> index2 = map_factory.create_map(map_type_name);
- index2->reserve(1000);
- test_func_real<map_type>(*index2);
- }
- }
+ for (const auto& map_type_name : map_type_names) {
+ std::unique_ptr<map_type> index1 = map_factory.create_map(map_type_name);
+ index1->reserve(1000);
+ test_func_all<map_type>(*index1);
+ std::unique_ptr<map_type> index2 = map_factory.create_map(map_type_name);
+ index2->reserve(1000);
+ test_func_real<map_type>(*index2);
+ }
}
diff --git a/test/t/io/test_compression_factory.cpp b/test/t/io/test_compression_factory.cpp
new file mode 100644
index 0000000..5428d82
--- /dev/null
+++ b/test/t/io/test_compression_factory.cpp
@@ -0,0 +1,27 @@
+
+#include "catch.hpp"
+
+#include <osmium/io/compression.hpp>
+
+TEST_CASE("Compression factory") {
+ const auto& factory = osmium::io::CompressionFactory::instance();
+
+ 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));
+ }
+
+ 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");
+ }
+
+}
+
diff --git a/test/t/io/test_reader_with_mock_parser.cpp b/test/t/io/test_reader_with_mock_parser.cpp
index c5c9975..b1076cc 100644
--- a/test/t/io/test_reader_with_mock_parser.cpp
+++ b/test/t/io/test_reader_with_mock_parser.cpp
@@ -24,9 +24,9 @@ public:
MockParser(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,
- osmium::osm_entity_bits::type read_types,
+ osmium::io::detail::reader_options options,
const std::string& fail_in) :
- Parser(input_queue, output_queue, header_promise, read_types),
+ Parser(input_queue, output_queue, header_promise, options),
m_fail_in(fail_in) {
}
@@ -59,8 +59,8 @@ TEST_CASE("Test Reader using MockParser") {
[&](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,
- osmium::osm_entity_bits::type read_which_entities) {
- return std::unique_ptr<osmium::io::detail::Parser>(new MockParser(input_queue, output_queue, header_promise, read_which_entities, fail_in));
+ osmium::io::detail::reader_options options) {
+ return std::unique_ptr<osmium::io::detail::Parser>(new MockParser(input_queue, output_queue, header_promise, options, fail_in));
});
SECTION("no failure") {
diff --git a/test/t/buffer/test_buffer_basics.cpp b/test/t/memory/test_buffer_basics.cpp
similarity index 100%
rename from test/t/buffer/test_buffer_basics.cpp
rename to test/t/memory/test_buffer_basics.cpp
diff --git a/test/t/buffer/test_buffer_node.cpp b/test/t/memory/test_buffer_node.cpp
similarity index 50%
rename from test/t/buffer/test_buffer_node.cpp
rename to test/t/memory/test_buffer_node.cpp
index ba2431b..040cbb8 100644
--- a/test/t/buffer/test_buffer_node.cpp
+++ b/test/t/memory/test_buffer_node.cpp
@@ -3,7 +3,7 @@
#include <osmium/builder/osm_object_builder.hpp>
#include <osmium/osm/node.hpp>
-void check_node_1(osmium::Node& node) {
+void check_node_1(const osmium::Node& node) {
REQUIRE(1 == node.id());
REQUIRE(3 == node.version());
REQUIRE(true == node.visible());
@@ -11,9 +11,9 @@ void check_node_1(osmium::Node& node) {
REQUIRE(21 == node.uid());
REQUIRE(123 == uint32_t(node.timestamp()));
REQUIRE(osmium::Location(3.5, 4.7) == node.location());
- REQUIRE(std::string("testuser") == node.user());
+ REQUIRE(std::string{"testuser"} == node.user());
- for (osmium::memory::Item& item : node) {
+ for (const osmium::memory::Item& item : node) {
REQUIRE(osmium::item_type::tag_list == item.type());
}
@@ -22,7 +22,7 @@ void check_node_1(osmium::Node& node) {
REQUIRE(0 == std::distance(node.tags().begin(), node.tags().end()));
}
-void check_node_2(osmium::Node& node) {
+void check_node_2(const osmium::Node& node) {
REQUIRE(2 == node.id());
REQUIRE(3 == node.version());
REQUIRE(true == node.visible());
@@ -30,9 +30,9 @@ void check_node_2(osmium::Node& node) {
REQUIRE(21 == node.uid());
REQUIRE(123 == uint32_t(node.timestamp()));
REQUIRE(osmium::Location(3.5, 4.7) == node.location());
- REQUIRE(std::string("testuser") == node.user());
+ REQUIRE(std::string{"testuser"} == node.user());
- for (osmium::memory::Item& item : node) {
+ for (const osmium::memory::Item& item : node) {
REQUIRE(osmium::item_type::tag_list == item.type());
}
@@ -61,60 +61,52 @@ TEST_CASE("Node in Buffer") {
constexpr size_t buffer_size = 10000;
unsigned char data[buffer_size];
- osmium::memory::Buffer buffer(data, buffer_size, 0);
+ osmium::memory::Buffer buffer{data, buffer_size, 0};
SECTION("Add node to buffer") {
{
// add node 1
- osmium::builder::NodeBuilder node_builder(buffer);
- osmium::Node& node = node_builder.object();
- REQUIRE(osmium::item_type::node == node.type());
-
- node.set_id(1);
- node.set_version(3);
- node.set_visible(true);
- node.set_changeset(333);
- node.set_uid(21);
- node.set_timestamp(123);
- node.set_location(osmium::Location(3.5, 4.7));
-
- node_builder.add_user("testuser");
-
- buffer.commit();
+ osmium::builder::NodeBuilder node_builder{buffer};
+
+ node_builder.set_id(1)
+ .set_version(3)
+ .set_visible(true)
+ .set_changeset(333)
+ .set_uid(21)
+ .set_timestamp(123)
+ .set_location(osmium::Location{3.5, 4.7})
+ .set_user("testuser");
}
+ buffer.commit();
+
{
// add node 2
- osmium::builder::NodeBuilder node_builder(buffer);
- osmium::Node& node = node_builder.object();
- REQUIRE(osmium::item_type::node == node.type());
-
- node.set_id(2);
- node.set_version(3);
- node.set_visible(true);
- node.set_changeset(333);
- node.set_uid(21);
- node.set_timestamp(123);
- node.set_location(osmium::Location(3.5, 4.7));
-
- node_builder.add_user("testuser");
-
- {
- osmium::builder::TagListBuilder tag_builder(buffer, &node_builder);
- tag_builder.add_tag("amenity", "bank");
- tag_builder.add_tag("name", "OSM Savings");
- }
-
- buffer.commit();
+ osmium::builder::NodeBuilder node_builder{buffer};
+
+ node_builder.set_id(2)
+ .set_version(3)
+ .set_visible(true)
+ .set_changeset(333)
+ .set_uid(21)
+ .set_timestamp(123)
+ .set_location(osmium::Location{3.5, 4.7})
+ .set_user("testuser");
+
+ osmium::builder::TagListBuilder tag_builder{node_builder};
+ tag_builder.add_tag("amenity", "bank");
+ tag_builder.add_tag("name", "OSM Savings");
}
+ buffer.commit();
+
REQUIRE(2 == std::distance(buffer.begin(), buffer.end()));
int item_no = 0;
- for (osmium::memory::Item& item : buffer) {
+ for (const osmium::memory::Item& item : buffer) {
REQUIRE(osmium::item_type::node == item.type());
- osmium::Node& node = static_cast<osmium::Node&>(item);
+ const osmium::Node& node = static_cast<const osmium::Node&>(item);
switch (item_no) {
case 0:
@@ -137,24 +129,21 @@ TEST_CASE("Node in Buffer") {
{
// add node 1
- osmium::builder::NodeBuilder node_builder(buffer);
- osmium::Node& node = node_builder.object();
- REQUIRE(osmium::item_type::node == node.type());
-
- node.set_id(1);
- node.set_version(3);
- node.set_visible(true);
- node.set_changeset(333);
- node.set_uid(21);
- node.set_timestamp(123);
- node.set_location(osmium::Location(3.5, 4.7));
-
- node_builder.add_user("testuser");
-
- buffer.commit();
+ osmium::builder::NodeBuilder node_builder{buffer};
+
+ node_builder.set_id(1)
+ .set_version(3)
+ .set_visible(true)
+ .set_changeset(333)
+ .set_uid(21)
+ .set_timestamp(123)
+ .set_location(osmium::Location{3.5, 4.7})
+ .set_user("testuser");
}
- osmium::memory::Buffer buffer2(buffer_size, osmium::memory::Buffer::auto_grow::yes);
+ buffer.commit();
+
+ osmium::memory::Buffer buffer2{buffer_size, osmium::memory::Buffer::auto_grow::yes};
buffer2.add_buffer(buffer);
buffer2.commit();
@@ -169,24 +158,21 @@ TEST_CASE("Node in Buffer") {
{
// add node 1
- osmium::builder::NodeBuilder node_builder(buffer);
- osmium::Node& node = node_builder.object();
- REQUIRE(osmium::item_type::node == node.type());
-
- node.set_id(1);
- node.set_version(3);
- node.set_visible(true);
- node.set_changeset(333);
- node.set_uid(21);
- node.set_timestamp(123);
- node.set_location(osmium::Location(3.5, 4.7));
-
- node_builder.add_user("testuser");
-
- buffer.commit();
+ osmium::builder::NodeBuilder node_builder{buffer};
+
+ node_builder.set_id(1)
+ .set_version(3)
+ .set_visible(true)
+ .set_changeset(333)
+ .set_uid(21)
+ .set_timestamp(123)
+ .set_location(osmium::Location{3.5, 4.7})
+ .set_user("testuser");
}
- osmium::memory::Buffer buffer2(buffer_size, osmium::memory::Buffer::auto_grow::yes);
+ buffer.commit();
+
+ osmium::memory::Buffer buffer2{buffer_size, osmium::memory::Buffer::auto_grow::yes};
std::copy(buffer.begin(), buffer.end(), std::back_inserter(buffer2));
diff --git a/test/t/buffer/test_buffer_purge.cpp b/test/t/memory/test_buffer_purge.cpp
similarity index 60%
rename from test/t/buffer/test_buffer_purge.cpp
rename to test/t/memory/test_buffer_purge.cpp
index a72db1b..e61e08d 100644
--- a/test/t/buffer/test_buffer_purge.cpp
+++ b/test/t/memory/test_buffer_purge.cpp
@@ -17,9 +17,9 @@ struct CallbackClass {
TEST_CASE("Purge data from buffer") {
constexpr size_t buffer_size = 10000;
+ osmium::memory::Buffer buffer{buffer_size};
SECTION("purge empty buffer") {
- osmium::memory::Buffer buffer(buffer_size);
REQUIRE(std::distance(buffer.begin(), buffer.end()) == 0);
CallbackClass callback;
@@ -30,15 +30,13 @@ TEST_CASE("Purge data from buffer") {
}
SECTION("purge buffer with one object but nothing to delete") {
- osmium::memory::Buffer buffer(buffer_size);
-
{
- osmium::builder::NodeBuilder node_builder(buffer);
- node_builder.add_user("testuser");
+ osmium::builder::NodeBuilder node_builder{buffer};
+ node_builder.set_user("testuser");
}
buffer.commit();
REQUIRE(std::distance(buffer.begin(), buffer.end()) == 1);
- size_t committed = buffer.committed();
+ const size_t committed = buffer.committed();
CallbackClass callback;
buffer.purge_removed(&callback);
@@ -49,12 +47,10 @@ TEST_CASE("Purge data from buffer") {
}
SECTION("purge buffer with one object which gets deleted") {
- osmium::memory::Buffer buffer(buffer_size);
-
{
- osmium::builder::NodeBuilder node_builder(buffer);
- node_builder.add_user("testuser");
- node_builder.object().set_removed(true);
+ osmium::builder::NodeBuilder node_builder{buffer};
+ node_builder.set_user("testuser");
+ node_builder.set_removed(true);
}
buffer.commit();
REQUIRE(std::distance(buffer.begin(), buffer.end()) == 1);
@@ -68,21 +64,19 @@ TEST_CASE("Purge data from buffer") {
}
SECTION("purge buffer with two objects, first gets deleted") {
- osmium::memory::Buffer buffer(buffer_size);
-
{
- osmium::builder::NodeBuilder node_builder(buffer);
- node_builder.add_user("testuser");
- node_builder.object().set_removed(true);
+ osmium::builder::NodeBuilder node_builder{buffer};
+ node_builder.set_user("testuser");
+ node_builder.set_removed(true);
}
buffer.commit();
- size_t size1 = buffer.committed();
+ const size_t size1 = buffer.committed();
{
- osmium::builder::NodeBuilder node_builder(buffer);
- node_builder.add_user("testuser");
+ osmium::builder::NodeBuilder node_builder{buffer};
+ node_builder.set_user("testuser");
}
buffer.commit();
- size_t size2 = buffer.committed() - size1;
+ const size_t size2 = buffer.committed() - size1;
REQUIRE(std::distance(buffer.begin(), buffer.end()) == 2);
CallbackClass callback;
@@ -94,18 +88,16 @@ TEST_CASE("Purge data from buffer") {
}
SECTION("purge buffer with two objects, second gets deleted") {
- osmium::memory::Buffer buffer(buffer_size);
-
{
- osmium::builder::NodeBuilder node_builder(buffer);
- node_builder.add_user("testuser_longer_name");
+ osmium::builder::NodeBuilder node_builder{buffer};
+ node_builder.set_user("testuser_longer_name");
}
buffer.commit();
size_t size1 = buffer.committed();
{
- osmium::builder::NodeBuilder node_builder(buffer);
- node_builder.add_user("testuser");
- node_builder.object().set_removed(true);
+ osmium::builder::NodeBuilder node_builder{buffer};
+ node_builder.set_user("testuser");
+ node_builder.set_removed(true);
}
buffer.commit();
@@ -120,24 +112,22 @@ TEST_CASE("Purge data from buffer") {
}
SECTION("purge buffer with three objects, middle one gets deleted") {
- osmium::memory::Buffer buffer(buffer_size);
-
{
- osmium::builder::NodeBuilder node_builder(buffer);
- node_builder.add_user("testuser_longer_name");
+ osmium::builder::NodeBuilder node_builder{buffer};
+ node_builder.set_user("testuser_longer_name");
}
buffer.commit();
{
- osmium::builder::NodeBuilder node_builder(buffer);
- node_builder.add_user("testuser");
- node_builder.object().set_removed(true);
+ osmium::builder::NodeBuilder node_builder{buffer};
+ node_builder.set_user("testuser");
+ node_builder.set_removed(true);
}
buffer.commit();
{
- osmium::builder::NodeBuilder node_builder(buffer);
- node_builder.add_user("sn");
+ osmium::builder::NodeBuilder node_builder{buffer};
+ node_builder.set_user("sn");
}
buffer.commit();
@@ -151,26 +141,24 @@ TEST_CASE("Purge data from buffer") {
}
SECTION("purge buffer with three objects, all get deleted") {
- osmium::memory::Buffer buffer(buffer_size);
-
{
- osmium::builder::NodeBuilder node_builder(buffer);
- node_builder.add_user("testuser_longer_name");
- node_builder.object().set_removed(true);
+ osmium::builder::NodeBuilder node_builder{buffer};
+ node_builder.set_user("testuser_longer_name");
+ node_builder.set_removed(true);
}
buffer.commit();
{
- osmium::builder::NodeBuilder node_builder(buffer);
- node_builder.add_user("testuser");
- node_builder.object().set_removed(true);
+ osmium::builder::NodeBuilder node_builder{buffer};
+ node_builder.set_user("testuser");
+ node_builder.set_removed(true);
}
buffer.commit();
{
- osmium::builder::NodeBuilder node_builder(buffer);
- node_builder.add_user("sn");
- node_builder.object().set_removed(true);
+ osmium::builder::NodeBuilder node_builder{buffer};
+ node_builder.set_user("sn");
+ node_builder.set_removed(true);
}
buffer.commit();
diff --git a/test/t/basic/test_area.cpp b/test/t/osm/test_area.cpp
similarity index 100%
rename from test/t/basic/test_area.cpp
rename to test/t/osm/test_area.cpp
diff --git a/test/t/basic/test_box.cpp b/test/t/osm/test_box.cpp
similarity index 100%
rename from test/t/basic/test_box.cpp
rename to test/t/osm/test_box.cpp
diff --git a/test/t/basic/test_changeset.cpp b/test/t/osm/test_changeset.cpp
similarity index 73%
rename from test/t/basic/test_changeset.cpp
rename to test/t/osm/test_changeset.cpp
index 36c4778..9be8fbb 100644
--- a/test/t/basic/test_changeset.cpp
+++ b/test/t/osm/test_changeset.cpp
@@ -9,7 +9,7 @@
using namespace osmium::builder::attr;
TEST_CASE("Build changeset") {
- osmium::memory::Buffer buffer(10 * 1000);
+ osmium::memory::Buffer buffer{10 * 1000};
osmium::builder::add_changeset(buffer,
_cid(42),
@@ -88,58 +88,57 @@ TEST_CASE("Build changeset") {
}
TEST_CASE("Create changeset without helper") {
- osmium::memory::Buffer buffer(10 * 1000);
- osmium::builder::ChangesetBuilder builder(buffer);
-
- osmium::Changeset& cs1 = builder.object();
- cs1.set_id(42)
- .set_created_at(100)
- .set_closed_at(200)
- .set_num_changes(7)
- .set_num_comments(2)
- .set_uid(9);
-
- builder.add_user("user");
+ osmium::memory::Buffer buffer{10 * 1000};
{
- osmium::builder::TagListBuilder tl_builder(buffer, &builder);
- tl_builder.add_tag("key1", "val1");
- tl_builder.add_tag("key2", "val2");
- }
-
- {
- osmium::builder::ChangesetDiscussionBuilder disc_builder(buffer, &builder);
+ osmium::builder::ChangesetBuilder builder{buffer};
+
+ builder.set_id(42)
+ .set_created_at(100)
+ .set_closed_at(200)
+ .set_num_changes(7)
+ .set_num_comments(2)
+ .set_uid(9)
+ .set_user("user");
+
+ {
+ osmium::builder::TagListBuilder tl_builder{builder};
+ tl_builder.add_tag("key1", "val1");
+ tl_builder.add_tag("key2", "val2");
+ }
+
+ osmium::builder::ChangesetDiscussionBuilder disc_builder{builder};
disc_builder.add_comment(osmium::Timestamp(300), 10, "user2");
disc_builder.add_comment_text("foo");
disc_builder.add_comment(osmium::Timestamp(400), 9, "user");
disc_builder.add_comment_text("bar");
}
- buffer.commit();
+ const auto& cs = buffer.get<osmium::Changeset>(buffer.commit());
- REQUIRE(42 == cs1.id());
- REQUIRE(9 == cs1.uid());
- REQUIRE(7 == cs1.num_changes());
- REQUIRE(2 == cs1.num_comments());
- REQUIRE(true == cs1.closed());
- REQUIRE(osmium::Timestamp(100) == cs1.created_at());
- REQUIRE(osmium::Timestamp(200) == cs1.closed_at());
- REQUIRE(2 == cs1.tags().size());
- REQUIRE(std::string("user") == cs1.user());
+ REQUIRE(42 == cs.id());
+ REQUIRE(9 == cs.uid());
+ REQUIRE(7 == cs.num_changes());
+ REQUIRE(2 == cs.num_comments());
+ REQUIRE(true == cs.closed());
+ REQUIRE(osmium::Timestamp(100) == cs.created_at());
+ REQUIRE(osmium::Timestamp(200) == cs.closed_at());
+ REQUIRE(2 == cs.tags().size());
+ REQUIRE(std::string("user") == cs.user());
- auto cit = cs1.discussion().begin();
+ auto cit = cs.discussion().begin();
- REQUIRE(cit != cs1.discussion().end());
+ REQUIRE(cit != cs.discussion().end());
REQUIRE(cit->date() == osmium::Timestamp(300));
REQUIRE(cit->uid() == 10);
REQUIRE(std::string("user2") == cit->user());
REQUIRE(std::string("foo") == cit->text());
- REQUIRE(++cit != cs1.discussion().end());
+ REQUIRE(++cit != cs.discussion().end());
REQUIRE(cit->date() == osmium::Timestamp(400));
REQUIRE(cit->uid() == 9);
REQUIRE(std::string("user") == cit->user());
REQUIRE(std::string("bar") == cit->text());
- REQUIRE(++cit == cs1.discussion().end());
+ REQUIRE(++cit == cs.discussion().end());
}
diff --git a/test/t/basic/test_crc.cpp b/test/t/osm/test_crc.cpp
similarity index 100%
rename from test/t/basic/test_crc.cpp
rename to test/t/osm/test_crc.cpp
diff --git a/test/t/osm/test_entity_bits.cpp b/test/t/osm/test_entity_bits.cpp
new file mode 100644
index 0000000..a124fa3
--- /dev/null
+++ b/test/t/osm/test_entity_bits.cpp
@@ -0,0 +1,62 @@
+#include "catch.hpp"
+
+#include <osmium/osm/entity_bits.hpp>
+
+static_assert((osmium::osm_entity_bits::node
+ |osmium::osm_entity_bits::way
+ |osmium::osm_entity_bits::relation)
+ == osmium::osm_entity_bits::nwr, "entity_bits nwr failed");
+
+static_assert((osmium::osm_entity_bits::node
+ |osmium::osm_entity_bits::way
+ |osmium::osm_entity_bits::relation
+ |osmium::osm_entity_bits::area)
+ == osmium::osm_entity_bits::nwra, "entity_bits nwra failed");
+
+static_assert((osmium::osm_entity_bits::nwra
+ |osmium::osm_entity_bits::changeset)
+ == osmium::osm_entity_bits::all, "entity_bits all failed");
+
+static_assert((osmium::osm_entity_bits::all
+ &osmium::osm_entity_bits::node)
+ == osmium::osm_entity_bits::node, "entity_bits node failed");
+
+static_assert((~osmium::osm_entity_bits::all) == osmium::osm_entity_bits::nothing, "entity_bits nothing is the inverse of all");
+static_assert((~osmium::osm_entity_bits::nothing) == osmium::osm_entity_bits::all, "entity_bits all is the inverse of nothing");
+static_assert((~osmium::osm_entity_bits::changeset) == osmium::osm_entity_bits::nwra, "entity_bits nwra is the inverse of changeset");
+
+TEST_CASE("Bitwise 'and' and 'or' on entity bits") {
+ osmium::osm_entity_bits::type entities = osmium::osm_entity_bits::node | osmium::osm_entity_bits::way;
+ REQUIRE(entities == (osmium::osm_entity_bits::node | osmium::osm_entity_bits::way));
+
+ entities |= osmium::osm_entity_bits::relation;
+ REQUIRE((entities & osmium::osm_entity_bits::object));
+
+ entities |= osmium::osm_entity_bits::area;
+ REQUIRE(entities == osmium::osm_entity_bits::object);
+
+ REQUIRE_FALSE((entities & osmium::osm_entity_bits::changeset));
+
+ entities &= osmium::osm_entity_bits::node;
+ REQUIRE((entities & osmium::osm_entity_bits::node));
+ REQUIRE_FALSE((entities & osmium::osm_entity_bits::way));
+ REQUIRE(entities == osmium::osm_entity_bits::node);
+}
+
+TEST_CASE("Bitwise 'not' on entity bits") {
+ REQUIRE(~osmium::osm_entity_bits::all == osmium::osm_entity_bits::nothing);
+ REQUIRE(~osmium::osm_entity_bits::nothing == osmium::osm_entity_bits::all);
+ REQUIRE(~osmium::osm_entity_bits::node == (osmium::osm_entity_bits::way | osmium::osm_entity_bits::relation | osmium::osm_entity_bits::area | osmium::osm_entity_bits::changeset));
+ REQUIRE(~osmium::osm_entity_bits::nwr == (osmium::osm_entity_bits::area | osmium::osm_entity_bits::changeset));
+ REQUIRE(~osmium::osm_entity_bits::nwra == osmium::osm_entity_bits::changeset);
+}
+
+TEST_CASE("Converting item types to entity bits") {
+ REQUIRE(osmium::osm_entity_bits::nothing == osmium::osm_entity_bits::from_item_type(osmium::item_type::undefined));
+ REQUIRE(osmium::osm_entity_bits::node == osmium::osm_entity_bits::from_item_type(osmium::item_type::node));
+ REQUIRE(osmium::osm_entity_bits::way == osmium::osm_entity_bits::from_item_type(osmium::item_type::way));
+ REQUIRE(osmium::osm_entity_bits::relation == osmium::osm_entity_bits::from_item_type(osmium::item_type::relation));
+ REQUIRE(osmium::osm_entity_bits::changeset == osmium::osm_entity_bits::from_item_type(osmium::item_type::changeset));
+ REQUIRE(osmium::osm_entity_bits::area == osmium::osm_entity_bits::from_item_type(osmium::item_type::area));
+}
+
diff --git a/test/t/basic/test_location.cpp b/test/t/osm/test_location.cpp
similarity index 78%
rename from test/t/basic/test_location.cpp
rename to test/t/osm/test_location.cpp
index dc5b378..7abf779 100644
--- a/test/t/basic/test_location.cpp
+++ b/test/t/osm/test_location.cpp
@@ -166,41 +166,44 @@ TEST_CASE("Location hash") {
}
}
-#define CR(s, v, r) { \
- const char* strm = "-" s; \
- const char* strp = strm + 1; \
- REQUIRE(std::atof(strp) == Approx( v / 10000000.0)); \
- REQUIRE(std::atof(strm) == Approx(-v / 10000000.0)); \
- const char** data = &strp; \
- REQUIRE(osmium::detail::string_to_location_coordinate(data) == v); \
- REQUIRE(std::string{*data} == r); \
- data = &strm; \
- REQUIRE(osmium::detail::string_to_location_coordinate(data) == -v); \
- REQUIRE(std::string{*data} == r); \
- }
-
-#define C(s, v) CR(s, v, "")
-
-#define F(s) { \
- const char* strm = "-" s; \
- const char* strp = strm + 1; \
- const char** data = &strp; \
- REQUIRE_THROWS_AS(osmium::detail::string_to_location_coordinate(data), osmium::invalid_location); \
- data = &strm; \
- REQUIRE_THROWS_AS(osmium::detail::string_to_location_coordinate(data), osmium::invalid_location); \
- }
+void C(const char* s, long v, const char* r = "") {
+ std::string strm{"-"};
+ strm += s;
+ REQUIRE(std::atof(strm.c_str() + 1) == Approx( v / 10000000.0));
+ REQUIRE(std::atof(strm.c_str() ) == Approx(-v / 10000000.0));
+ const char* x = strm.c_str() + 1;
+ const char** data = &x;
+ REQUIRE(osmium::detail::string_to_location_coordinate(data) == v);
+ REQUIRE(std::string{*data} == r);
+ x = strm.c_str();
+ data = &x;
+ REQUIRE(osmium::detail::string_to_location_coordinate(data) == -v);
+ REQUIRE(std::string{*data} == r);
+}
+
+void F(const char* s) {
+ std::string strm{"-"};
+ 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);
+ ++x;
+ data = &x;
+ REQUIRE_THROWS_AS(osmium::detail::string_to_location_coordinate(data), osmium::invalid_location);
+}
TEST_CASE("Parsing coordinates from strings") {
F("x");
F(".");
+ F(".e2");
F("--");
F("");
F(" ");
F(" 123");
- CR("123 ", 1230000000, " ");
- CR("123x", 1230000000, "x");
- CR("1.2x", 12000000, "x");
+ C("123 ", 1230000000, " ");
+ C("123x", 1230000000, "x");
+ C("1.2x", 12000000, "x");
C("0", 0);
@@ -223,14 +226,19 @@ TEST_CASE("Parsing coordinates from strings") {
F("1234");
F("1234.");
F("12345678901234567890");
+ F("1.1234568111111111111111111111111111111");
+ F("112.34568111111111111111111111111111111");
C("0.", 0);
+ C(".0", 0);
C("0.0", 0);
C("1.", 10000000);
C("1.0", 10000000);
C("1.2", 12000000);
C("0.1", 1000000);
+ C(".1", 1000000);
C("0.01", 100000);
+ C(".01", 100000);
C("0.001", 10000);
C("0.0001", 1000);
C("0.00001", 100);
@@ -251,6 +259,24 @@ TEST_CASE("Parsing coordinates from strings") {
C("179.99999999", 1800000000);
C("200.123", 2001230000);
+ C("8.109E-4" , 8109);
+ C("8.1090E-4" , 8109);
+ C("8.10909E-4" , 8109);
+ C("8.109095E-4" , 8109);
+ C("8.1090959E-4" , 8109);
+ C("8.10909598E-4" , 8109);
+ C("8.109095988E-4" , 8109);
+ C("8.1090959887E-4" , 8109);
+ C("8.10909598870E-4" , 8109);
+ C("8.109095988709E-4" , 8109);
+ C("8.1090959887098E-4" , 8109);
+ C("8.10909598870983E-4" , 8109);
+ C("8.109095988709837E-4" , 8109);
+ C("81.09095988709837E-4" , 81091);
+ C("810.9095988709837E-4" , 810910);
+ C(".8109095988709837E-4" , 811);
+ C(".08109095988709837E-4" , 81);
+
C("1e2", 1000000000);
C("1e1", 100000000);
C("1e0", 10000000);
@@ -263,8 +289,10 @@ TEST_CASE("Parsing coordinates from strings") {
C("1e-7", 1);
C("1.0e2", 1000000000);
+ C("1.e2", 1000000000);
C("1.1e1", 110000000);
C("0.1e1", 10000000);
+ C(".1e1", 10000000);
C("1.2e0", 12000000);
C("1.9e-1", 1900000);
C("2.0e-2", 200000);
@@ -291,32 +319,35 @@ TEST_CASE("Parsing coordinates from strings") {
F("5.0e2");
F("3e2");
F("1e");
+ F("1e-");
+ F("1e1234567");
F("0.5e");
F("1e10");
- CR("1e2 ", 1000000000, " ");
- CR("1.1e2 ", 1100000000, " ");
- CR("1.1e2x", 1100000000, "x");
- CR("1.1e2:", 1100000000, ":");
+ C("1e2 ", 1000000000, " ");
+ C("1.1e2 ", 1100000000, " ");
+ C("1.1e2x", 1100000000, "x");
+ C("1.1e2:", 1100000000, ":");
}
-#undef C
-#undef CR
-#undef F
-
-#define CW(v, s) buffer.clear(); \
- osmium::detail::append_location_coordinate_to_string(std::back_inserter(buffer), v); \
- CHECK(buffer == s); \
- buffer.clear(); \
- osmium::detail::append_location_coordinate_to_string(std::back_inserter(buffer), -v); \
- CHECK(buffer == "-" s);
+TEST_CASE("Writing zero coordinate into string") {
+ std::string buffer;
+ osmium::detail::append_location_coordinate_to_string(std::back_inserter(buffer), 0);
+ REQUIRE(buffer == "0");
+}
-TEST_CASE("Writing coordinates into string") {
+void CW(long v, const char* s) {
std::string buffer;
- osmium::detail::append_location_coordinate_to_string(std::back_inserter(buffer), 0);
- CHECK(buffer == "0");
+ osmium::detail::append_location_coordinate_to_string(std::back_inserter(buffer), v);
+ REQUIRE(buffer == s);
+ buffer.clear();
+ osmium::detail::append_location_coordinate_to_string(std::back_inserter(buffer), -v);
+ REQUIRE(buffer[0] == '-');
+ REQUIRE_FALSE(std::strcmp(buffer.c_str() + 1, s));
+}
+TEST_CASE("Writing coordinate into string") {
CW( 10000000, "1");
CW( 90000000, "9");
CW( 100000000, "10");
@@ -338,8 +369,6 @@ TEST_CASE("Writing coordinates into string") {
CW(1799999999, "179.9999999");
}
-#undef CW
-
TEST_CASE("set lon/lat from string") {
osmium::Location loc;
loc.set_lon("1.2");
diff --git a/test/t/basic/test_node.cpp b/test/t/osm/test_node.cpp
similarity index 100%
rename from test/t/basic/test_node.cpp
rename to test/t/osm/test_node.cpp
diff --git a/test/t/basic/test_node_ref.cpp b/test/t/osm/test_node_ref.cpp
similarity index 100%
rename from test/t/basic/test_node_ref.cpp
rename to test/t/osm/test_node_ref.cpp
diff --git a/test/t/basic/test_object_comparisons.cpp b/test/t/osm/test_object_comparisons.cpp
similarity index 100%
rename from test/t/basic/test_object_comparisons.cpp
rename to test/t/osm/test_object_comparisons.cpp
diff --git a/test/t/basic/test_relation.cpp b/test/t/osm/test_relation.cpp
similarity index 100%
rename from test/t/basic/test_relation.cpp
rename to test/t/osm/test_relation.cpp
diff --git a/test/t/basic/test_timestamp.cpp b/test/t/osm/test_timestamp.cpp
similarity index 100%
rename from test/t/basic/test_timestamp.cpp
rename to test/t/osm/test_timestamp.cpp
diff --git a/test/t/basic/test_types_from_string.cpp b/test/t/osm/test_types_from_string.cpp
similarity index 100%
rename from test/t/basic/test_types_from_string.cpp
rename to test/t/osm/test_types_from_string.cpp
diff --git a/test/t/basic/test_way.cpp b/test/t/osm/test_way.cpp
similarity index 98%
rename from test/t/basic/test_way.cpp
rename to test/t/osm/test_way.cpp
index 005ef30..21258a4 100644
--- a/test/t/basic/test_way.cpp
+++ b/test/t/osm/test_way.cpp
@@ -68,7 +68,7 @@ TEST_CASE("build way with helpers") {
{
osmium::builder::WayBuilder builder(buffer);
- builder.add_user("username");
+ builder.set_user("username");
builder.add_tags({
{"amenity", "restaurant"},
{"name", "Zum goldenen Schwanen"}
--
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