Merge pull request #3296 from Project-OSRM/libosmium-2.10.0

Osmium 2.10
This commit is contained in:
Patrick Niklaus 2016-11-12 02:12:49 +01:00 committed by GitHub
commit 5a293e891b
122 changed files with 4268 additions and 2033 deletions

View File

@ -10,7 +10,7 @@ set -o nounset
# http://git.661346.n2.nabble.com/subtree-merges-lose-prefix-after-rebase-td7332850.html # http://git.661346.n2.nabble.com/subtree-merges-lose-prefix-after-rebase-td7332850.html
OSMIUM_REPO=https://github.com/osmcode/libosmium.git OSMIUM_REPO=https://github.com/osmcode/libosmium.git
OSMIUM_TAG=v2.9.0 OSMIUM_TAG=v2.10.0
VARIANT_REPO=https://github.com/mapbox/variant.git VARIANT_REPO=https://github.com/mapbox/variant.git
VARIANT_TAG=v1.1.0 VARIANT_TAG=v1.1.0

View File

@ -127,7 +127,7 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
auto extractor_callbacks = std::make_unique<ExtractorCallbacks>(extraction_containers); auto extractor_callbacks = std::make_unique<ExtractorCallbacks>(extraction_containers);
const osmium::io::File input_file(config.input_path.string()); const osmium::io::File input_file(config.input_path.string());
osmium::io::Reader reader(input_file); osmium::io::Reader reader(input_file, osmium::io::read_meta::no);
const osmium::io::Header header = reader.header(); const osmium::io::Header header = reader.header();
unsigned number_of_nodes = 0; unsigned number_of_nodes = 0;

View File

@ -13,6 +13,53 @@ This project adheres to [Semantic Versioning](http://semver.org/).
### Fixed ### 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 ## [2.9.0] - 2016-09-15
### Added ### Added
@ -110,7 +157,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- New functions for iterating over specific item types in buffers - New functions for iterating over specific item types in buffers
(`osmium::memory::Buffer::select()`), over specific subitems (`osmium::memory::Buffer::select()`), over specific subitems
(`osmium::OSMObject::subitems()`), and for iterating over all rings of (`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. - Debug output optionally prints CRC32 when `add_crc32` file option is set.
### Changed ### 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 one in Writer. Calling flush() on the OutputIterator isn't needed any
more. more.
- Reader now throws when trying to read after eof or an error. - Reader now throws when trying to read after eof or an error.
- I/O functions that used to throw std::runtime_error now throw - I/O functions that used to throw `std::runtime_error` now throw
osmium::io_error or derived. `osmium::io_error` or derived.
- Optional parameters on osmium::io::Writer now work in any order. - Optional parameters on `osmium::io::Writer` now work in any order.
### Fixed ### 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 Doxygen (up to version 1.8.8). This version contains a workaround to fix
this. 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.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.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 [2.7.2]: https://github.com/osmcode/libosmium/compare/v2.7.1...v2.7.2

View File

@ -24,7 +24,7 @@ set(CMAKE_CONFIGURATION_TYPES "Debug;Release;RelWithDebInfo;MinSizeRel;Dev;Cover
project(libosmium) project(libosmium)
set(LIBOSMIUM_VERSION_MAJOR 2) set(LIBOSMIUM_VERSION_MAJOR 2)
set(LIBOSMIUM_VERSION_MINOR 9) set(LIBOSMIUM_VERSION_MINOR 10)
set(LIBOSMIUM_VERSION_PATCH 0) set(LIBOSMIUM_VERSION_PATCH 0)
set(LIBOSMIUM_VERSION set(LIBOSMIUM_VERSION
@ -285,6 +285,10 @@ if(BUILD_DATA_TESTS)
add_subdirectory(test/data-tests) add_subdirectory(test/data-tests)
endif() endif()
if(BUILD_EXAMPLES)
add_subdirectory(test/examples)
endif()
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
# #

View File

@ -4,8 +4,8 @@ http://osmcode.org/libosmium
A fast and flexible C++ library for working with OpenStreetMap data. A fast and flexible C++ library for working with OpenStreetMap data.
[![Build Status](https://secure.travis-ci.org/osmcode/libosmium.png)](https://travis-ci.org/osmcode/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/mkbg6e6stdgq7c1b?svg=true)](https://ci.appveyor.com/project/Mapbox/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 Libosmium is developed on Linux, but also works on OSX and Windows (with some
limitations). limitations).

View File

@ -12,6 +12,7 @@ set(BENCHMARKS
count count
count_tag count_tag
index_map index_map
mercator
static_vs_dynamic_index static_vs_dynamic_index
write_pbf write_pbf
CACHE STRING "Benchmark programs" CACHE STRING "Benchmark programs"
@ -37,6 +38,8 @@ foreach(benchmark ${BENCHMARKS})
@ONLY) @ONLY)
endforeach() endforeach()
string(TOUPPER "${CMAKE_BUILD_TYPE}" _cmake_build_type)
set(_cxx_flags "${CMAKE_CXX_FLAGS_${_cmake_build_type}}")
foreach(file setup run_benchmarks) foreach(file setup run_benchmarks)
configure_file(${file}.sh ${CMAKE_CURRENT_BINARY_DIR}/${file}.sh @ONLY) configure_file(${file}.sh ${CMAKE_CURRENT_BINARY_DIR}/${file}.sh @ONLY)
endforeach() endforeach()

View File

@ -4,9 +4,9 @@
# #
cd $DATA_DIR 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 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 13 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 120 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 2 GB 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 26 GB curl --location --output 5_planet.osm.pbf http://planet.osm.org/pbf/planet-latest.osm.pbf # about 35 GB

View File

@ -19,15 +19,15 @@ struct CountHandler : public osmium::handler::Handler {
uint64_t ways = 0; uint64_t ways = 0;
uint64_t relations = 0; uint64_t relations = 0;
void node(osmium::Node&) { void node(const osmium::Node&) {
++nodes; ++nodes;
} }
void way(osmium::Way&) { void way(const osmium::Way&) {
++ways; ++ways;
} }
void relation(osmium::Relation&) { void relation(const osmium::Relation&) {
++relations; ++relations;
} }

View File

@ -18,7 +18,7 @@ struct CountHandler : public osmium::handler::Handler {
uint64_t counter = 0; uint64_t counter = 0;
uint64_t all = 0; uint64_t all = 0;
void node(osmium::Node& node) { void node(const osmium::Node& node) {
++all; ++all;
const char* amenity = node.tags().get_value_by_key("amenity"); const char* amenity = node.tags().get_value_by_key("amenity");
if (amenity && !strcmp(amenity, "post_box")) { 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; ++all;
} }
void relation(osmium::Relation&) { void relation(const osmium::Relation&) {
++all; ++all;
} }

View File

@ -0,0 +1,43 @@
/*
The code in this file is released into the Public Domain.
*/
#include <cstdint>
#include <cstdlib>
#include <iostream>
#include <string>
#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 GeomHandler : public osmium::handler::Handler {
osmium::geom::WKBFactory<osmium::geom::MercatorProjection> factory;
void node(const osmium::Node& node) {
const std::string geom = factory.create_point(node);
}
};
int main(int argc, char* argv[]) {
if (argc != 2) {
std::cerr << "Usage: " << argv[0] << " OSMFILE\n";
std::exit(1);
}
const std::string input_filename{argv[1]};
osmium::io::Reader reader{input_filename};
GeomHandler handler;
osmium::apply(reader, handler);
reader.close();
}

View File

@ -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

View File

@ -9,6 +9,10 @@ if [ -z $DATA_DIR ]; then
fi fi
OB_DIR=@CMAKE_BINARY_DIR@/benchmarks 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_RUNS=3
OB_SEQ=`seq -s' ' 1 $OB_RUNS` 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 "BENCHMARK: $BENCHMARK_NAME"
echo "---------------------" 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:" echo "CPU:"
grep '^model name' /proc/cpuinfo | tail -1 grep '^model name' /proc/cpuinfo | tail -1
grep '^cpu MHz' /proc/cpuinfo | tail -1 grep '^cpu MHz' /proc/cpuinfo | tail -1
grep '^cpu cores' /proc/cpuinfo | tail -1 grep '^cpu cores' /proc/cpuinfo | tail -1
grep '^siblings' /proc/cpuinfo | tail -1 grep '^siblings' /proc/cpuinfo | tail -1
echo "---------------------" echo "---------------------"
echo "MEMORY:" echo "MEMORY:"

View File

@ -2,8 +2,8 @@
# #
# FindOsmium.cmake # FindOsmium.cmake
# #
# Find the Libosmium headers and, optionally, several components needed for # Find the Libosmium headers and, optionally, several components needed
# different Libosmium functions. # for different Libosmium functions.
# #
#---------------------------------------------------------------------- #----------------------------------------------------------------------
# #
@ -18,9 +18,12 @@
# #
# Then add the following in your CMakeLists.txt: # Then add the following in your CMakeLists.txt:
# #
# find_package(Osmium REQUIRED COMPONENTS <XXX>) # find_package(Osmium [version] REQUIRED COMPONENTS <XXX>)
# include_directories(SYSTEM ${OSMIUM_INCLUDE_DIRS}) # 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 # For the <XXX> substitute a space separated list of one or more of the
# following components: # following components:
# #
@ -51,10 +54,9 @@
# #
#---------------------------------------------------------------------- #----------------------------------------------------------------------
# Look for the header file. # This is the list of directories where we look for osmium and protozero
find_path(OSMIUM_INCLUDE_DIR osmium/osm.hpp # includes.
PATH_SUFFIXES include set(_osmium_include_path
PATHS
../libosmium ../libosmium
~/Library/Frameworks ~/Library/Frameworks
/Library/Frameworks /Library/Frameworks
@ -62,6 +64,22 @@ find_path(OSMIUM_INCLUDE_DIR osmium/osm.hpp
/opt /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}") set(OSMIUM_INCLUDE_DIRS "${OSMIUM_INCLUDE_DIR}")
#---------------------------------------------------------------------- #----------------------------------------------------------------------
@ -95,17 +113,31 @@ if(Osmium_USE_PBF)
find_package(ZLIB) find_package(ZLIB)
find_package(Threads) find_package(Threads)
list(APPEND OSMIUM_EXTRA_FIND_VARS ZLIB_FOUND Threads_FOUND) message(STATUS "Looking for protozero")
if(ZLIB_FOUND AND Threads_FOUND) 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 list(APPEND OSMIUM_PBF_LIBRARIES
${ZLIB_LIBRARIES} ${ZLIB_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT} ${CMAKE_THREAD_LIBS_INIT}
) )
if(WIN32) if(WIN32)
# This is needed for the ntohl() function
list(APPEND OSMIUM_PBF_LIBRARIES ws2_32) list(APPEND OSMIUM_PBF_LIBRARIES ws2_32)
endif() endif()
list(APPEND OSMIUM_INCLUDE_DIRS list(APPEND OSMIUM_INCLUDE_DIRS
${ZLIB_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR}
${PROTOZERO_INCLUDE_DIR}
) )
else() else()
message(WARNING "Osmium: Can not find some libraries for PBF input/output, please install them or configure the paths.") message(WARNING "Osmium: Can not find some libraries for PBF input/output, please install them or configure the paths.")
@ -203,7 +235,7 @@ if(Osmium_USE_SPARSEHASH)
if(SPARSEHASH_INCLUDE_DIR) if(SPARSEHASH_INCLUDE_DIR)
# Find size of sparsetable::size_type. This does not work on older # Find size of sparsetable::size_type. This does not work on older
# CMake versions because they can do this check only in C, not in C++. # CMake versions because they can do this check only in C, not in C++.
if (NOT CMAKE_VERSION VERSION_LESS 3.0) if(NOT CMAKE_VERSION VERSION_LESS 3.0)
include(CheckTypeSize) include(CheckTypeSize)
set(CMAKE_REQUIRED_INCLUDES ${SPARSEHASH_INCLUDE_DIR}) set(CMAKE_REQUIRED_INCLUDES ${SPARSEHASH_INCLUDE_DIR})
set(CMAKE_EXTRA_INCLUDE_FILES "google/sparsetable") set(CMAKE_EXTRA_INCLUDE_FILES "google/sparsetable")
@ -253,13 +285,15 @@ endif()
# Check that all required libraries are available # Check that all required libraries are available
# #
#---------------------------------------------------------------------- #----------------------------------------------------------------------
if (OSMIUM_EXTRA_FIND_VARS) if(OSMIUM_EXTRA_FIND_VARS)
list(REMOVE_DUPLICATES OSMIUM_EXTRA_FIND_VARS) list(REMOVE_DUPLICATES OSMIUM_EXTRA_FIND_VARS)
endif() endif()
# Handle the QUIETLY and REQUIRED arguments and set OSMIUM_FOUND to TRUE if # Handle the QUIETLY and REQUIRED arguments and the optional version check
# all listed variables are TRUE. # and set OSMIUM_FOUND to TRUE if all listed variables are TRUE.
include(FindPackageHandleStandardArgs) 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) unset(OSMIUM_EXTRA_FIND_VARS)
#---------------------------------------------------------------------- #----------------------------------------------------------------------

View File

@ -10,18 +10,20 @@ message(STATUS "Configuring examples")
set(EXAMPLES set(EXAMPLES
area_test area_test
change_tags
convert convert
count count
create_pois
debug debug
dump_internal
filter_discussions filter_discussions
index index_lookup
location_cache_create location_cache_create
location_cache_use location_cache_use
pub_names pub_names
read read
read_with_progress read_with_progress
road_length road_length
serdump
tiles tiles
CACHE STRING "Example programs" CACHE STRING "Example programs"
) )
@ -32,7 +34,7 @@ set(EXAMPLES
# Examples depending on wingetopt # Examples depending on wingetopt
# #
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
set(GETOPT_EXAMPLES area_test convert index serdump) set(GETOPT_EXAMPLES area_test convert index_lookup)
if(NOT GETOPT_MISSING) if(NOT GETOPT_MISSING)
foreach(example ${GETOPT_EXAMPLES}) foreach(example ${GETOPT_EXAMPLES})
list(APPEND EXAMPLE_LIBS_${example} ${GETOPT_LIBRARY}) list(APPEND EXAMPLE_LIBS_${example} ${GETOPT_LIBRARY})

View File

@ -18,12 +18,24 @@ them.
## Still reasonably simple examples ## Still reasonably simple examples
* `osmium_read_with_progress`
* `osmium_filter_discussions` * `osmium_filter_discussions`
* `osmium_convert` * `osmium_convert`
* `osmium_pub_names`
* `osmium_road_length`
## More advanced examples ## More advanced examples
* `osmium_area_test` * `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 ## License

View File

@ -106,7 +106,7 @@ int main(int argc, char* argv[]) {
// Read options from command line. // Read options from command line.
while (true) { 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) { if (c == -1) {
break; 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) { if (remaining_args != 1) {
std::cerr << "Usage: " << argv[0] << " [OPTIONS] OSMFILE\n"; std::cerr << "Usage: " << argv[0] << " [OPTIONS] OSMFILE\n";
std::exit(1); std::exit(1);

View File

@ -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);
}
}

View File

@ -67,7 +67,7 @@ int main(int argc, char* argv[]) {
// Read options from command line. // Read options from command line.
while (true) { 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) { if (c == -1) {
break; 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) { if (remaining_args > 2) {
std::cerr << "Usage: " << argv[0] << " [OPTIONS] [INFILE [OUTFILE]]\n"; std::cerr << "Usage: " << argv[0] << " [OPTIONS] [INFILE [OUTFILE]]\n";
std::exit(1); std::exit(1);
@ -124,13 +124,13 @@ int main(int argc, char* argv[]) {
osmium::io::Reader reader{input_file}; osmium::io::Reader reader{input_file};
// Get header from input file and change the "generator" setting to // Get header from input file and change the "generator" setting to
// outselves. // ourselves.
osmium::io::Header header = reader.header(); osmium::io::Header header = reader.header();
header.set("generator", "osmium_convert"); header.set("generator", "osmium_convert");
// Initialize Writer using the header from above and tell it that it // Initialize Writer using the header from above and tell it that it
// is allowed to overwrite a possibly existing file. // 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 // 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 // a time. This is much easier and faster than copying each object

View File

@ -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);
}
}

View File

@ -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());
}

View File

@ -67,7 +67,7 @@ int main(int argc, char* argv[]) {
// file for the output file. This will copy over some header information. // 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 // The last parameter will tell the writer that it is allowed to overwrite
// an existing file. Without it, it will refuse to do so. // 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 // Create range of input iterators that will iterator over all changesets
// delivered from input file through the "reader". // delivered from input file through the "reader".

View File

@ -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);
}

View File

@ -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);
}
}

0
third_party/libosmium/examples/osmium_pub_names.cpp vendored Executable file → Normal file
View File

0
third_party/libosmium/examples/osmium_road_length.cpp vendored Executable file → Normal file
View File

View File

@ -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);
}
}

View File

@ -193,12 +193,12 @@ namespace osmium {
}; // struct location_to_ring_map }; // struct location_to_ring_map
inline bool operator==(const location_to_ring_map& a, const location_to_ring_map& b) noexcept { inline bool operator==(const location_to_ring_map& lhs, const location_to_ring_map& rhs) noexcept {
return a.location == b.location; return lhs.location == rhs.location;
} }
inline bool operator<(const location_to_ring_map& a, const location_to_ring_map& b) noexcept { inline bool operator<(const location_to_ring_map& lhs, const location_to_ring_map& rhs) noexcept {
return a.location < b.location; return lhs.location < rhs.location;
} }
} // namespace detail } // namespace detail
@ -288,7 +288,7 @@ namespace osmium {
} }
void add_tags_to_area(osmium::builder::AreaBuilder& builder, const osmium::Way& way) const { 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 { 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) { 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) { for (const osmium::Tag& tag : tags) {
if (std::strcmp(tag.key(), "type")) { if (std::strcmp(tag.key(), "type")) {
tl_builder.add_tag(tag.key(), tag.value()); tl_builder.add_tag(tag.key(), tag.value());
@ -354,7 +354,7 @@ namespace osmium {
} }
if (m_config.keep_type_tag) { if (m_config.keep_type_tag) {
builder.add_item(&relation.tags()); builder.add_item(relation.tags());
} else { } else {
copy_tags_without_type(builder, relation.tags()); copy_tags_without_type(builder, relation.tags());
} }
@ -373,12 +373,12 @@ namespace osmium {
if (debug()) { if (debug()) {
std::cerr << " only one outer way\n"; std::cerr << " only one outer way\n";
} }
builder.add_item(&(*ways.cbegin())->tags()); builder.add_item((*ways.cbegin())->tags());
} else { } else {
if (debug()) { if (debug()) {
std::cerr << " multiple outer ways, get common tags\n"; 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); add_common_tags(tl_builder, ways);
} }
} }
@ -386,7 +386,7 @@ namespace osmium {
template <typename TBuilder> template <typename TBuilder>
static void build_ring_from_proto_ring(osmium::builder::AreaBuilder& builder, const detail::ProtoRing& ring) { static void build_ring_from_proto_ring(osmium::builder::AreaBuilder& builder, const detail::ProtoRing& ring) {
TBuilder ring_builder(builder.buffer(), &builder); TBuilder ring_builder{builder};
ring_builder.add_node_ref(ring.get_node_ref_start()); ring_builder.add_node_ref(ring.get_node_ref_start());
for (const auto& segment : ring.segments()) { for (const auto& segment : ring.segments()) {
ring_builder.add_node_ref(segment->stop()); ring_builder.add_node_ref(segment->stop());
@ -458,8 +458,8 @@ namespace osmium {
} }
detail::NodeRefSegment* get_next_segment(const osmium::Location& location) { 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) { auto it = std::lower_bound(m_locations.begin(), m_locations.end(), slocation{}, [this, &location](const slocation& lhs, const slocation& rhs) {
return a.location(m_segment_list, location) < b.location(m_segment_list, location); return lhs.location(m_segment_list, location) < rhs.location(m_segment_list, location);
}); });
assert(it != m_locations.end()); assert(it != m_locations.end());
@ -744,8 +744,8 @@ namespace osmium {
m_locations.emplace_back(n, true); m_locations.emplace_back(n, true);
} }
std::stable_sort(m_locations.begin(), m_locations.end(), [this](const slocation& a, const slocation& b) { std::stable_sort(m_locations.begin(), m_locations.end(), [this](const slocation& lhs, const slocation& rhs) {
return a.location(m_segment_list) < b.location(m_segment_list); 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); 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) { const auto ring_min = std::min_element(xrings.begin(), xrings.end(), [](const location_to_ring_map& lhs, const location_to_ring_map& rhs) {
return a.ring().min_segment() < b.ring().min_segment(); return lhs.ring().min_segment() < rhs.ring().min_segment();
}); });
find_inner_outer_complex(); find_inner_outer_complex();
@ -1068,11 +1068,11 @@ namespace osmium {
// Find the candidate with the smallest/largest area // Find the candidate with the smallest/largest area
const auto chosen_cand = ring_min_is_outer ? const auto chosen_cand = ring_min_is_outer ?
std::min_element(candidates.cbegin(), candidates.cend(), [](const candidate& a, const candidate& b) { std::min_element(candidates.cbegin(), candidates.cend(), [](const candidate& lhs, const candidate& rhs) {
return std::abs(a.sum) < std::abs(b.sum); return std::abs(lhs.sum) < std::abs(rhs.sum);
}) : }) :
std::max_element(candidates.cbegin(), candidates.cend(), [](const candidate& a, const candidate& b) { std::max_element(candidates.cbegin(), candidates.cend(), [](const candidate& lhs, const candidate& rhs) {
return std::abs(a.sum) < std::abs(b.sum); return std::abs(lhs.sum) < std::abs(rhs.sum);
}); });
if (debug()) { if (debug()) {
@ -1103,8 +1103,8 @@ namespace osmium {
const auto locs = make_range(std::equal_range(m_locations.begin(), const auto locs = make_range(std::equal_range(m_locations.begin(),
m_locations.end(), m_locations.end(),
slocation{}, slocation{},
[this, &location](const slocation& a, const slocation& b) { [this, &location](const slocation& lhs, const slocation& rhs) {
return a.location(m_segment_list, location) < b.location(m_segment_list, location); return lhs.location(m_segment_list, location) < rhs.location(m_segment_list, location);
})); }));
for (auto& loc : locs) { for (auto& loc : locs) {
if (!m_segment_list[loc.item].is_done()) { if (!m_segment_list[loc.item].is_done()) {
@ -1267,8 +1267,8 @@ namespace osmium {
} }
for (const auto& location : m_split_locations) { for (const auto& location : m_split_locations) {
if (m_config.problem_reporter) { 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) { auto it = std::lower_bound(m_locations.cbegin(), m_locations.cend(), slocation{}, [this, &location](const slocation& lhs, const slocation& rhs) {
return a.location(m_segment_list, location) < b.location(m_segment_list, location); return lhs.location(m_segment_list, location) < rhs.location(m_segment_list, location);
}); });
assert(it != m_locations.cend()); assert(it != m_locations.cend());
const osmium::object_id_type id = it->node_ref(m_segment_list).ref(); const osmium::object_id_type id = it->node_ref(m_segment_list).ref();
@ -1362,7 +1362,7 @@ namespace osmium {
#endif #endif
bool create_area(osmium::memory::Buffer& out_buffer, const osmium::Way& way) { 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); builder.initialize_from_object(way);
const bool area_okay = create_rings(); 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) { bool create_area(osmium::memory::Buffer& out_buffer, const osmium::Relation& relation, const std::vector<const osmium::Way*>& members) {
m_num_members = members.size(); m_num_members = members.size();
osmium::builder::AreaBuilder builder(out_buffer); osmium::builder::AreaBuilder builder{out_buffer};
builder.initialize_from_object(relation); builder.initialize_from_object(relation);
const bool area_okay = create_rings(); const bool area_okay = create_rings();

View File

@ -379,8 +379,8 @@ namespace osmium {
sl[2] = {1, s2.first().location() }; sl[2] = {1, s2.first().location() };
sl[3] = {1, s2.second().location()}; sl[3] = {1, s2.second().location()};
std::sort(sl, sl+4, [](const seg_loc& a, const seg_loc& b) { std::sort(sl, sl+4, [](const seg_loc& lhs, const seg_loc& rhs) {
return a.location < b.location; return lhs.location < rhs.location;
}); });
if (sl[1].location == sl[2].location) { if (sl[1].location == sl[2].location) {

View File

@ -101,7 +101,7 @@ namespace osmium {
* Calculate the number of segments in all the ways together. * Calculate the number of segments in all the ways together.
*/ */
static size_t get_num_segments(const std::vector<const osmium::Way*>& members) noexcept { 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()) { if (way->nodes().empty()) {
return sum; return sum;
} else { } else {

View File

@ -73,18 +73,18 @@ namespace osmium {
}; // struct vec }; // struct vec
// addition // addition
constexpr inline vec operator+(const vec& a, const vec& b) noexcept { constexpr inline vec operator+(const vec& lhs, const vec& rhs) noexcept {
return vec{a.x + b.x, a.y + b.y}; return vec{lhs.x + rhs.x, lhs.y + rhs.y};
} }
// subtraction // subtraction
constexpr inline vec operator-(const vec& a, const vec& b) noexcept { constexpr inline vec operator-(const vec& lhs, const vec& rhs) noexcept {
return vec{a.x - b.x, a.y - b.y}; return vec{lhs.x - rhs.x, lhs.y - rhs.y};
} }
// cross product // cross product
constexpr inline int64_t operator*(const vec& a, const vec& b) noexcept { constexpr inline int64_t operator*(const vec& lhs, const vec& rhs) noexcept {
return a.x * b.y - a.y * b.x; return lhs.x * rhs.y - lhs.y * rhs.x;
} }
// scale vector // scale vector
@ -98,13 +98,13 @@ namespace osmium {
} }
// equality // equality
constexpr inline bool operator==(const vec& a, const vec& b) noexcept { constexpr inline bool operator==(const vec& lhs, const vec& rhs) noexcept {
return a.x == b.x && a.y == b.y; return lhs.x == rhs.x && lhs.y == rhs.y;
} }
// inequality // inequality
constexpr inline bool operator!=(const vec& a, const vec& b) noexcept { constexpr inline bool operator!=(const vec& lhs, const vec& rhs) noexcept {
return !(a == b); return !(lhs == rhs);
} }
template <typename TChar, typename TTraits> template <typename TChar, typename TTraits>

View File

@ -617,7 +617,7 @@ namespace osmium {
template <typename TBuilder, typename... TArgs> template <typename TBuilder, typename... TArgs>
inline void add_user(TBuilder& builder, const TArgs&... args) { 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(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()"); 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_basic<detail::node_handler>(builder, args...);
detail::add_user(builder, args...); detail::add_user(builder, args...);
detail::add_list<TagListBuilder, detail::tags_handler>(builder, args...); detail::add_list<TagListBuilder, detail::tags_handler>(builder, args...);
}
return buffer.commit(); 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(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()"); 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_basic<detail::object_handler>(builder, args...);
detail::add_user(builder, args...); detail::add_user(builder, args...);
detail::add_list<TagListBuilder, detail::tags_handler>(builder, args...); detail::add_list<TagListBuilder, detail::tags_handler>(builder, args...);
detail::add_list<WayNodeListBuilder, detail::nodes_handler>(builder, args...); detail::add_list<WayNodeListBuilder, detail::nodes_handler>(builder, args...);
}
return buffer.commit(); 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(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()"); 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_basic<detail::object_handler>(builder, args...);
detail::add_user(builder, args...); detail::add_user(builder, args...);
detail::add_list<TagListBuilder, detail::tags_handler>(builder, args...); detail::add_list<TagListBuilder, detail::tags_handler>(builder, args...);
detail::add_list<RelationMemberListBuilder, detail::members_handler>(builder, args...); detail::add_list<RelationMemberListBuilder, detail::members_handler>(builder, args...);
}
return buffer.commit(); 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(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()"); 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_basic<detail::changeset_handler>(builder, args...);
detail::add_user(builder, args...); detail::add_user(builder, args...);
detail::add_list<TagListBuilder, detail::tags_handler>(builder, args...); detail::add_list<TagListBuilder, detail::tags_handler>(builder, args...);
detail::add_list<ChangesetDiscussionBuilder, detail::discussion_handler>(builder, args...); detail::add_list<ChangesetDiscussionBuilder, detail::discussion_handler>(builder, args...);
}
return buffer.commit(); 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(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()"); 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_basic<detail::object_handler>(builder, args...);
detail::add_user(builder, args...); detail::add_user(builder, args...);
detail::add_list<TagListBuilder, detail::tags_handler>(builder, args...); detail::add_list<TagListBuilder, detail::tags_handler>(builder, args...);
(void)std::initializer_list<int>{ (void)std::initializer_list<int>{
(detail::ring_handler::set_value(builder, args), 0)... (detail::ring_handler::set_value(builder, args), 0)...
}; };
}
return buffer.commit(); return buffer.commit();
} }

View File

@ -45,6 +45,7 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/memory/item.hpp> #include <osmium/memory/item.hpp>
#include <osmium/osm/types.hpp> #include <osmium/osm/types.hpp>
#include <osmium/util/cast.hpp> #include <osmium/util/cast.hpp>
#include <osmium/util/compatibility.hpp>
namespace osmium { namespace osmium {
@ -53,6 +54,10 @@ namespace osmium {
*/ */
namespace builder { namespace builder {
/**
* Parent class for individual builder classes. Instantiate one of
* its derived classes.
*/
class Builder { class Builder {
osmium::memory::Buffer& m_buffer; osmium::memory::Buffer& m_buffer;
@ -71,20 +76,34 @@ namespace osmium {
m_buffer(buffer), m_buffer(buffer),
m_parent(parent), m_parent(parent),
m_item_offset(buffer.written()) { m_item_offset(buffer.written()) {
m_buffer.reserve_space(size); reserve_space(size);
assert(buffer.is_aligned()); assert(buffer.is_aligned());
if (m_parent) { if (m_parent) {
assert(m_buffer.builder_count() == 1 && "Only one sub-builder can be open at any time.");
m_parent->add_size(size); 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; ~Builder() = default;
#else
~Builder() noexcept {
m_buffer.decrement_builder_count();
}
#endif
osmium::memory::Item& item() const { osmium::memory::Item& item() const {
return *reinterpret_cast<osmium::memory::Item*>(m_buffer.data() + m_item_offset); 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. * Add padding to buffer (if needed) to align data properly.
@ -102,7 +121,7 @@ namespace osmium {
void add_padding(bool self = false) { void add_padding(bool self = false) {
const auto padding = osmium::memory::align_bytes - (size() % osmium::memory::align_bytes); const auto padding = osmium::memory::align_bytes - (size() % osmium::memory::align_bytes);
if (padding != 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) { if (self) {
add_size(padding); add_size(padding);
} else if (m_parent) { } else if (m_parent) {
@ -123,12 +142,6 @@ namespace osmium {
return item().byte_size(); 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 * Reserve space for an object of class T in buffer and return
* pointer to it. * pointer to it.
@ -136,7 +149,7 @@ namespace osmium {
template <typename T> template <typename T>
T* reserve_space_for() { T* reserve_space_for() {
assert(m_buffer.is_aligned()); assert(m_buffer.is_aligned());
return reinterpret_cast<T*>(m_buffer.reserve_space(sizeof(T))); return reinterpret_cast<T*>(reserve_space(sizeof(T)));
} }
/** /**
@ -149,7 +162,7 @@ namespace osmium {
* @returns The number of bytes appended (length). * @returns The number of bytes appended (length).
*/ */
osmium::memory::item_size_type append(const char* data, const osmium::memory::item_size_type 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); std::copy_n(reinterpret_cast<const unsigned char*>(data), length, target);
return length; return length;
} }
@ -170,65 +183,37 @@ namespace osmium {
* @returns The number of bytes appended (always 1). * @returns The number of bytes appended (always 1).
*/ */
osmium::memory::item_size_type append_zero() { osmium::memory::item_size_type append_zero() {
*m_buffer.reserve_space(1) = '\0'; *reserve_space(1) = '\0';
return 1; return 1;
} }
public:
/// Return the buffer this builder is using. /// Return the buffer this builder is using.
osmium::memory::Buffer& buffer() noexcept { osmium::memory::Buffer& buffer() noexcept {
return m_buffer; return m_buffer;
} }
/**
* Add a subitem to the object being built. This can be something
* like a TagList or RelationMemberList.
*/
void add_item(const osmium::memory::Item& item) {
m_buffer.add_item(item);
add_size(item.padded_size());
}
/**
* @deprecated Use the version of add_item() taking a
* reference instead.
*/
OSMIUM_DEPRECATED void add_item(const osmium::memory::Item* item) {
assert(item);
add_item(*item);
}
}; // class Builder }; // 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.
*/
void add_user(const char* user) {
add_user(user, static_cast_with_assert<string_size_type>(std::strlen(user)));
}
/**
* Add user name to buffer.
*
* @param user User name.
*/
void add_user(const std::string& user) {
add_user(user.data(), static_cast_with_assert<string_size_type>(user.size()));
}
}; // class ObjectBuilder
} // namespace builder } // namespace builder
} // namespace osmium } // namespace osmium

View File

@ -45,6 +45,7 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/builder/builder.hpp> #include <osmium/builder/builder.hpp>
#include <osmium/osm/item_type.hpp> #include <osmium/osm/item_type.hpp>
#include <osmium/osm/location.hpp> #include <osmium/osm/location.hpp>
#include <osmium/osm/node.hpp>
#include <osmium/osm/node_ref.hpp> #include <osmium/osm/node_ref.hpp>
#include <osmium/osm/object.hpp> #include <osmium/osm/object.hpp>
#include <osmium/osm/tag.hpp> #include <osmium/osm/tag.hpp>
@ -55,6 +56,7 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/osm/relation.hpp> #include <osmium/osm/relation.hpp>
#include <osmium/osm/timestamp.hpp> #include <osmium/osm/timestamp.hpp>
#include <osmium/osm/way.hpp> #include <osmium/osm/way.hpp>
#include <osmium/util/compatibility.hpp>
namespace osmium { namespace osmium {
@ -66,12 +68,18 @@ namespace osmium {
namespace builder { namespace builder {
class TagListBuilder : public ObjectBuilder<TagList> { class TagListBuilder : public Builder {
public: public:
explicit TagListBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) : 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() { ~TagListBuilder() {
@ -169,21 +177,27 @@ namespace osmium {
}; // class TagListBuilder }; // class TagListBuilder
template <typename T> template <typename T>
class NodeRefListBuilder : public ObjectBuilder<T> { class NodeRefListBuilder : public Builder {
public: public:
explicit NodeRefListBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) : 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() { ~NodeRefListBuilder() {
static_cast<Builder*>(this)->add_padding(); add_padding();
} }
void add_node_ref(const NodeRef& node_ref) { void add_node_ref(const NodeRef& node_ref) {
new (static_cast<Builder*>(this)->reserve_space_for<osmium::NodeRef>()) osmium::NodeRef(node_ref); new (reserve_space_for<osmium::NodeRef>()) osmium::NodeRef(node_ref);
static_cast<Builder*>(this)->add_size(sizeof(osmium::NodeRef)); add_size(sizeof(osmium::NodeRef));
} }
void add_node_ref(const object_id_type ref, const osmium::Location& location = Location{}) { void add_node_ref(const object_id_type ref, const osmium::Location& location = Location{}) {
@ -196,7 +210,7 @@ namespace osmium {
using OuterRingBuilder = NodeRefListBuilder<OuterRing>; using OuterRingBuilder = NodeRefListBuilder<OuterRing>;
using InnerRingBuilder = NodeRefListBuilder<InnerRing>; using InnerRingBuilder = NodeRefListBuilder<InnerRing>;
class RelationMemberListBuilder : public ObjectBuilder<RelationMemberList> { class RelationMemberListBuilder : public Builder {
/** /**
* Add role to buffer. * Add role to buffer.
@ -219,7 +233,13 @@ namespace osmium {
public: public:
explicit RelationMemberListBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) : 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() { ~RelationMemberListBuilder() {
@ -245,7 +265,7 @@ namespace osmium {
add_size(sizeof(RelationMember)); add_size(sizeof(RelationMember));
add_role(*member, role, role_length); add_role(*member, role, role_length);
if (full_member) { if (full_member) {
add_item(full_member); add_item(*full_member);
} }
} }
@ -281,7 +301,7 @@ namespace osmium {
}; // class RelationMemberListBuilder }; // class RelationMemberListBuilder
class ChangesetDiscussionBuilder : public ObjectBuilder<ChangesetDiscussion> { class ChangesetDiscussionBuilder : public Builder {
osmium::ChangesetComment* m_comment = nullptr; osmium::ChangesetComment* m_comment = nullptr;
@ -309,7 +329,13 @@ namespace osmium {
public: public:
explicit ChangesetDiscussionBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) : 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() { ~ChangesetDiscussionBuilder() {
@ -339,19 +365,101 @@ namespace osmium {
}; // class ChangesetDiscussionBuilder }; // class ChangesetDiscussionBuilder
template <typename T> #define OSMIUM_FORWARD(setter) \
class OSMObjectBuilder : public ObjectBuilder<T> { 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: public:
explicit OSMObjectBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) : explicit OSMObjectBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
ObjectBuilder<T>(buffer, parent) { Builder(buffer, parent, sizeof(T) + min_size_for_user) {
static_cast<Builder*>(this)->reserve_space_for<string_size_type>(); new (&item()) T();
static_cast<Builder*>(this)->add_size(sizeof(string_size_type)); 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) { 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) { for (const auto& p : tags) {
tl_builder.add_tag(p.first, p.second); tl_builder.add_tag(p.first, p.second);
} }
@ -359,19 +467,40 @@ namespace osmium {
}; // class OSMObjectBuilder }; // class OSMObjectBuilder
using NodeBuilder = OSMObjectBuilder<osmium::Node>; class NodeBuilder : public OSMObjectBuilder<NodeBuilder, Node> {
using RelationBuilder = OSMObjectBuilder<osmium::Relation>;
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: public:
explicit WayBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) : 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) { 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) { for (const auto& node_ref : nodes) {
builder.add_node_ref(node_ref); builder.add_node_ref(node_ref);
} }
@ -379,32 +508,147 @@ namespace osmium {
}; // class WayBuilder }; // 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: public:
explicit AreaBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) : 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. * Initialize area attributes from the attributes of the given object.
*/ */
void initialize_from_object(const osmium::OSMObject& source) { void initialize_from_object(const osmium::OSMObject& source) {
osmium::Area& area = object(); set_id(osmium::object_id_to_area_id(source.id(), source.type()));
area.set_id(osmium::object_id_to_area_id(source.id(), source.type())); set_version(source.version());
area.set_version(source.version()); set_changeset(source.changeset());
area.set_changeset(source.changeset()); set_timestamp(source.timestamp());
area.set_timestamp(source.timestamp()); set_visible(source.visible());
area.set_visible(source.visible()); set_uid(source.uid());
area.set_uid(source.uid()); set_user(source.user());
add_user(source.user());
} }
}; // class AreaBuilder }; // 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 } // namespace builder

View File

@ -95,7 +95,7 @@ namespace osmium {
return m_message.c_str(); return m_message.c_str();
} }
}; // struct geometry_error }; // class geometry_error
/** /**
* @brief Everything related to geometry handling. * @brief Everything related to geometry handling.

View File

@ -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 * @file
* *
* This file contains code for conversion of OSM geometries into GDAL * This file contains code for conversion of OSM geometries into GEOS
* geometries. * 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`. * @attention If you include this file, you'll need to link with `libgeos`.
*/ */
@ -88,6 +98,7 @@ namespace osmium {
namespace detail { namespace detail {
/// @deprecated
class GEOSFactoryImpl { class GEOSFactoryImpl {
std::unique_ptr<const geos::geom::PrecisionModel> m_precision_model; std::unique_ptr<const geos::geom::PrecisionModel> m_precision_model;
@ -245,6 +256,7 @@ namespace osmium {
} // namespace detail } // namespace detail
/// @deprecated
template <typename TProjection = IdentityProjection> template <typename TProjection = IdentityProjection>
using GEOSFactory = GeometryFactory<osmium::geom::detail::GEOSFactoryImpl, TProjection>; using GEOSFactory = GeometryFactory<osmium::geom::detail::GEOSFactoryImpl, TProjection>;
@ -254,4 +266,6 @@ namespace osmium {
#undef THROW #undef THROW
#endif
#endif // OSMIUM_GEOM_GEOS_HPP #endif // OSMIUM_GEOM_GEOS_HPP

View File

@ -43,11 +43,11 @@ namespace osmium {
/** /**
* Check whether one geometry contains another. * Check whether one geometry contains another.
*/ */
inline bool contains(const osmium::Box& a, const osmium::Box& b) { inline bool contains(const osmium::Box& lhs, const osmium::Box& rhs) {
return ((a.bottom_left().x() >= b.bottom_left().x()) && return ((lhs.bottom_left().x() >= rhs.bottom_left().x()) &&
(a.top_right().x() <= b.top_right().x()) && (lhs.top_right().x() <= rhs.top_right().x()) &&
(a.bottom_left().y() >= b.bottom_left().y()) && (lhs.bottom_left().y() >= rhs.bottom_left().y()) &&
(a.top_right().y() <= b.top_right().y())); (lhs.top_right().y() <= rhs.top_right().y()));
} }
} // namespace geom } // namespace geom

View File

@ -118,23 +118,23 @@ namespace osmium {
}; // struct Tile }; // struct Tile
/// Tiles are equal if all their attributes are equal. /// Tiles are equal if all their attributes are equal.
inline bool operator==(const Tile& a, const Tile& b) { inline bool operator==(const Tile& lhs, const Tile& rhs) {
return a.z == b.z && a.x == b.x && a.y == b.y; return lhs.z == rhs.z && lhs.x == rhs.x && lhs.y == rhs.y;
} }
inline bool operator!=(const Tile& a, const Tile& b) { inline bool operator!=(const Tile& lhs, const Tile& rhs) {
return ! (a == b); return ! (lhs == rhs);
} }
/** /**
* This defines an arbitrary order on tiles for use in std::map etc. * This defines an arbitrary order on tiles for use in std::map etc.
*/ */
inline bool operator<(const Tile& a, const Tile& b) { inline bool operator<(const Tile& lhs, const Tile& rhs) {
if (a.z < b.z) return true; if (lhs.z < rhs.z) return true;
if (a.z > b.z) return false; if (lhs.z > rhs.z) return false;
if (a.x < b.x) return true; if (lhs.x < rhs.x) return true;
if (a.x > b.x) return false; if (lhs.x > rhs.x) return false;
return a.y < b.y; return lhs.y < rhs.y;
} }
} // namespace geom } // namespace geom

View File

@ -51,6 +51,9 @@ namespace osmium {
namespace handler { 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 * Note: This handler will only work if either all object IDs are
* positive or all object IDs are negative. * positive or all object IDs are negative.
@ -95,10 +98,8 @@ namespace osmium {
m_offset += relation.byte_size(); m_offset += relation.byte_size();
} }
// XXX
void operator()(const osmium::memory::Buffer& buffer) { void operator()(const osmium::memory::Buffer& buffer) {
osmium::io::detail::reliable_write(m_data_fd, buffer.data(), buffer.committed()); osmium::io::detail::reliable_write(m_data_fd, buffer.data(), buffer.committed());
osmium::apply(buffer.begin(), buffer.end(), *this); osmium::apply(buffer.begin(), buffer.end(), *this);
} }

View File

@ -165,7 +165,7 @@ namespace osmium {
} }
} }
if (error && !m_ignore_errors) { 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"};
} }
} }

View File

@ -46,6 +46,8 @@ namespace osmium {
namespace handler { 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 * Note: This handler will only work if either all object IDs are
* positive or all object IDs are negative. * positive or all object IDs are negative.

View File

@ -33,50 +33,15 @@ DEALINGS IN THE SOFTWARE.
*/ */
#include <type_traits> #include <osmium/index/id_set.hpp>
#include <vector>
namespace osmium { namespace osmium {
namespace index { namespace index {
/** /// @deprecated Use osmium::index::IdSet instead.
* 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.
*/
template <typename T> template <typename T>
class BoolVector { using BoolVector = IdSet<T>;
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
} // namespace index } // namespace index

View File

@ -85,11 +85,11 @@ namespace osmium {
try { try {
const TValue& value = m_vector.at(id); const TValue& value = m_vector.at(id);
if (value == osmium::index::empty_value<TValue>()) { if (value == osmium::index::empty_value<TValue>()) {
not_found_error(id); throw osmium::not_found{id};
} }
return value; return value;
} catch (const std::out_of_range&) { } 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; return a.first < b.first;
}); });
if (result == m_vector.end() || result->first != id) { if (result == m_vector.end() || result->first != id) {
not_found_error(id); throw osmium::not_found{id};
} else { } else {
return result->second; return result->second;
} }

View File

@ -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@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

View File

@ -35,7 +35,6 @@ DEALINGS IN THE SOFTWARE.
#include <cstddef> #include <cstddef>
#include <limits> #include <limits>
#include <sstream>
#include <stdexcept> #include <stdexcept>
#include <string> #include <string>
@ -57,6 +56,10 @@ namespace osmium {
std::runtime_error(what) { 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 }; // struct not_found
/** /**
@ -64,13 +67,6 @@ namespace osmium {
*/ */
namespace index { 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 * Some of the index classes need an "empty" value that can
* never appear in real data. This function must return this * never appear in real data. This function must return this

View File

@ -48,6 +48,18 @@ DEALINGS IN THE SOFTWARE.
namespace osmium { 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 { namespace index {
/** /**
@ -148,14 +160,14 @@ namespace osmium {
// default implementation is empty // 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. // but not always. It could, for instance, sort internal data.
// This is why it is not declared const here. // This is why it is not declared const here.
virtual void dump_as_list(const int /*fd*/) { virtual void dump_as_list(const int /*fd*/) {
throw std::runtime_error("can't dump as list"); throw std::runtime_error("can't dump as list");
} }
// This function could usually be const in derived classes, // This function can usually be const in derived classes,
// but not always. It could, for instance, sort internal data. // but not always. It could, for instance, sort internal data.
// This is why it is not declared const here. // This is why it is not declared const here.
virtual void dump_as_array(const int /*fd*/) { virtual void dump_as_array(const int /*fd*/) {
@ -188,13 +200,6 @@ namespace osmium {
MapFactory(MapFactory&&) = delete; MapFactory(MapFactory&&) = delete;
MapFactory& operator=(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: public:
static MapFactory<id_type, value_type>& instance() { static MapFactory<id_type, value_type>& instance() {
@ -226,7 +231,7 @@ namespace osmium {
std::vector<std::string> config = osmium::split_string(config_string, ','); std::vector<std::string> config = osmium::split_string(config_string, ',');
if (config.empty()) { 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]); auto it = m_callbacks.find(config[0]);
@ -234,7 +239,7 @@ namespace osmium {
return std::unique_ptr<map_type>((it->second)(config)); 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 }; // class MapFactory

View File

@ -63,7 +63,7 @@ namespace osmium {
} }
const TValue get(const TId id) const final { const TValue get(const TId id) const final {
not_found_error(id); throw osmium::not_found{id};
} }
size_t size() const final { size_t size() const final {

View File

@ -79,7 +79,7 @@ namespace osmium {
const TValue get(const TId id) const final { const TValue get(const TId id) const final {
auto it = m_elements.find(id); auto it = m_elements.find(id);
if (it == m_elements.end()) { if (it == m_elements.end()) {
not_found_error(id); throw osmium::not_found{id};
} }
return it->second; return it->second;
} }

View File

@ -99,10 +99,10 @@ namespace osmium {
const TValue get(const TId id) const final { const TValue get(const TId id) const final {
if (id >= m_elements.size()) { if (id >= m_elements.size()) {
not_found_error(id); throw osmium::not_found{id};
} }
if (m_elements[id] == osmium::index::empty_value<TValue>()) { if (m_elements[id] == osmium::index::empty_value<TValue>()) {
not_found_error(id); throw osmium::not_found{id};
} }
return m_elements[id]; return m_elements[id];
} }

View File

@ -145,10 +145,11 @@ namespace osmium {
private: private:
using compression_map_type = std::map<const osmium::io::file_compression, using callbacks_type = std::tuple<create_compressor_type,
std::tuple<create_compressor_type, create_decompressor_type_fd,
create_decompressor_type_fd, create_decompressor_type_buffer>;
create_decompressor_type_buffer>>;
using compression_map_type = std::map<const osmium::io::file_compression, callbacks_type>;
compression_map_type m_callbacks; compression_map_type m_callbacks;
@ -160,11 +161,17 @@ namespace osmium {
CompressionFactory(CompressionFactory&&) = delete; CompressionFactory(CompressionFactory&&) = delete;
CompressionFactory& operator=(CompressionFactory&&) = delete; CompressionFactory& operator=(CompressionFactory&&) = delete;
OSMIUM_NORETURN void error(osmium::io::file_compression compression) { const callbacks_type& find_callbacks(osmium::io::file_compression compression) const {
std::string error_message {"Support for compression '"}; 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 += as_string(compression);
error_message += "' not compiled into this binary."; error_message += "' not compiled into this binary";
throw unsupported_file_format_error(error_message); throw unsupported_file_format_error{error_message};
} }
public: public:
@ -189,36 +196,21 @@ namespace osmium {
} }
template <typename... TArgs> template <typename... TArgs>
std::unique_ptr<osmium::io::Compressor> create_compressor(osmium::io::file_compression compression, TArgs&&... args) { std::unique_ptr<osmium::io::Compressor> create_compressor(osmium::io::file_compression compression, TArgs&&... args) const {
auto it = m_callbacks.find(compression); const auto callbacks = find_callbacks(compression);
return std::unique_ptr<osmium::io::Compressor>(std::get<0>(callbacks)(std::forward<TArgs>(args)...));
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::Decompressor> create_decompressor(osmium::io::file_compression compression, int fd) { std::unique_ptr<osmium::io::Decompressor> create_decompressor(osmium::io::file_compression compression, int fd) const {
auto it = m_callbacks.find(compression); const auto callbacks = find_callbacks(compression);
auto p = std::unique_ptr<osmium::io::Decompressor>(std::get<1>(callbacks)(fd));
if (it != m_callbacks.end()) { p->set_file_size(osmium::util::file_size(fd));
auto p = std::unique_ptr<osmium::io::Decompressor>(std::get<1>(it->second)(fd)); return p;
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, const char* buffer, size_t size) { std::unique_ptr<osmium::io::Decompressor> create_decompressor(osmium::io::file_compression compression, const char* buffer, size_t size) const {
auto it = m_callbacks.find(compression); const auto callbacks = find_callbacks(compression);
return std::unique_ptr<osmium::io::Decompressor>(std::get<2>(callbacks)(buffer, size));
if (it != m_callbacks.end()) {
return std::unique_ptr<osmium::io::Decompressor>(std::get<2>(it->second)(buffer, size));
}
error(compression);
} }
}; // class CompressionFactory }; // class CompressionFactory

View File

@ -55,12 +55,17 @@ namespace osmium {
namespace detail { 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 { class Parser {
future_buffer_queue_type& m_output_queue; future_buffer_queue_type& m_output_queue;
std::promise<osmium::io::Header>& m_header_promise; std::promise<osmium::io::Header>& m_header_promise;
queue_wrapper<std::string> m_input_queue; queue_wrapper<std::string> m_input_queue;
osmium::osm_entity_bits::type m_read_types; reader_options m_options;
bool m_header_is_done; bool m_header_is_done;
protected: protected:
@ -73,11 +78,15 @@ namespace osmium {
return m_input_queue.has_reached_end_of_data(); return m_input_queue.has_reached_end_of_data();
} }
osmium::osm_entity_bits::type read_types() const { osmium::osm_entity_bits::type read_types() const noexcept {
return m_read_types; return m_options.read_which_entities;
} }
bool header_is_done() const { osmium::io::read_meta read_metadata() const noexcept {
return m_options.read_metadata;
}
bool header_is_done() const noexcept {
return m_header_is_done; return m_header_is_done;
} }
@ -111,11 +120,11 @@ namespace osmium {
Parser(future_string_queue_type& input_queue, Parser(future_string_queue_type& input_queue,
future_buffer_queue_type& output_queue, future_buffer_queue_type& output_queue,
std::promise<osmium::io::Header>& header_promise, 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_output_queue(output_queue),
m_header_promise(header_promise), m_header_promise(header_promise),
m_input_queue(input_queue), m_input_queue(input_queue),
m_read_types(read_types), m_options(options),
m_header_is_done(false) { 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&, using create_parser_type = std::function<std::unique_ptr<Parser>(future_string_queue_type&,
future_buffer_queue_type&, future_buffer_queue_type&,
std::promise<osmium::io::Header>& header_promise, std::promise<osmium::io::Header>& header_promise,
osmium::osm_entity_bits::type read_which_entities)>; osmium::io::detail::reader_options options)>;
private: private:

View File

@ -80,7 +80,7 @@ namespace osmium {
struct o5m_error : public io_error { struct o5m_error : public io_error {
explicit o5m_error(const char* what) : 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 }; // struct o5m_error
@ -135,7 +135,7 @@ namespace osmium {
const char* get(uint64_t index) const { const char* get(uint64_t index) const {
if (m_table.empty() || index == 0 || index > number_of_entries) { 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; auto entry = (current_entry + number_of_entries - index) % number_of_entries;
return &m_table[entry * entry_size]; return &m_table[entry * entry_size];
@ -191,7 +191,7 @@ namespace osmium {
static const unsigned char header_magic[] = { 0xff, 0xe0, 0x04, 'o', '5' }; 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))) { 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); m_data += sizeof(header_magic);
@ -203,7 +203,7 @@ namespace osmium {
} else if (*m_data == 'c') { // o5c change file } else if (*m_data == 'c') { // o5c change file
m_header.set_has_multiple_object_versions(true); m_header.set_has_multiple_object_versions(true);
} else { } else {
throw o5m_error("wrong header magic"); throw o5m_error{"wrong header magic"};
} }
m_data++; m_data++;
@ -211,7 +211,7 @@ namespace osmium {
void check_file_format_version() { void check_file_format_version() {
if (*m_data != '2') { if (*m_data != '2') {
throw o5m_error("wrong header magic"); throw o5m_error{"wrong header magic"};
} }
m_data++; m_data++;
@ -219,7 +219,7 @@ namespace osmium {
void decode_header() { void decode_header() {
if (! ensure_bytes_available(7)) { // overall length of 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(); check_header_magic();
@ -260,7 +260,7 @@ namespace osmium {
if (**dataptr == 0x00) { // get inline string if (**dataptr == 0x00) { // get inline string
(*dataptr)++; (*dataptr)++;
if (*dataptr == end) { if (*dataptr == end) {
throw o5m_error("string format error"); throw o5m_error{"string format error"};
} }
return *dataptr; return *dataptr;
} else { // get from reference table } else { // get from reference table
@ -277,7 +277,7 @@ namespace osmium {
auto uid = protozero::decode_varint(&data, end); auto uid = protozero::decode_varint(&data, end);
if (data == end) { if (data == end) {
throw o5m_error("missing user name"); throw o5m_error{"missing user name"};
} }
const char* user = ++data; const char* user = ++data;
@ -290,7 +290,7 @@ namespace osmium {
while (*data++) { while (*data++) {
if (data == end) { 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); 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) { void decode_tags(osmium::builder::Builder& parent, const char** dataptr, const char* const end) {
osmium::builder::TagListBuilder tl_builder(m_buffer, builder); osmium::builder::TagListBuilder builder{parent};
while(*dataptr != end) { while (*dataptr != end) {
bool update_pointer = (**dataptr == 0x00); bool update_pointer = (**dataptr == 0x00);
const char* data = decode_string(dataptr, end); const char* data = decode_string(dataptr, end);
const char* start = data; const char* start = data;
while (*data++) { while (*data++) {
if (data == end) { 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; const char* value = data;
while (*data++) { while (*data++) {
if (data == end) { 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; *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) { void decode_node(const char* data, const char* const end) {
osmium::builder::NodeBuilder builder(m_buffer); osmium::builder::NodeBuilder builder{m_buffer};
osmium::Node& node = builder.object();
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) { if (data == end) {
// no location, object is deleted // no location, object is deleted
builder.object().set_visible(false); builder.set_visible(false);
builder.object().set_location(osmium::Location{}); builder.set_location(osmium::Location{});
} else { } else {
auto lon = m_delta_lon.update(zvarint(&data, end)); auto lon = m_delta_lon.update(zvarint(&data, end));
auto lat = m_delta_lat.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) { 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) { void decode_way(const char* data, const char* const end) {
osmium::builder::WayBuilder builder(m_buffer); osmium::builder::WayBuilder builder{m_buffer};
osmium::Way& way = builder.object();
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) { if (data == end) {
// no reference section, object is deleted // no reference section, object is deleted
builder.object().set_visible(false); builder.set_visible(false);
} else { } else {
auto reference_section_length = protozero::decode_varint(&data, end); auto reference_section_length = protozero::decode_varint(&data, end);
if (reference_section_length > 0) { if (reference_section_length > 0) {
const char* const end_refs = data + reference_section_length; const char* const end_refs = data + reference_section_length;
if (end_refs > end) { 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) { while (data < end_refs) {
wn_builder.add_node_ref(m_delta_way_node_id.update(zvarint(&data, end))); wn_builder.add_node_ref(m_delta_way_node_id.update(zvarint(&data, end)));
@ -408,16 +404,14 @@ namespace osmium {
} }
if (data != end) { if (data != end) {
decode_tags(&builder, &data, end); decode_tags(builder, &data, end);
} }
} }
m_buffer.commit();
} }
osmium::item_type decode_member_type(char c) { osmium::item_type decode_member_type(char c) {
if (c < '0' || c > '2') { 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'); return osmium::nwr_index_to_item_type(c - '0');
} }
@ -429,13 +423,13 @@ namespace osmium {
auto member_type = decode_member_type(*data++); auto member_type = decode_member_type(*data++);
if (data == end) { if (data == end) {
throw o5m_error("missing role"); throw o5m_error{"missing role"};
} }
const char* role = data; const char* role = data;
while (*data++) { while (*data++) {
if (data == end) { 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) { void decode_relation(const char* data, const char* const end) {
osmium::builder::RelationBuilder builder(m_buffer); osmium::builder::RelationBuilder builder{m_buffer};
osmium::Relation& relation = builder.object();
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) { if (data == end) {
// no reference section, object is deleted // no reference section, object is deleted
builder.object().set_visible(false); builder.set_visible(false);
} else { } else {
auto reference_section_length = protozero::decode_varint(&data, end); auto reference_section_length = protozero::decode_varint(&data, end);
if (reference_section_length > 0) { if (reference_section_length > 0) {
const char* const end_refs = data + reference_section_length; const char* const end_refs = data + reference_section_length;
if (end_refs > end) { 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) { while (data < end_refs) {
auto delta_id = zvarint(&data, end); auto delta_id = zvarint(&data, end);
if (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 type_role = decode_role(&data, end);
auto i = osmium::item_type_to_nwr_index(type_role.first); auto i = osmium::item_type_to_nwr_index(type_role.first);
@ -481,11 +474,9 @@ namespace osmium {
} }
if (data != end) { 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) { void decode_bbox(const char* data, const char* const end) {
@ -537,11 +528,11 @@ namespace osmium {
try { try {
length = protozero::decode_varint(&m_data, m_end); length = protozero::decode_varint(&m_data, m_end);
} catch (const protozero::end_of_buffer_exception&) { } 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)) { if (! ensure_bytes_available(length)) {
throw o5m_error("premature end of file"); throw o5m_error{"premature end of file"};
} }
switch (ds_type) { switch (ds_type) {
@ -549,18 +540,21 @@ namespace osmium {
mark_header_as_done(); mark_header_as_done();
if (read_types() & osmium::osm_entity_bits::node) { if (read_types() & osmium::osm_entity_bits::node) {
decode_node(m_data, m_data + length); decode_node(m_data, m_data + length);
m_buffer.commit();
} }
break; break;
case dataset_type::way: case dataset_type::way:
mark_header_as_done(); mark_header_as_done();
if (read_types() & osmium::osm_entity_bits::way) { if (read_types() & osmium::osm_entity_bits::way) {
decode_way(m_data, m_data + length); decode_way(m_data, m_data + length);
m_buffer.commit();
} }
break; break;
case dataset_type::relation: case dataset_type::relation:
mark_header_as_done(); mark_header_as_done();
if (read_types() & osmium::osm_entity_bits::relation) { if (read_types() & osmium::osm_entity_bits::relation) {
decode_relation(m_data, m_data + length); decode_relation(m_data, m_data + length);
m_buffer.commit();
} }
break; break;
case dataset_type::bounding_box: case dataset_type::bounding_box:
@ -598,8 +592,8 @@ namespace osmium {
O5mParser(future_string_queue_type& input_queue, O5mParser(future_string_queue_type& input_queue,
future_buffer_queue_type& output_queue, future_buffer_queue_type& output_queue,
std::promise<osmium::io::Header>& header_promise, std::promise<osmium::io::Header>& header_promise,
osmium::osm_entity_bits::type read_types) : osmium::io::detail::reader_options options) :
Parser(input_queue, output_queue, header_promise, read_types), Parser(input_queue, output_queue, header_promise, options),
m_header(), m_header(),
m_buffer(buffer_size), m_buffer(buffer_size),
m_input(), m_input(),
@ -625,8 +619,8 @@ namespace osmium {
[](future_string_queue_type& input_queue, [](future_string_queue_type& input_queue,
future_buffer_queue_type& output_queue, future_buffer_queue_type& output_queue,
std::promise<osmium::io::Header>& header_promise, std::promise<osmium::io::Header>& header_promise,
osmium::osm_entity_bits::type read_which_entities) { osmium::io::detail::reader_options options) {
return std::unique_ptr<Parser>(new O5mParser(input_queue, output_queue, header_promise, read_which_entities)); return std::unique_ptr<Parser>(new O5mParser(input_queue, output_queue, header_promise, options));
}); });
// dummy function to silence the unused variable warning from above // dummy function to silence the unused variable warning from above

View File

@ -82,8 +82,8 @@ namespace osmium {
OPLParser(future_string_queue_type& input_queue, OPLParser(future_string_queue_type& input_queue,
future_buffer_queue_type& output_queue, future_buffer_queue_type& output_queue,
std::promise<osmium::io::Header>& header_promise, std::promise<osmium::io::Header>& header_promise,
osmium::osm_entity_bits::type read_types) : osmium::io::detail::reader_options options) :
Parser(input_queue, output_queue, header_promise, read_types) { Parser(input_queue, output_queue, header_promise, options) {
set_header_value(osmium::io::Header{}); set_header_value(osmium::io::Header{});
} }
@ -137,8 +137,8 @@ namespace osmium {
[](future_string_queue_type& input_queue, [](future_string_queue_type& input_queue,
future_buffer_queue_type& output_queue, future_buffer_queue_type& output_queue,
std::promise<osmium::io::Header>& header_promise, std::promise<osmium::io::Header>& header_promise,
osmium::osm_entity_bits::type read_which_entities) { osmium::io::detail::reader_options options) {
return std::unique_ptr<Parser>(new OPLParser(input_queue, output_queue, header_promise, read_which_entities)); return std::unique_ptr<Parser>(new OPLParser(input_queue, output_queue, header_promise, options));
}); });
// dummy function to silence the unused variable warning from above // dummy function to silence the unused variable warning from above

View File

@ -365,9 +365,8 @@ namespace osmium {
inline void opl_parse_node(const char** data, osmium::memory::Buffer& buffer) { inline void opl_parse_node(const char** data, osmium::memory::Buffer& buffer) {
osmium::builder::NodeBuilder builder{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; const char* tags_begin = nullptr;
@ -382,19 +381,19 @@ namespace osmium {
++(*data); ++(*data);
switch (c) { switch (c) {
case 'v': case 'v':
node.set_version(opl_parse_version(data)); builder.set_version(opl_parse_version(data));
break; break;
case 'd': case 'd':
node.set_visible(opl_parse_visible(data)); builder.set_visible(opl_parse_visible(data));
break; break;
case 'c': case 'c':
node.set_changeset(opl_parse_changeset_id(data)); builder.set_changeset(opl_parse_changeset_id(data));
break; break;
case 't': case 't':
node.set_timestamp(opl_parse_timestamp(data)); builder.set_timestamp(opl_parse_timestamp(data));
break; break;
case 'i': case 'i':
node.set_uid(opl_parse_uid(data)); builder.set_uid(opl_parse_uid(data));
break; break;
case 'u': case 'u':
opl_parse_string(data, user); opl_parse_string(data, user);
@ -422,23 +421,20 @@ namespace osmium {
} }
if (location.valid()) { if (location.valid()) {
node.set_location(location); builder.set_location(location);
} }
builder.add_user(user); builder.set_user(user);
if (tags_begin) { if (tags_begin) {
opl_parse_tags(tags_begin, buffer, &builder); opl_parse_tags(tags_begin, buffer, &builder);
} }
buffer.commit();
} }
inline void opl_parse_way(const char** data, osmium::memory::Buffer& buffer) { inline void opl_parse_way(const char** data, osmium::memory::Buffer& buffer) {
osmium::builder::WayBuilder builder{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; const char* tags_begin = nullptr;
@ -455,19 +451,19 @@ namespace osmium {
++(*data); ++(*data);
switch (c) { switch (c) {
case 'v': case 'v':
way.set_version(opl_parse_version(data)); builder.set_version(opl_parse_version(data));
break; break;
case 'd': case 'd':
way.set_visible(opl_parse_visible(data)); builder.set_visible(opl_parse_visible(data));
break; break;
case 'c': case 'c':
way.set_changeset(opl_parse_changeset_id(data)); builder.set_changeset(opl_parse_changeset_id(data));
break; break;
case 't': case 't':
way.set_timestamp(opl_parse_timestamp(data)); builder.set_timestamp(opl_parse_timestamp(data));
break; break;
case 'i': case 'i':
way.set_uid(opl_parse_uid(data)); builder.set_uid(opl_parse_uid(data));
break; break;
case 'u': case 'u':
opl_parse_string(data, user); opl_parse_string(data, user);
@ -488,15 +484,13 @@ namespace osmium {
} }
} }
builder.add_user(user); builder.set_user(user);
if (tags_begin) { if (tags_begin) {
opl_parse_tags(tags_begin, buffer, &builder); opl_parse_tags(tags_begin, buffer, &builder);
} }
opl_parse_way_nodes(nodes_begin, nodes_end, 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) { 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) { inline void opl_parse_relation(const char** data, osmium::memory::Buffer& buffer) {
osmium::builder::RelationBuilder builder{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; const char* tags_begin = nullptr;
@ -555,19 +548,19 @@ namespace osmium {
++(*data); ++(*data);
switch (c) { switch (c) {
case 'v': case 'v':
relation.set_version(opl_parse_version(data)); builder.set_version(opl_parse_version(data));
break; break;
case 'd': case 'd':
relation.set_visible(opl_parse_visible(data)); builder.set_visible(opl_parse_visible(data));
break; break;
case 'c': case 'c':
relation.set_changeset(opl_parse_changeset_id(data)); builder.set_changeset(opl_parse_changeset_id(data));
break; break;
case 't': case 't':
relation.set_timestamp(opl_parse_timestamp(data)); builder.set_timestamp(opl_parse_timestamp(data));
break; break;
case 'i': case 'i':
relation.set_uid(opl_parse_uid(data)); builder.set_uid(opl_parse_uid(data));
break; break;
case 'u': case 'u':
opl_parse_string(data, user); opl_parse_string(data, user);
@ -588,7 +581,7 @@ namespace osmium {
} }
} }
builder.add_user(user); builder.set_user(user);
if (tags_begin) { if (tags_begin) {
opl_parse_tags(tags_begin, buffer, &builder); opl_parse_tags(tags_begin, buffer, &builder);
@ -597,15 +590,12 @@ namespace osmium {
if (members_begin != members_end) { if (members_begin != members_end) {
opl_parse_relation_members(members_begin, members_end, buffer, &builder); opl_parse_relation_members(members_begin, members_end, buffer, &builder);
} }
buffer.commit();
} }
inline void opl_parse_changeset(const char** data, osmium::memory::Buffer& buffer) { inline void opl_parse_changeset(const char** data, osmium::memory::Buffer& buffer) {
osmium::builder::ChangesetBuilder builder{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; const char* tags_begin = nullptr;
@ -621,19 +611,19 @@ namespace osmium {
++(*data); ++(*data);
switch (c) { switch (c) {
case 'k': 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; break;
case 's': case 's':
changeset.set_created_at(opl_parse_timestamp(data)); builder.set_created_at(opl_parse_timestamp(data));
break; break;
case 'e': case 'e':
changeset.set_closed_at(opl_parse_timestamp(data)); builder.set_closed_at(opl_parse_timestamp(data));
break; break;
case 'd': 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; break;
case 'i': case 'i':
changeset.set_uid(opl_parse_uid(data)); builder.set_uid(opl_parse_uid(data));
break; break;
case 'u': case 'u':
opl_parse_string(data, user); opl_parse_string(data, user);
@ -672,17 +662,17 @@ namespace osmium {
} }
if (location1.valid() && location2.valid()) { if (location1.valid() && location2.valid()) {
changeset.bounds().extend(location1); osmium::Box box;
changeset.bounds().extend(location2); box.extend(location1);
box.extend(location2);
builder.set_bounds(box);
} }
builder.add_user(user); builder.set_user(user);
if (tags_begin) { if (tags_begin) {
opl_parse_tags(tags_begin, buffer, &builder); opl_parse_tags(tags_begin, buffer, &builder);
} }
buffer.commit();
} }
inline bool opl_parse_line(uint64_t line_count, inline bool opl_parse_line(uint64_t line_count,
@ -702,6 +692,7 @@ namespace osmium {
if (read_types & osmium::osm_entity_bits::node) { if (read_types & osmium::osm_entity_bits::node) {
++data; ++data;
opl_parse_node(&data, buffer); opl_parse_node(&data, buffer);
buffer.commit();
return true; return true;
} }
break; break;
@ -709,6 +700,7 @@ namespace osmium {
if (read_types & osmium::osm_entity_bits::way) { if (read_types & osmium::osm_entity_bits::way) {
++data; ++data;
opl_parse_way(&data, buffer); opl_parse_way(&data, buffer);
buffer.commit();
return true; return true;
} }
break; break;
@ -716,6 +708,7 @@ namespace osmium {
if (read_types & osmium::osm_entity_bits::relation) { if (read_types & osmium::osm_entity_bits::relation) {
++data; ++data;
opl_parse_relation(&data, buffer); opl_parse_relation(&data, buffer);
buffer.commit();
return true; return true;
} }
break; break;
@ -723,6 +716,7 @@ namespace osmium {
if (read_types & osmium::osm_entity_bits::changeset) { if (read_types & osmium::osm_entity_bits::changeset) {
++data; ++data;
opl_parse_changeset(&data, buffer); opl_parse_changeset(&data, buffer);
buffer.commit();
return true; return true;
} }
break; break;

View File

@ -50,6 +50,7 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/io/detail/pbf.hpp> // IWYU pragma: export #include <osmium/io/detail/pbf.hpp> // IWYU pragma: export
#include <osmium/io/detail/protobuf_tags.hpp> #include <osmium/io/detail/protobuf_tags.hpp>
#include <osmium/io/detail/zlib.hpp> #include <osmium/io/detail/zlib.hpp>
#include <osmium/io/file_format.hpp>
#include <osmium/io/header.hpp> #include <osmium/io/header.hpp>
#include <osmium/memory/buffer.hpp> #include <osmium/memory/buffer.hpp>
#include <osmium/osm/box.hpp> #include <osmium/osm/box.hpp>
@ -94,6 +95,8 @@ namespace osmium {
osmium::memory::Buffer m_buffer { initial_buffer_size }; osmium::memory::Buffer m_buffer { initial_buffer_size };
osmium::io::read_meta m_read_metadata;
void decode_stringtable(const data_view& data) { void decode_stringtable(const data_view& data) {
if (!m_stringtable.empty()) { if (!m_stringtable.empty()) {
throw osmium::pbf_error("more than one stringtable in pbf file"); throw osmium::pbf_error("more than one stringtable in pbf file");
@ -143,13 +146,19 @@ namespace osmium {
case OSMFormat::PrimitiveGroup::repeated_Node_nodes: case OSMFormat::PrimitiveGroup::repeated_Node_nodes:
if (m_read_types & osmium::osm_entity_bits::node) { if (m_read_types & osmium::osm_entity_bits::node) {
decode_node(pbf_primitive_group.get_view()); decode_node(pbf_primitive_group.get_view());
m_buffer.commit();
} else { } else {
pbf_primitive_group.skip(); pbf_primitive_group.skip();
} }
break; break;
case OSMFormat::PrimitiveGroup::optional_DenseNodes_dense: case OSMFormat::PrimitiveGroup::optional_DenseNodes_dense:
if (m_read_types & osmium::osm_entity_bits::node) { 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 { } else {
pbf_primitive_group.skip(); pbf_primitive_group.skip();
} }
@ -157,6 +166,7 @@ namespace osmium {
case OSMFormat::PrimitiveGroup::repeated_Way_ways: case OSMFormat::PrimitiveGroup::repeated_Way_ways:
if (m_read_types & osmium::osm_entity_bits::way) { if (m_read_types & osmium::osm_entity_bits::way) {
decode_way(pbf_primitive_group.get_view()); decode_way(pbf_primitive_group.get_view());
m_buffer.commit();
} else { } else {
pbf_primitive_group.skip(); pbf_primitive_group.skip();
} }
@ -164,6 +174,7 @@ namespace osmium {
case OSMFormat::PrimitiveGroup::repeated_Relation_relations: case OSMFormat::PrimitiveGroup::repeated_Relation_relations:
if (m_read_types & osmium::osm_entity_bits::relation) { if (m_read_types & osmium::osm_entity_bits::relation) {
decode_relation(pbf_primitive_group.get_view()); decode_relation(pbf_primitive_group.get_view());
m_buffer.commit();
} else { } else {
pbf_primitive_group.skip(); pbf_primitive_group.skip();
} }
@ -221,9 +232,9 @@ namespace osmium {
using kv_type = protozero::iterator_range<protozero::pbf_reader::const_uint32_iterator>; 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()) { if (!keys.empty()) {
osmium::builder::TagListBuilder tl_builder(m_buffer, &builder); osmium::builder::TagListBuilder builder{parent};
auto kit = keys.begin(); auto kit = keys.begin();
auto vit = vals.begin(); auto vit = vals.begin();
while (kit != keys.end()) { while (kit != keys.end()) {
@ -233,7 +244,7 @@ namespace osmium {
} }
const auto& k = m_stringtable.at(*kit++); const auto& k = m_stringtable.at(*kit++);
const auto& v = m_stringtable.at(*vit++); 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) { void decode_node(const data_view& data) {
osmium::builder::NodeBuilder builder(m_buffer); osmium::builder::NodeBuilder builder{m_buffer};
osmium::Node& node = builder.object(); osmium::Node& node = builder.object();
kv_type keys; kv_type keys;
@ -266,7 +277,11 @@ namespace osmium {
vals = pbf_node.get_packed_uint32(); vals = pbf_node.get_packed_uint32();
break; break;
case OSMFormat::Node::optional_Info_info: 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; break;
case OSMFormat::Node::required_sint64_lat: case OSMFormat::Node::required_sint64_lat:
lat = pbf_node.get_sint64(); 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); build_tag_list(builder, keys, vals);
m_buffer.commit();
} }
void decode_way(const data_view& data) { void decode_way(const data_view& data) {
osmium::builder::WayBuilder builder(m_buffer); osmium::builder::WayBuilder builder{m_buffer};
kv_type keys; kv_type keys;
kv_type vals; kv_type vals;
@ -321,7 +334,11 @@ namespace osmium {
vals = pbf_way.get_packed_uint32(); vals = pbf_way.get_packed_uint32();
break; break;
case OSMFormat::Way::optional_Info_info: 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; break;
case OSMFormat::Way::packed_sint64_refs: case OSMFormat::Way::packed_sint64_refs:
refs = pbf_way.get_packed_sint64(); 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()) { if (!refs.empty()) {
osmium::builder::WayNodeListBuilder wnl_builder(m_buffer, &builder); osmium::builder::WayNodeListBuilder wnl_builder{builder};
osmium::util::DeltaDecode<int64_t> ref; osmium::util::DeltaDecode<int64_t> ref;
if (lats.empty()) { if (lats.empty()) {
for (const auto& ref_value : refs) { for (const auto& ref_value : refs) {
@ -363,12 +380,10 @@ namespace osmium {
} }
build_tag_list(builder, keys, vals); build_tag_list(builder, keys, vals);
m_buffer.commit();
} }
void decode_relation(const data_view& data) { void decode_relation(const data_view& data) {
osmium::builder::RelationBuilder builder(m_buffer); osmium::builder::RelationBuilder builder{m_buffer};
kv_type keys; kv_type keys;
kv_type vals; kv_type vals;
@ -391,7 +406,11 @@ namespace osmium {
vals = pbf_relation.get_packed_uint32(); vals = pbf_relation.get_packed_uint32();
break; break;
case OSMFormat::Relation::optional_Info_info: 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; break;
case OSMFormat::Relation::packed_int32_roles_sid: case OSMFormat::Relation::packed_int32_roles_sid:
roles = pbf_relation.get_packed_int32(); 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()) { if (!refs.empty()) {
osmium::builder::RelationMemberListBuilder rml_builder(m_buffer, &builder); osmium::builder::RelationMemberListBuilder rml_builder{builder};
osmium::util::DeltaDecode<int64_t> ref; osmium::util::DeltaDecode<int64_t> ref;
while (!roles.empty() && !refs.empty() && !types.empty()) { while (!roles.empty() && !refs.empty() && !types.empty()) {
const auto& r = m_stringtable.at(roles.front()); const auto& r = m_stringtable.at(roles.front());
@ -431,8 +450,84 @@ namespace osmium {
} }
build_tag_list(builder, keys, vals); 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) { void decode_dense_nodes(const data_view& data) {
@ -522,7 +617,7 @@ namespace osmium {
bool visible = true; bool visible = true;
osmium::builder::NodeBuilder builder(m_buffer); osmium::builder::NodeBuilder builder{m_buffer};
osmium::Node& node = builder.object(); osmium::Node& node = builder.object();
node.set_id(dense_id.update(ids.front())); 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())); const auto& u = m_stringtable.at(dense_user_sid.update(user_sids.front()));
user_sids.drop_front(); user_sids.drop_front();
builder.add_user(u.first, u.second); builder.set_user(u.first, u.second);
} else {
builder.add_user("");
} }
// even if the node isn't visible, there's still a record // even if the node isn't visible, there's still a record
@ -588,31 +681,18 @@ namespace osmium {
} }
if (tag_it != tags.end()) { if (tag_it != tags.end()) {
osmium::builder::TagListBuilder tl_builder(m_buffer, &builder); build_tag_list_from_dense_nodes(builder, tag_it, tags.end());
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;
}
} }
m_buffer.commit();
} }
} }
public: 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_data(data),
m_read_types(read_types) { m_read_types(read_types),
m_read_metadata(read_metadata) {
} }
PBFPrimitiveBlockDecoder(const PBFPrimitiveBlockDecoder&) = delete; PBFPrimitiveBlockDecoder(const PBFPrimitiveBlockDecoder&) = delete;
@ -789,12 +869,14 @@ namespace osmium {
std::shared_ptr<std::string> m_input_buffer; std::shared_ptr<std::string> m_input_buffer;
osmium::osm_entity_bits::type m_read_types; osmium::osm_entity_bits::type m_read_types;
osmium::io::read_meta m_read_metadata;
public: 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_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; PBFDataBlobDecoder(const PBFDataBlobDecoder&) = default;
@ -807,7 +889,7 @@ namespace osmium {
osmium::memory::Buffer operator()() { osmium::memory::Buffer operator()() {
std::string output; 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(); return decoder();
} }

View File

@ -180,7 +180,7 @@ namespace osmium {
while (const auto size = check_type_and_get_blob_size("OSMData")) { while (const auto size = check_type_and_get_blob_size("OSMData")) {
std::string input_buffer = read_from_input_queue_with_check(size); std::string input_buffer = read_from_input_queue_with_check(size);
PBFDataBlobDecoder data_blob_parser{ std::move(input_buffer), read_types() }; PBFDataBlobDecoder data_blob_parser{std::move(input_buffer), read_types(), read_metadata()};
if (osmium::config::use_pool_threads_for_pbf_parsing()) { if (osmium::config::use_pool_threads_for_pbf_parsing()) {
send_to_output_queue(osmium::thread::Pool::instance().submit(std::move(data_blob_parser))); send_to_output_queue(osmium::thread::Pool::instance().submit(std::move(data_blob_parser)));
@ -195,8 +195,8 @@ namespace osmium {
PBFParser(future_string_queue_type& input_queue, PBFParser(future_string_queue_type& input_queue,
future_buffer_queue_type& output_queue, future_buffer_queue_type& output_queue,
std::promise<osmium::io::Header>& header_promise, std::promise<osmium::io::Header>& header_promise,
osmium::osm_entity_bits::type read_types) : osmium::io::detail::reader_options options) :
Parser(input_queue, output_queue, header_promise, read_types), Parser(input_queue, output_queue, header_promise, options),
m_input_buffer() { m_input_buffer() {
} }
@ -221,8 +221,8 @@ namespace osmium {
[](future_string_queue_type& input_queue, [](future_string_queue_type& input_queue,
future_buffer_queue_type& output_queue, future_buffer_queue_type& output_queue,
std::promise<osmium::io::Header>& header_promise, std::promise<osmium::io::Header>& header_promise,
osmium::osm_entity_bits::type read_which_entities) { osmium::io::detail::reader_options options) {
return std::unique_ptr<Parser>(new PBFParser(input_queue, output_queue, header_promise, read_which_entities)); return std::unique_ptr<Parser>(new PBFParser(input_queue, output_queue, header_promise, options));
}); });
// dummy function to silence the unused variable warning from above // dummy function to silence the unused variable warning from above

View File

@ -33,10 +33,10 @@ DEALINGS IN THE SOFTWARE.
*/ */
#include <algorithm>
#include <exception> #include <exception>
#include <future> #include <future>
#include <string> #include <string>
#include <utility>
#include <osmium/memory/buffer.hpp> #include <osmium/memory/buffer.hpp>
#include <osmium/thread/queue.hpp> #include <osmium/thread/queue.hpp>
@ -59,13 +59,6 @@ namespace osmium {
*/ */
using future_buffer_queue_type = future_queue_type<osmium::memory::Buffer>; using future_buffer_queue_type = future_queue_type<osmium::memory::Buffer>;
/**
* This type of queue contains OSM file data in the form it is
* stored on disk, ie encoded as XML, PBF, etc.
* The "end of file" is marked by an empty string.
*/
using string_queue_type = osmium::thread::Queue<std::string>;
/** /**
* This type of queue contains OSM file data in the form it is * This type of queue contains OSM file data in the form it is
* stored on disk, ie encoded as XML, PBF, etc. * stored on disk, ie encoded as XML, PBF, etc.
@ -95,11 +88,11 @@ namespace osmium {
add_to_queue<T>(queue, T{}); 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(); 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; return !buffer;
} }

View File

@ -80,8 +80,8 @@ namespace osmium {
XML_Error error_code; XML_Error error_code;
std::string error_string; std::string error_string;
explicit xml_error(XML_Parser parser) : explicit xml_error(const XML_Parser& parser) :
io_error(std::string("XML parsing error at line ") io_error(std::string{"XML parsing error at line "}
+ std::to_string(XML_GetCurrentLineNumber(parser)) + std::to_string(XML_GetCurrentLineNumber(parser))
+ ", column " + ", column "
+ std::to_string(XML_GetCurrentColumnNumber(parser)) + std::to_string(XML_GetCurrentColumnNumber(parser))
@ -117,7 +117,7 @@ namespace osmium {
} }
explicit format_version_error(const char* v) : 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) { version(v) {
} }
@ -201,7 +201,7 @@ namespace osmium {
static void entity_declaration_handler(void*, static void entity_declaration_handler(void*,
const XML_Char*, int, const XML_Char*, int, const XML_Char*, const XML_Char*, int, const XML_Char*, int, const XML_Char*,
const XML_Char*, const XML_Char*, 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: public:
@ -209,7 +209,7 @@ namespace osmium {
explicit ExpatXMLParser(T* callback_object) : explicit ExpatXMLParser(T* callback_object) :
m_parser(XML_ParserCreate(nullptr)) { m_parser(XML_ParserCreate(nullptr)) {
if (!m_parser) { if (!m_parser) {
throw osmium::io_error("Internal error: Can not create parser"); throw osmium::io_error{"Internal error: Can not create parser"};
} }
XML_SetUserData(m_parser, callback_object); XML_SetUserData(m_parser, callback_object);
XML_SetElementHandler(m_parser, start_element_wrapper, end_element_wrapper); XML_SetElementHandler(m_parser, start_element_wrapper, end_element_wrapper);
@ -229,7 +229,7 @@ namespace osmium {
void operator()(const std::string& data, bool last) { 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) { 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; return user;
} }
void init_changeset(osmium::builder::ChangesetBuilder* builder, const XML_Char** attrs) { void init_changeset(osmium::builder::ChangesetBuilder& builder, const XML_Char** attrs) {
const char* user = ""; osmium::Box box;
osmium::Changeset& new_changeset = builder->object();
osmium::Location min; check_attributes(attrs, [&builder, &box](const XML_Char* name, const XML_Char* value) {
osmium::Location max;
check_attributes(attrs, [&min, &max, &user, &new_changeset](const XML_Char* name, const XML_Char* value) {
if (!std::strcmp(name, "min_lon")) { if (!std::strcmp(name, "min_lon")) {
min.set_lon(value); box.bottom_left().set_lon(value);
} else if (!std::strcmp(name, "min_lat")) { } else if (!std::strcmp(name, "min_lat")) {
min.set_lat(value); box.bottom_left().set_lat(value);
} else if (!std::strcmp(name, "max_lon")) { } else if (!std::strcmp(name, "max_lon")) {
max.set_lon(value); box.top_right().set_lon(value);
} else if (!std::strcmp(name, "max_lat")) { } else if (!std::strcmp(name, "max_lat")) {
max.set_lat(value); box.top_right().set_lat(value);
} else if (!std::strcmp(name, "user")) { } else if (!std::strcmp(name, "user")) {
user = value; builder.set_user(value);
} else { } else {
new_changeset.set_attribute(name, value); builder.set_attribute(name, value);
} }
}); });
new_changeset.bounds().extend(min); builder.set_bounds(box);
new_changeset.bounds().extend(max);
builder->add_user(user);
} }
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* k = "";
const char* v = ""; const char* v = "";
check_attributes(attrs, [&k, &v](const XML_Char* name, const XML_Char* value) { check_attributes(attrs, [&k, &v](const XML_Char* name, const XML_Char* value) {
if (name[0] == 'k' && name[1] == 0) { if (name[0] == 'k' && name[1] == 0) {
k = value; k = value;
@ -309,8 +304,9 @@ namespace osmium {
v = value; v = value;
} }
}); });
if (!m_tl_builder) { 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); m_tl_builder->add_tag(k, v);
} }
@ -330,17 +326,17 @@ namespace osmium {
if (!std::strcmp(name, "version")) { if (!std::strcmp(name, "version")) {
m_header.set("version", value); m_header.set("version", value);
if (std::strcmp(value, "0.6")) { if (std::strcmp(value, "0.6")) {
throw osmium::format_version_error(value); throw osmium::format_version_error{value};
} }
} else if (!std::strcmp(name, "generator")) { } else if (!std::strcmp(name, "generator")) {
m_header.set("generator", value); m_header.set("generator", value);
} }
}); });
if (m_header.get("version") == "") { if (m_header.get("version") == "") {
throw osmium::format_version_error(); throw osmium::format_version_error{};
} }
} else { } 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; m_context = context::top;
break; break;
@ -349,8 +345,8 @@ namespace osmium {
if (!std::strcmp(element, "node")) { if (!std::strcmp(element, "node")) {
mark_header_as_done(); mark_header_as_done();
if (read_types() & osmium::osm_entity_bits::node) { if (read_types() & osmium::osm_entity_bits::node) {
m_node_builder = std::unique_ptr<osmium::builder::NodeBuilder>(new osmium::builder::NodeBuilder(m_buffer)); m_node_builder.reset(new osmium::builder::NodeBuilder{m_buffer});
m_node_builder->add_user(init_object(m_node_builder->object(), attrs)); m_node_builder->set_user(init_object(m_node_builder->object(), attrs));
m_context = context::node; m_context = context::node;
} else { } else {
m_context = context::ignored_node; m_context = context::ignored_node;
@ -358,8 +354,8 @@ namespace osmium {
} else if (!std::strcmp(element, "way")) { } else if (!std::strcmp(element, "way")) {
mark_header_as_done(); mark_header_as_done();
if (read_types() & osmium::osm_entity_bits::way) { if (read_types() & osmium::osm_entity_bits::way) {
m_way_builder = std::unique_ptr<osmium::builder::WayBuilder>(new osmium::builder::WayBuilder(m_buffer)); m_way_builder.reset(new osmium::builder::WayBuilder{m_buffer});
m_way_builder->add_user(init_object(m_way_builder->object(), attrs)); m_way_builder->set_user(init_object(m_way_builder->object(), attrs));
m_context = context::way; m_context = context::way;
} else { } else {
m_context = context::ignored_way; m_context = context::ignored_way;
@ -367,8 +363,8 @@ namespace osmium {
} else if (!std::strcmp(element, "relation")) { } else if (!std::strcmp(element, "relation")) {
mark_header_as_done(); mark_header_as_done();
if (read_types() & osmium::osm_entity_bits::relation) { if (read_types() & osmium::osm_entity_bits::relation) {
m_relation_builder = std::unique_ptr<osmium::builder::RelationBuilder>(new osmium::builder::RelationBuilder(m_buffer)); m_relation_builder.reset(new osmium::builder::RelationBuilder{m_buffer});
m_relation_builder->add_user(init_object(m_relation_builder->object(), attrs)); m_relation_builder->set_user(init_object(m_relation_builder->object(), attrs));
m_context = context::relation; m_context = context::relation;
} else { } else {
m_context = context::ignored_relation; m_context = context::ignored_relation;
@ -376,8 +372,8 @@ namespace osmium {
} else if (!std::strcmp(element, "changeset")) { } else if (!std::strcmp(element, "changeset")) {
mark_header_as_done(); mark_header_as_done();
if (read_types() & osmium::osm_entity_bits::changeset) { if (read_types() & osmium::osm_entity_bits::changeset) {
m_changeset_builder = std::unique_ptr<osmium::builder::ChangesetBuilder>(new osmium::builder::ChangesetBuilder(m_buffer)); m_changeset_builder.reset(new osmium::builder::ChangesetBuilder{m_buffer});
init_changeset(m_changeset_builder.get(), attrs); init_changeset(*m_changeset_builder, attrs);
m_context = context::changeset; m_context = context::changeset;
} else { } else {
m_context = context::ignored_changeset; m_context = context::ignored_changeset;
@ -407,7 +403,7 @@ namespace osmium {
m_last_context = context::node; m_last_context = context::node;
m_context = context::in_object; m_context = context::in_object;
if (!std::strcmp(element, "tag")) { if (!std::strcmp(element, "tag")) {
get_tag(m_node_builder.get(), attrs); get_tag(*m_node_builder, attrs);
} }
break; break;
case context::way: case context::way:
@ -417,7 +413,7 @@ namespace osmium {
m_tl_builder.reset(); m_tl_builder.reset();
if (!m_wnl_builder) { 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; NodeRef nr;
@ -433,7 +429,7 @@ namespace osmium {
m_wnl_builder->add_node_ref(nr); m_wnl_builder->add_node_ref(nr);
} else if (!std::strcmp(element, "tag")) { } else if (!std::strcmp(element, "tag")) {
m_wnl_builder.reset(); m_wnl_builder.reset();
get_tag(m_way_builder.get(), attrs); get_tag(*m_way_builder, attrs);
} }
break; break;
case context::relation: case context::relation:
@ -443,7 +439,7 @@ namespace osmium {
m_tl_builder.reset(); m_tl_builder.reset();
if (!m_rml_builder) { 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; 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) { 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) { 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); m_rml_builder->add_member(type, ref, role);
} else if (!std::strcmp(element, "tag")) { } else if (!std::strcmp(element, "tag")) {
m_rml_builder.reset(); m_rml_builder.reset();
get_tag(m_relation_builder.get(), attrs); get_tag(*m_relation_builder, attrs);
} }
break; break;
case context::changeset: case context::changeset:
@ -476,12 +472,12 @@ namespace osmium {
m_context = context::discussion; m_context = context::discussion;
m_tl_builder.reset(); m_tl_builder.reset();
if (!m_changeset_discussion_builder) { 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")) { } else if (!std::strcmp(element, "tag")) {
m_context = context::in_object; m_context = context::in_object;
m_changeset_discussion_builder.reset(); m_changeset_discussion_builder.reset();
get_tag(m_changeset_builder.get(), attrs); get_tag(*m_changeset_builder, attrs);
} }
break; break;
case context::discussion: case context::discussion:
@ -632,8 +628,8 @@ namespace osmium {
XMLParser(future_string_queue_type& input_queue, XMLParser(future_string_queue_type& input_queue,
future_buffer_queue_type& output_queue, future_buffer_queue_type& output_queue,
std::promise<osmium::io::Header>& header_promise, std::promise<osmium::io::Header>& header_promise,
osmium::osm_entity_bits::type read_types) : osmium::io::detail::reader_options options) :
Parser(input_queue, output_queue, header_promise, read_types), Parser(input_queue, output_queue, header_promise, options),
m_context(context::root), m_context(context::root),
m_last_context(context::root), m_last_context(context::root),
m_in_delete_section(false), m_in_delete_section(false),
@ -657,7 +653,7 @@ namespace osmium {
ExpatXMLParser<XMLParser> parser(this); ExpatXMLParser<XMLParser> parser(this);
while (!input_done()) { while (!input_done()) {
std::string data = get_input(); const std::string data{get_input()};
parser(data, input_done()); parser(data, input_done());
if (read_types() == osmium::osm_entity_bits::nothing && header_is_done()) { if (read_types() == osmium::osm_entity_bits::nothing && header_is_done()) {
break; break;
@ -680,8 +676,8 @@ namespace osmium {
[](future_string_queue_type& input_queue, [](future_string_queue_type& input_queue,
future_buffer_queue_type& output_queue, future_buffer_queue_type& output_queue,
std::promise<osmium::io::Header>& header_promise, std::promise<osmium::io::Header>& header_promise,
osmium::osm_entity_bits::type read_which_entities) { osmium::io::detail::reader_options options) {
return std::unique_ptr<Parser>(new XMLParser(input_queue, output_queue, header_promise, read_which_entities)); return std::unique_ptr<Parser>(new XMLParser{input_queue, output_queue, header_promise, options});
}); });
// dummy function to silence the unused variable warning from above // dummy function to silence the unused variable warning from above

View File

@ -49,6 +49,11 @@ namespace osmium {
debug = 6 debug = 6
}; };
enum class read_meta {
no = 0,
yes = 1
};
// avoid g++ false positive // avoid g++ false positive
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wreturn-type" #pragma GCC diagnostic ignored "-Wreturn-type"

View File

@ -44,17 +44,37 @@ namespace osmium {
namespace io { 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 { class Header : public osmium::util::Options {
/// Bounding boxes /// Bounding boxes
std::vector<osmium::Box> m_boxes; std::vector<osmium::Box> m_boxes;
/** /**
* Are there possibly multiple versions of the same object in this stream of objects? * Are there possibly multiple versions of the same object in
* This is true for history files and for change files, but not for normal OSM files. * this stream of objects? This should be true for history files
*/ * and for change files, but not for normal OSM data files.
*/
bool m_has_multiple_object_versions = false; bool m_has_multiple_object_versions = false;
public: public:
@ -65,49 +85,76 @@ namespace osmium {
Options(values) { Options(values) {
} }
Header(const Header&) = default; /**
Header& operator=(const Header&) = default; * Get the bounding boxes defined in the header.
*/
Header(Header&&) = default;
Header& operator=(Header&&) = default;
~Header() = default;
std::vector<osmium::Box>& boxes() noexcept { std::vector<osmium::Box>& boxes() noexcept {
return m_boxes; return m_boxes;
} }
/**
* Get the bounding boxes defined in the header.
*/
const std::vector<osmium::Box>& boxes() const noexcept { const std::vector<osmium::Box>& boxes() const noexcept {
return m_boxes; return m_boxes;
} }
/**
* Set all the bounding boxes in the header.
*/
Header& boxes(const std::vector<osmium::Box>& boxes) noexcept { Header& boxes(const std::vector<osmium::Box>& boxes) noexcept {
m_boxes = boxes; m_boxes = boxes;
return *this; 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 { 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 joined_boxes() const {
osmium::Box box; osmium::Box box;
for (const auto& b : m_boxes) { for (const auto& b : m_boxes) {
box.extend(b.bottom_left()); box.extend(b);
box.extend(b.top_right());
} }
return box; 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) { Header& add_box(const osmium::Box& box) {
m_boxes.push_back(box); m_boxes.push_back(box);
return *this; return *this;
} }
/**
* Can this file contain multiple versions of the same object?
*/
bool has_multiple_object_versions() const noexcept { bool has_multiple_object_versions() const noexcept {
return m_has_multiple_object_versions; 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 { Header& set_has_multiple_object_versions(bool value) noexcept {
m_has_multiple_object_versions = value; m_has_multiple_object_versions = value;
return *this; return *this;

View File

@ -91,7 +91,6 @@ namespace osmium {
class Reader { class Reader {
osmium::io::File m_file; osmium::io::File m_file;
osmium::osm_entity_bits::type m_read_which_entities;
enum class status { enum class status {
okay = 0, // normal reading okay = 0, // normal reading
@ -118,15 +117,25 @@ namespace osmium {
size_t m_file_size; 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. // This function will run in a separate thread.
static void parser_thread(const osmium::io::File& file, static void parser_thread(const osmium::io::File& file,
detail::future_string_queue_type& input_queue, detail::future_string_queue_type& input_queue,
detail::future_buffer_queue_type& osmdata_queue, detail::future_buffer_queue_type& osmdata_queue,
std::promise<osmium::io::Header>&& header_promise, 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); std::promise<osmium::io::Header> promise = std::move(header_promise);
const auto creator = detail::ParserFactory::instance().get_creator_function(file); 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(); parser->parse();
} }
@ -205,15 +214,28 @@ namespace osmium {
/** /**
* Create new Reader object. * Create new Reader object.
* *
* @param file The file we want to open. * @param file The file (contains name and format info) to open.
* @param read_which_entities Which OSM entities (nodes, ways, relations, and/or changesets) * @param args All further arguments are optional and can appear
* should be read from the input file. It can speed the read up * in any order:
* significantly if objects that are not needed anyway are not *
* parsed. * * 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_file(file.check()),
m_read_which_entities(read_which_entities),
m_status(status::okay), m_status(status::okay),
m_childpid(0), m_childpid(0),
m_input_queue(detail::get_input_queue_size(), "raw_input"), m_input_queue(detail::get_input_queue_size(), "raw_input"),
@ -227,17 +249,24 @@ namespace osmium {
m_header(), m_header(),
m_thread(), m_thread(),
m_file_size(m_decompressor->file_size()) { m_file_size(m_decompressor->file_size()) {
(void)std::initializer_list<int>{
(set_option(args), 0)...
};
std::promise<osmium::io::Header> header_promise; std::promise<osmium::io::Header> header_promise;
m_header_future = header_promise.get_future(); 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) : template <typename... TArgs>
Reader(osmium::io::File(filename), read_types) { 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) : template <typename... TArgs>
Reader(osmium::io::File(filename), read_types) { explicit Reader(const char* filename, TArgs&&... args) :
Reader(osmium::io::File(filename), std::forward<TArgs>(args)...) {
} }
Reader(const Reader&) = delete; Reader(const Reader&) = delete;
@ -304,7 +333,7 @@ namespace osmium {
try { try {
if (m_header_future.valid()) { if (m_header_future.valid()) {
m_header = m_header_future.get(); 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; m_status = status::eof;
} }
} }
@ -330,7 +359,7 @@ namespace osmium {
osmium::memory::Buffer buffer; osmium::memory::Buffer buffer;
if (m_status != status::okay || 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'"); throw io_error("Can not read from reader when in status 'closed', 'eof', or 'error'");
} }

View File

@ -113,6 +113,9 @@ namespace osmium {
size_t m_capacity; size_t m_capacity;
size_t m_written; size_t m_written;
size_t m_committed; size_t m_committed;
#ifndef NDEBUG
uint8_t m_builder_count{0};
#endif
auto_grow m_auto_grow {auto_grow::no}; auto_grow m_auto_grow {auto_grow::no};
std::function<void(Buffer&)> m_full; std::function<void(Buffer&)> m_full;
@ -216,13 +219,28 @@ namespace osmium {
~Buffer() = default; ~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. * Return a pointer to data inside the buffer.
* *
* @pre The buffer must be valid. * @pre The buffer must be valid.
*/ */
unsigned char* data() const noexcept { unsigned char* data() const noexcept {
assert(m_data); assert(m_data && "This must be a valid buffer");
return m_data; return m_data;
} }
@ -258,7 +276,7 @@ namespace osmium {
* @pre The buffer must be valid. * @pre The buffer must be valid.
*/ */
bool is_aligned() const noexcept { 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); return (m_written % align_bytes == 0) && (m_committed % align_bytes == 0);
} }
@ -283,7 +301,7 @@ namespace osmium {
* than the difference between committed() and capacity(). * than the difference between committed() and capacity().
*/ */
OSMIUM_DEPRECATED void set_full_callback(std::function<void(Buffer&)> full) { 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; m_full = full;
} }
@ -292,7 +310,6 @@ namespace osmium {
* This works only with internally memory-managed buffers. * This works only with internally memory-managed buffers.
* If the given size is not larger than the current capacity, * If the given size is not larger than the current capacity,
* nothing is done. * nothing is done.
* Already written but not committed data is discarded.
* *
* @pre The buffer must be valid. * @pre The buffer must be valid.
* *
@ -305,7 +322,7 @@ namespace osmium {
* @throws std::bad_alloc if there isn't enough memory available. * @throws std::bad_alloc if there isn't enough memory available.
*/ */
void grow(size_t size) { void grow(size_t size) {
assert(m_data); assert(m_data && "This must be a valid buffer");
if (!m_memory) { if (!m_memory) {
throw std::logic_error("Can't grow Buffer if it doesn't use internal memory management."); throw std::logic_error("Can't grow Buffer if it doesn't use internal memory management.");
} }
@ -325,15 +342,18 @@ namespace osmium {
/** /**
* Mark currently written bytes in the buffer as committed. * 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(). * by is_aligned().
* @pre No builder can be open on this buffer.
* *
* @returns Number of committed bytes before this commit. Can be * @returns Number of committed bytes before this commit. Can be
* used as an offset into the buffer to get to the * used as an offset into the buffer to get to the
* object being committed by this call. * object being committed by this call.
*/ */
size_t commit() { 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()); assert(is_aligned());
const size_t offset = m_committed; const size_t offset = m_committed;
@ -345,9 +365,11 @@ namespace osmium {
* Roll back changes in buffer to last committed state. * Roll back changes in buffer to last committed state.
* *
* @pre The buffer must be valid. * @pre The buffer must be valid.
* @pre No builder can be open on this buffer.
*/ */
void rollback() { 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; m_written = m_committed;
} }
@ -356,9 +378,12 @@ namespace osmium {
* *
* No-op on an invalid buffer. * 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. * @returns Number of bytes in the buffer before it was cleared.
*/ */
size_t clear() { size_t clear() {
assert(m_builder_count == 0 && "Make sure there are no Builder objects still in scope");
const size_t committed = m_committed; const size_t committed = m_committed;
m_written = 0; m_written = 0;
m_committed = 0; m_committed = 0;
@ -377,7 +402,7 @@ namespace osmium {
*/ */
template <typename T> template <typename T>
T& get(const size_t offset) const { 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]); return *reinterpret_cast<T*>(&m_data[offset]);
} }
@ -415,7 +440,7 @@ namespace osmium {
* no callback defined and the buffer isn't auto-growing. * no callback defined and the buffer isn't auto-growing.
*/ */
unsigned char* reserve_space(const size_t size) { unsigned char* reserve_space(const size_t size) {
assert(m_data); assert(m_data && "This must be a valid buffer");
// try to flush the buffer empty first. // try to flush the buffer empty first.
if (m_written + size > m_capacity && m_full) { if (m_written + size > m_capacity && m_full) {
m_full(*this); m_full(*this);
@ -455,7 +480,7 @@ namespace osmium {
*/ */
template <typename T> template <typename T>
T& add_item(const T& item) { 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()); unsigned char* target = reserve_space(item.padded_size());
std::copy_n(reinterpret_cast<const unsigned char*>(&item), item.padded_size(), target); std::copy_n(reinterpret_cast<const unsigned char*>(&item), item.padded_size(), target);
return *reinterpret_cast<T*>(target); return *reinterpret_cast<T*>(target);
@ -465,6 +490,7 @@ namespace osmium {
* Add committed contents of the given buffer to this buffer. * Add committed contents of the given buffer to this buffer.
* *
* @pre The buffer must be valid. * @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 * Note that you have to eventually call commit() to actually
* commit this data. * commit this data.
@ -472,7 +498,9 @@ namespace osmium {
* @param buffer The source of the copy. Must be valid. * @param buffer The source of the copy. Must be valid.
*/ */
void add_buffer(const Buffer& buffer) { void add_buffer(const Buffer& buffer) {
assert(m_data && buffer); 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()); unsigned char* target = reserve_space(buffer.committed());
std::copy_n(buffer.data(), buffer.committed(), target); std::copy_n(buffer.data(), buffer.committed(), target);
} }
@ -482,11 +510,13 @@ namespace osmium {
* you can use std::back_inserter. * you can use std::back_inserter.
* *
* @pre The buffer must be valid. * @pre The buffer must be valid.
* @pre No builder can be open on this buffer.
* *
* @param item The item to be added. * @param item The item to be added.
*/ */
void push_back(const osmium::memory::Item& item) { void push_back(const osmium::memory::Item& item) {
assert(m_data); 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); add_item(item);
commit(); commit();
} }
@ -537,7 +567,7 @@ namespace osmium {
*/ */
template <typename T> template <typename T>
t_iterator<T> begin() { 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); return t_iterator<T>(m_data, m_data + m_committed);
} }
@ -550,7 +580,7 @@ namespace osmium {
* @returns Iterator to first OSMEntity in the buffer. * @returns Iterator to first OSMEntity in the buffer.
*/ */
iterator begin() { iterator begin() {
assert(m_data); assert(m_data && "This must be a valid buffer");
return iterator(m_data, m_data + m_committed); return iterator(m_data, m_data + m_committed);
} }
@ -565,7 +595,7 @@ namespace osmium {
*/ */
template <typename T> template <typename T>
t_iterator<T> get_iterator(size_t offset) { 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); return t_iterator<T>(m_data + offset, m_data + m_committed);
} }
@ -579,7 +609,7 @@ namespace osmium {
* buffer. * buffer.
*/ */
iterator get_iterator(size_t offset) { 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); return iterator(m_data + offset, m_data + m_committed);
} }
@ -593,7 +623,7 @@ namespace osmium {
*/ */
template <typename T> template <typename T>
t_iterator<T> end() { 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); return t_iterator<T>(m_data + m_committed, m_data + m_committed);
} }
@ -606,40 +636,40 @@ namespace osmium {
* @returns End iterator. * @returns End iterator.
*/ */
iterator end() { iterator end() {
assert(m_data); assert(m_data && "This must be a valid buffer");
return iterator(m_data + m_committed, m_data + m_committed); return iterator(m_data + m_committed, m_data + m_committed);
} }
template <typename T> template <typename T>
t_const_iterator<T> cbegin() const { 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); return t_const_iterator<T>(m_data, m_data + m_committed);
} }
const_iterator cbegin() const { 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); return const_iterator(m_data, m_data + m_committed);
} }
template <typename T> template <typename T>
t_const_iterator<T> get_iterator(size_t offset) const { t_const_iterator<T> get_iterator(size_t offset) const {
assert(m_data); assert(m_data && "This must be a valid buffer");
return t_const_iterator<T>(m_data + offset, m_data + m_committed); return t_const_iterator<T>(m_data + offset, m_data + m_committed);
} }
const_iterator get_iterator(size_t offset) const { const_iterator get_iterator(size_t offset) const {
assert(m_data); assert(m_data && "This must be a valid buffer");
return const_iterator(m_data + offset, m_data + m_committed); return const_iterator(m_data + offset, m_data + m_committed);
} }
template <typename T> template <typename T>
t_const_iterator<T> cend() const { 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); return t_const_iterator<T>(m_data + m_committed, m_data + m_committed);
} }
const_iterator cend() const { 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); return const_iterator(m_data + m_committed, m_data + m_committed);
} }
@ -698,7 +728,7 @@ namespace osmium {
*/ */
template <typename TCallbackClass> template <typename TCallbackClass>
void purge_removed(TCallbackClass* callback) { void purge_removed(TCallbackClass* callback) {
assert(m_data); assert(m_data && "This must be a valid buffer");
if (begin() == end()) { if (begin() == end()) {
return; return;
} }

View File

@ -46,9 +46,9 @@ namespace osmium {
template <typename TMember> template <typename TMember>
class CollectionIterator { class CollectionIterator {
// This data_type is either 'unsigned char*' or 'const unsigned char*' depending // This data_type is either 'unsigned char*' or 'const unsigned
// on whether TMember is const. This allows this class to be used as an iterator and // char*' depending on whether TMember is const. This allows this
// as a const_iterator. // 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; using data_type = typename std::conditional<std::is_const<TMember>::value, const unsigned char*, unsigned char*>::type;
data_type m_data; data_type m_data;
@ -92,11 +92,11 @@ namespace osmium {
return m_data; return m_data;
} }
TMember& operator*() const { TMember& operator*() const noexcept {
return *reinterpret_cast<TMember*>(m_data); return *reinterpret_cast<TMember*>(m_data);
} }
TMember* operator->() const { TMember* operator->() const noexcept {
return reinterpret_cast<TMember*>(m_data); return reinterpret_cast<TMember*>(m_data);
} }
@ -118,9 +118,12 @@ namespace osmium {
public: public:
using iterator = CollectionIterator<TMember>; using value_type = TMember;
using const_iterator = CollectionIterator<const TMember>; using reference = TMember&;
using value_type = 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; static constexpr osmium::item_type itemtype = TCollectionItemType;
@ -128,31 +131,45 @@ namespace osmium {
Item(sizeof(Collection<TMember, TCollectionItemType>), TCollectionItemType) { 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(); 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>)); return iterator(data() + sizeof(Collection<TMember, TCollectionItemType>));
} }
iterator end() { iterator end() noexcept {
return iterator(data() + byte_size()); return iterator(data() + byte_size());
} }
const_iterator cbegin() const { const_iterator cbegin() const noexcept {
return const_iterator(data() + sizeof(Collection<TMember, TCollectionItemType>)); return const_iterator(data() + sizeof(Collection<TMember, TCollectionItemType>));
} }
const_iterator cend() const { const_iterator cend() const noexcept {
return const_iterator(data() + byte_size()); return const_iterator(data() + byte_size());
} }
const_iterator begin() const { const_iterator begin() const noexcept {
return cbegin(); return cbegin();
} }
const_iterator end() const { const_iterator end() const noexcept {
return cend(); return cend();
} }

View File

@ -59,9 +59,9 @@ namespace osmium {
using item_size_type = uint32_t; using item_size_type = uint32_t;
// align datastructures to this many bytes // 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); return (length + align_bytes - 1) & ~(align_bytes - 1);
} }

View File

@ -50,7 +50,8 @@ DEALINGS IN THE SOFTWARE.
namespace osmium { namespace osmium {
namespace builder { namespace builder {
template <class T> class ObjectBuilder; template <typename TDerived, typename T>
class OSMObjectBuilder;
} // namespace builder } // namespace builder
/** /**
@ -117,7 +118,8 @@ namespace osmium {
*/ */
class Area : public OSMObject { class Area : public OSMObject {
friend class osmium::builder::ObjectBuilder<osmium::Area>; template <typename TDerived, typename T>
friend class osmium::builder::OSMObjectBuilder;
Area() : Area() :
OSMObject(sizeof(Area), osmium::item_type::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 * Was this area created from a way? (In contrast to areas
* created from a relation and their members.) * created from a relation and their members.)
*
* Complexity: Constant.
*/ */
bool from_way() const noexcept { bool from_way() const noexcept {
return (positive_id() & 0x1) == 0; return (positive_id() & 0x1) == 0;
@ -137,6 +141,8 @@ namespace osmium {
/** /**
* Return the Id of the way or relation this area was created from. * Return the Id of the way or relation this area was created from.
*
* Complexity: Constant.
*/ */
osmium::object_id_type orig_id() const noexcept { osmium::object_id_type orig_id() const noexcept {
return osmium::area_id_to_object_id(id()); 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. * 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) * @returns Pair (number outer rings, number inner rings)
*/ */
std::pair<size_t, size_t> num_rings() const { std::pair<size_t, size_t> num_rings() const {

View File

@ -51,7 +51,7 @@ namespace osmium {
namespace builder { namespace builder {
class ChangesetDiscussionBuilder; class ChangesetDiscussionBuilder;
template <typename T> class ObjectBuilder; class ChangesetBuilder;
} // namespace builder } // namespace builder
class Changeset; class Changeset;
@ -129,20 +129,12 @@ namespace osmium {
class ChangesetDiscussion : public osmium::memory::Collection<ChangesetComment, osmium::item_type::changeset_discussion> { class ChangesetDiscussion : public osmium::memory::Collection<ChangesetComment, osmium::item_type::changeset_discussion> {
friend class osmium::builder::ObjectBuilder<osmium::Changeset>;
public: public:
using size_type = size_t;
ChangesetDiscussion() : ChangesetDiscussion() :
osmium::memory::Collection<ChangesetComment, osmium::item_type::changeset_discussion>() { 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 }; // class ChangesetDiscussion
static_assert(sizeof(ChangesetDiscussion) % osmium::memory::align_bytes == 0, "Class osmium::ChangesetDiscussion has wrong size to be aligned properly!"); 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 { class Changeset : public osmium::OSMEntity {
friend class osmium::builder::ObjectBuilder<osmium::Changeset>; friend class osmium::builder::ChangesetBuilder;
osmium::Box m_bounds; osmium::Box m_bounds;
osmium::Timestamp m_created_at; osmium::Timestamp m_created_at;
@ -173,10 +165,14 @@ namespace osmium {
OSMEntity(sizeof(Changeset), osmium::item_type::changeset) { 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; m_user_size = size;
} }
string_size_type user_size() const noexcept {
return m_user_size;
}
unsigned char* subitems_position() { unsigned char* subitems_position() {
return data() + osmium::memory::padded_length(sizeof(Changeset) + m_user_size); return data() + osmium::memory::padded_length(sizeof(Changeset) + m_user_size);
} }

View File

@ -100,15 +100,15 @@ namespace osmium {
return m_crc; return m_crc;
} }
void update_bool(const bool value) { void update_bool(const bool value) noexcept {
m_crc.process_byte(value); 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); 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 #if __BYTE_ORDER == __LITTLE_ENDIAN
m_crc.process_bytes(&value, sizeof(uint16_t)); m_crc.process_bytes(&value, sizeof(uint16_t));
#else #else
@ -117,7 +117,7 @@ namespace osmium {
#endif #endif
} }
void update_int32(const uint32_t value) { void update_int32(const uint32_t value) noexcept {
#if __BYTE_ORDER == __LITTLE_ENDIAN #if __BYTE_ORDER == __LITTLE_ENDIAN
m_crc.process_bytes(&value, sizeof(uint32_t)); m_crc.process_bytes(&value, sizeof(uint32_t));
#else #else
@ -126,7 +126,7 @@ namespace osmium {
#endif #endif
} }
void update_int64(const uint64_t value) { void update_int64(const uint64_t value) noexcept {
#if __BYTE_ORDER == __LITTLE_ENDIAN #if __BYTE_ORDER == __LITTLE_ENDIAN
m_crc.process_bytes(&value, sizeof(uint64_t)); m_crc.process_bytes(&value, sizeof(uint64_t));
#else #else
@ -135,57 +135,57 @@ namespace osmium {
#endif #endif
} }
void update_string(const char* str) { void update_string(const char* str) noexcept {
while (*str) { while (*str) {
m_crc.process_byte(*str++); m_crc.process_byte(*str++);
} }
} }
void update(const Timestamp& timestamp) { void update(const Timestamp& timestamp) noexcept {
update_int32(uint32_t(timestamp)); 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.x());
update_int32(location.y()); update_int32(location.y());
} }
void update(const osmium::Box& box) { void update(const osmium::Box& box) noexcept {
update(box.bottom_left()); update(box.bottom_left());
update(box.top_right()); update(box.top_right());
} }
void update(const NodeRef& node_ref) { void update(const NodeRef& node_ref) noexcept {
update_int64(node_ref.ref()); update_int64(node_ref.ref());
update(node_ref.location()); update(node_ref.location());
} }
void update(const NodeRefList& node_refs) { void update(const NodeRefList& node_refs) noexcept {
for (const NodeRef& node_ref : node_refs) { for (const NodeRef& node_ref : node_refs) {
update(node_ref); update(node_ref);
} }
} }
void update(const TagList& tags) { void update(const TagList& tags) noexcept {
for (const Tag& tag : tags) { for (const Tag& tag : tags) {
update_string(tag.key()); update_string(tag.key());
update_string(tag.value()); update_string(tag.value());
} }
} }
void update(const osmium::RelationMember& member) { void update(const osmium::RelationMember& member) noexcept {
update_int64(member.ref()); update_int64(member.ref());
update_int16(uint16_t(member.type())); update_int16(uint16_t(member.type()));
update_string(member.role()); update_string(member.role());
} }
void update(const osmium::RelationMemberList& members) { void update(const osmium::RelationMemberList& members) noexcept {
for (const RelationMember& member : members) { for (const RelationMember& member : members) {
update(member); update(member);
} }
} }
void update(const osmium::OSMObject& object) { void update(const osmium::OSMObject& object) noexcept {
update_int64(object.id()); update_int64(object.id());
update_bool(object.visible()); update_bool(object.visible());
update_int32(object.version()); update_int32(object.version());
@ -195,22 +195,22 @@ namespace osmium {
update(object.tags()); update(object.tags());
} }
void update(const osmium::Node& node) { void update(const osmium::Node& node) noexcept {
update(static_cast<const osmium::OSMObject&>(node)); update(static_cast<const osmium::OSMObject&>(node));
update(node.location()); update(node.location());
} }
void update(const osmium::Way& way) { void update(const osmium::Way& way) noexcept {
update(static_cast<const osmium::OSMObject&>(way)); update(static_cast<const osmium::OSMObject&>(way));
update(way.nodes()); update(way.nodes());
} }
void update(const osmium::Relation& relation) { void update(const osmium::Relation& relation) noexcept {
update(static_cast<const osmium::OSMObject&>(relation)); update(static_cast<const osmium::OSMObject&>(relation));
update(relation.members()); update(relation.members());
} }
void update(const osmium::Area& area) { void update(const osmium::Area& area) noexcept {
update(static_cast<const osmium::OSMObject&>(area)); update(static_cast<const osmium::OSMObject&>(area));
for (const auto& subitem : area) { for (const auto& subitem : area) {
if (subitem.type() == osmium::item_type::outer_ring || 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) { for (const auto& comment : discussion) {
update(comment.date()); update(comment.date());
update_int32(comment.uid()); 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_int64(changeset.id());
update(changeset.created_at()); update(changeset.created_at());
update(changeset.closed_at()); update(changeset.closed_at());

View File

@ -60,7 +60,9 @@ namespace osmium {
* assert(! (entities & osmium::osm_entity_bits::changeset)); * assert(! (entities & osmium::osm_entity_bits::changeset));
* @endcode * @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, nothing = 0x00,
node = 0x01, node = 0x01,
@ -75,8 +77,16 @@ namespace osmium {
}; // enum type }; // enum type
inline type operator|(const type lhs, const type rhs) noexcept { inline constexpr type operator|(const type lhs, const type rhs) noexcept {
return static_cast<type>(static_cast<int>(lhs) | static_cast<int> (rhs)); 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 constexpr type operator~(const type value) noexcept {
return all & static_cast<type>(~static_cast<int>(value));
} }
inline type& operator|=(type& lhs, const type rhs) noexcept { inline type& operator|=(type& lhs, const type rhs) noexcept {
@ -84,14 +94,6 @@ namespace osmium {
return lhs; return lhs;
} }
inline type operator&(const type lhs, const type rhs) noexcept {
return static_cast<type>(static_cast<int>(lhs) & static_cast<int> (rhs));
}
inline type operator~(const type value) noexcept {
return static_cast<type>(~static_cast<int>(value));
}
inline type operator&=(type& lhs, const type rhs) noexcept { inline type operator&=(type& lhs, const type rhs) noexcept {
lhs = lhs & rhs; lhs = lhs & rhs;
return lhs; return lhs;
@ -104,7 +106,7 @@ namespace osmium {
* changeset. * changeset.
*/ */
inline type from_item_type(osmium::item_type item_type) noexcept { 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); assert(ut <= 0x05);
if (ut == 0) { if (ut == 0) {
return nothing; return nothing;

View File

@ -86,23 +86,31 @@ namespace osmium {
++str; ++str;
} }
// there has to be at least one digit if (*str != '.') {
if (*str >= '0' && *str <= '9') { // there has to be at least one digit
result = *str - '0'; if (*str >= '0' && *str <= '9') {
++str; 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;
}
if (max_digits == 0) {
goto error;
}
} else { } else {
goto error; // need at least one digit after decimal dot if there was no
} // digit before decimal dot
if (*(str + 1) < '0' || *(str + 1) > '9') {
// optional additional digits before decimal point goto error;
while (*str >= '0' && *str <= '9' && max_digits > 0) { }
result = result * 10 + (*str - '0');
++str;
--max_digits;
}
if (max_digits == 0) {
goto error;
} }
// optional decimal point // optional decimal point
@ -163,18 +171,20 @@ namespace osmium {
} }
if (scale < 0) { if (scale < 0) {
result = 0; for (; scale < 0 && result > 0; ++scale) {
result /= 10;
}
} else { } else {
for (; scale > 0; --scale) { for (; scale > 0; --scale) {
result *= 10; result *= 10;
} }
}
result = (result + 5) / 10 * sign; result = (result + 5) / 10 * sign;
if (result > std::numeric_limits<int32_t>::max() || if (result > std::numeric_limits<int32_t>::max() ||
result < std::numeric_limits<int32_t>::min()) { result < std::numeric_limits<int32_t>::min()) {
goto error; goto error;
}
} }
*data = str; *data = str;

View File

@ -41,12 +41,14 @@ DEALINGS IN THE SOFTWARE.
namespace osmium { namespace osmium {
namespace builder { namespace builder {
template <typename T> class ObjectBuilder; template <typename TDerived, typename T>
class OSMObjectBuilder;
} // namespace builder } // namespace builder
class Node : public OSMObject { 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; osmium::Location m_location;
@ -62,7 +64,7 @@ namespace osmium {
return m_location; return m_location;
} }
Node& set_location(const osmium::Location& location) { Node& set_location(const osmium::Location& location) noexcept {
m_location = location; m_location = location;
return *this; return *this;
} }

View File

@ -52,12 +52,23 @@ namespace osmium {
public: 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 : explicit NodeRefList(osmium::item_type itemtype) noexcept :
osmium::memory::Item(sizeof(NodeRefList), itemtype) { osmium::memory::Item(sizeof(NodeRefList), itemtype) {
} }
/** /**
* Checks whether the collection is empty. * Checks whether the collection is empty.
*
* Complexity: Constant.
*/ */
bool empty() const noexcept { bool empty() const noexcept {
return sizeof(NodeRefList) == byte_size(); return sizeof(NodeRefList) == byte_size();
@ -65,8 +76,10 @@ namespace osmium {
/** /**
* Returns the number of NodeRefs in the collection. * 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); const auto size_node_refs = byte_size() - sizeof(NodeRefList);
assert(size_node_refs % sizeof(NodeRef) == 0); assert(size_node_refs % sizeof(NodeRef) == 0);
return size_node_refs / sizeof(NodeRef); return size_node_refs / sizeof(NodeRef);
@ -75,11 +88,13 @@ namespace osmium {
/** /**
* Access specified element. * Access specified element.
* *
* Complexity: Constant.
*
* @pre @code n < size() @endcode * @pre @code n < size() @endcode
* *
* @param n Get the n-th element of the collection. * @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()); assert(n < size());
const NodeRef* node_ref = &*(cbegin()); const NodeRef* node_ref = &*(cbegin());
return node_ref[n]; return node_ref[n];
@ -88,6 +103,8 @@ namespace osmium {
/** /**
* Access the first element. * Access the first element.
* *
* Complexity: Constant.
*
* @pre @code !empty() @endcode * @pre @code !empty() @endcode
*/ */
const NodeRef& front() const noexcept { const NodeRef& front() const noexcept {
@ -98,6 +115,8 @@ namespace osmium {
/** /**
* Access the last element. * Access the last element.
* *
* Complexity: Constant.
*
* @pre @code !empty() @endcode * @pre @code !empty() @endcode
*/ */
const NodeRef& back() const noexcept { const NodeRef& back() const noexcept {
@ -109,6 +128,8 @@ namespace osmium {
* Checks whether the first and last node in the collection have the * Checks whether the first and last node in the collection have the
* same ID. The locations are not checked. * same ID. The locations are not checked.
* *
* Complexity: Constant.
*
* @pre @code !empty() @endcode * @pre @code !empty() @endcode
*/ */
bool is_closed() const noexcept { bool is_closed() const noexcept {
@ -119,6 +140,8 @@ namespace osmium {
* Checks whether the first and last node in the collection have the * Checks whether the first and last node in the collection have the
* same ID. The locations are not checked. * same ID. The locations are not checked.
* *
* Complexity: Constant.
*
* @pre @code !empty() @endcode * @pre @code !empty() @endcode
*/ */
bool ends_have_same_id() const noexcept { 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 * Checks whether the first and last node in the collection have the
* same location. The IDs are not checked. * same location. The IDs are not checked.
* *
* Complexity: Constant.
*
* @pre @code !empty() @endcode * @pre @code !empty() @endcode
* @pre @code front().location() && back().location() @endcode * @pre @code front().location() && back().location() @endcode
*/ */
@ -137,10 +162,6 @@ namespace osmium {
return front().location() == back().location(); 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. /// Returns an iterator to the beginning.
iterator begin() noexcept { iterator begin() noexcept {
return iterator(data() + sizeof(NodeRefList)); return iterator(data() + sizeof(NodeRefList));

View File

@ -52,11 +52,19 @@ DEALINGS IN THE SOFTWARE.
namespace osmium { namespace osmium {
namespace builder {
template <typename TDerived, typename T>
class OSMObjectBuilder;
} // namespace builder
/** /**
* OSMObject (Node, Way, Relation, or Area). * OSMObject (Node, Way, Relation, or Area).
*/ */
class OSMObject : public osmium::OSMEntity { class OSMObject : public osmium::OSMEntity {
template <typename TDerived, typename T>
friend class osmium::builder::OSMObjectBuilder;
object_id_type m_id; object_id_type m_id;
bool m_deleted : 1; bool m_deleted : 1;
object_version_type m_version : 31; object_version_type m_version : 31;

View File

@ -43,11 +43,14 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/osm/item_type.hpp> #include <osmium/osm/item_type.hpp>
#include <osmium/osm/object.hpp> #include <osmium/osm/object.hpp>
#include <osmium/osm/types.hpp> #include <osmium/osm/types.hpp>
#include <osmium/util/compatibility.hpp>
namespace osmium { namespace osmium {
namespace builder { namespace builder {
template <typename> class ObjectBuilder; template <typename TDerived, typename T>
class OSMObjectBuilder;
class RelationMemberListBuilder; class RelationMemberListBuilder;
} // namespace builder } // namespace builder
@ -109,7 +112,8 @@ namespace osmium {
return m_ref; 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; m_ref = ref;
return *this; return *this;
} }
@ -149,23 +153,18 @@ namespace osmium {
public: public:
using size_type = size_t;
RelationMemberList() : RelationMemberList() :
osmium::memory::Collection<RelationMember, osmium::item_type::relation_member_list>() { 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 }; // class RelationMemberList
static_assert(sizeof(RelationMemberList) % osmium::memory::align_bytes == 0, "Class osmium::RelationMemberList has wrong size to be aligned properly!"); static_assert(sizeof(RelationMemberList) % osmium::memory::align_bytes == 0, "Class osmium::RelationMemberList has wrong size to be aligned properly!");
class Relation : public OSMObject { class Relation : public OSMObject {
friend class osmium::builder::ObjectBuilder<osmium::Relation>; template <typename TDerived, typename T>
friend class osmium::builder::OSMObjectBuilder;
Relation() noexcept : Relation() noexcept :
OSMObject(sizeof(Relation), osmium::item_type::relation) { OSMObject(sizeof(Relation), osmium::item_type::relation) {

View File

@ -86,12 +86,14 @@ namespace osmium {
}; // class Tag }; // class Tag
inline bool operator==(const Tag& a, const Tag& b) { inline bool operator==(const Tag& lhs, const Tag& rhs) {
return !std::strcmp(a.key(), b.key()) && !std::strcmp(a.value(), b.value()); return !std::strcmp(lhs.key(), rhs.key()) &&
!std::strcmp(lhs.value(), rhs.value());
} }
inline bool operator<(const Tag& a, const Tag& b) { inline bool operator<(const Tag& lhs, const Tag& rhs) {
return (!std::strcmp(a.key(), b.key()) && (std::strcmp(a.value(), b.value()) < 0)) || (std::strcmp(a.key(), b.key()) < 0); const auto c = std::strcmp(lhs.key(), rhs.key());
return (c == 0 ? std::strcmp(lhs.value(), rhs.value()) : c) < 0;
} }
/** /**
@ -112,19 +114,10 @@ namespace osmium {
public: public:
using size_type = size_t;
TagList() : TagList() :
osmium::memory::Collection<Tag, osmium::item_type::tag_list>() { 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 * Get tag value for the given tag key. If the key is not set, returns
* the default_value. * the default_value.

View File

@ -44,7 +44,8 @@ DEALINGS IN THE SOFTWARE.
namespace osmium { namespace osmium {
namespace builder { namespace builder {
template <typename T> class ObjectBuilder; template <typename TDerived, typename T>
class OSMObjectBuilder;
} // namespace builder } // namespace builder
/** /**
@ -66,7 +67,8 @@ namespace osmium {
class Way : public OSMObject { class Way : public OSMObject {
friend class osmium::builder::ObjectBuilder<osmium::Way>; template <typename TDerived, typename T>
friend class osmium::builder::OSMObjectBuilder;
Way() noexcept : Way() noexcept :
OSMObject(sizeof(Way), osmium::item_type::way) { OSMObject(sizeof(Way), osmium::item_type::way) {

View File

@ -40,6 +40,7 @@ DEALINGS IN THE SOFTWARE.
#include <functional> #include <functional>
#include <iomanip> #include <iomanip>
#include <iostream> #include <iostream>
#include <utility>
#include <vector> #include <vector>
#include <osmium/osm/item_type.hpp> #include <osmium/osm/item_type.hpp>
@ -353,7 +354,7 @@ namespace osmium {
member_meta(member.type()).emplace_back(member.ref(), m_relations.size(), n); member_meta(member.type()).emplace_back(member.ref(), m_relations.size(), n);
relation_meta.increment_need_members(); relation_meta.increment_need_members();
} else { } 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; ++n;
} }
@ -494,12 +495,65 @@ namespace osmium {
return m_members_buffer; 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) { size_t get_offset(osmium::item_type type, osmium::object_id_type id) {
const auto range = find_member_meta(type, id); const auto range = find_member_meta(type, id);
assert(!range.empty()); assert(!range.empty());
assert(range.begin()->is_available());
return range.begin()->buffer_offset(); 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> template <typename TIter>
void read_relations(TIter begin, TIter end) { void read_relations(TIter begin, TIter end) {
HandlerPass1 handler(*static_cast<TCollector*>(this)); HandlerPass1 handler(*static_cast<TCollector*>(this));
@ -525,7 +579,7 @@ namespace osmium {
/** /**
* Decide whether to purge removed members and then do it. * 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. * This could probably be improved upon.
*/ */
void possibly_purge_removed_members() { void possibly_purge_removed_members() {

View File

@ -35,6 +35,7 @@ DEALINGS IN THE SOFTWARE.
#include <cstddef> #include <cstddef>
#include <iosfwd> #include <iosfwd>
#include <limits>
#include <osmium/osm/types.hpp> #include <osmium/osm/types.hpp>
@ -71,24 +72,44 @@ namespace osmium {
/** /**
* Offset in the buffer where the object is stored. * 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; bool m_removed = false;
public: public:
/** /**
* Create new MemberMeta. The variant with zeros for relation_pos and * Create new MemberMeta.
* member_pos is used to create dummy MemberMeta that can be compared
* to the MemberMeta in the vectors using the equal_range algorithm.
*/ */
explicit MemberMeta(osmium::object_id_type member_id, size_t relation_pos=0, size_t member_pos=0) noexcept : explicit MemberMeta(osmium::object_id_type member_id, size_t relation_pos, size_t member_pos) noexcept :
m_member_id(member_id), m_member_id(member_id),
m_relation_pos(relation_pos), m_relation_pos(relation_pos),
m_member_pos(member_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 { osmium::object_id_type member_id() const noexcept {
return m_member_id; return m_member_id;
} }
@ -107,6 +128,11 @@ namespace osmium {
void set_buffer_offset(size_t offset) noexcept { void set_buffer_offset(size_t offset) noexcept {
m_buffer_offset = offset; m_buffer_offset = offset;
m_available = true;
}
bool is_available() const noexcept {
return m_available;
} }
bool removed() const noexcept { bool removed() const noexcept {
@ -124,8 +150,8 @@ namespace osmium {
* Used to sort a vector of MemberMeta objects and to later find * Used to sort a vector of MemberMeta objects and to later find
* them using binary search. * them using binary search.
*/ */
inline bool operator<(const MemberMeta& a, const MemberMeta& b) noexcept { inline bool operator<(const MemberMeta& lhs, const MemberMeta& rhs) noexcept {
return a.member_id() < b.member_id(); return lhs.member_id() < rhs.member_id();
} }
template <typename TChar, typename TTraits> template <typename TChar, typename TTraits>

View File

@ -51,7 +51,7 @@ namespace osmium {
namespace thread { 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. * A thread-safe queue.
@ -70,9 +70,12 @@ namespace osmium {
std::queue<T> m_queue; 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; 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 #ifdef OSMIUM_DEBUG_QUEUE_SIZE
/// The largest size the queue has been so far. /// The largest size the queue has been so far.
size_t m_largest_size; size_t m_largest_size;
@ -109,7 +112,8 @@ namespace osmium {
m_name(name), m_name(name),
m_mutex(), m_mutex(),
m_queue(), m_queue(),
m_data_available() m_data_available(),
m_space_available()
#ifdef OSMIUM_DEBUG_QUEUE_SIZE #ifdef OSMIUM_DEBUG_QUEUE_SIZE
, ,
m_largest_size(0), m_largest_size(0),
@ -123,13 +127,20 @@ namespace osmium {
~Queue() { ~Queue() {
#ifdef OSMIUM_DEBUG_QUEUE_SIZE #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 #endif
} }
/** /**
* Push an element onto the queue. If the queue has a max size, this * Push an element onto the queue. If the queue has a max size,
* call will block if the queue is full. * this call will block if the queue is full.
*/ */
void push(T value) { void push(T value) {
#ifdef OSMIUM_DEBUG_QUEUE_SIZE #ifdef OSMIUM_DEBUG_QUEUE_SIZE
@ -137,13 +148,16 @@ namespace osmium {
#endif #endif
if (m_max_size) { if (m_max_size) {
while (size() >= 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 #ifdef OSMIUM_DEBUG_QUEUE_SIZE
++m_full_counter; ++m_full_counter;
#endif #endif
} }
} }
std::lock_guard<std::mutex> lock(m_mutex); std::lock_guard<std::mutex> lock{m_mutex};
m_queue.push(std::move(value)); m_queue.push(std::move(value));
#ifdef OSMIUM_DEBUG_QUEUE_SIZE #ifdef OSMIUM_DEBUG_QUEUE_SIZE
if (m_largest_size < m_queue.size()) { if (m_largest_size < m_queue.size()) {
@ -157,7 +171,7 @@ namespace osmium {
#ifdef OSMIUM_DEBUG_QUEUE_SIZE #ifdef OSMIUM_DEBUG_QUEUE_SIZE
++m_pop_counter; ++m_pop_counter;
#endif #endif
std::unique_lock<std::mutex> lock(m_mutex); std::unique_lock<std::mutex> lock{m_mutex};
#ifdef OSMIUM_DEBUG_QUEUE_SIZE #ifdef OSMIUM_DEBUG_QUEUE_SIZE
if (m_queue.empty()) { if (m_queue.empty()) {
++m_empty_counter; ++m_empty_counter;
@ -169,6 +183,10 @@ namespace osmium {
if (!m_queue.empty()) { if (!m_queue.empty()) {
value = std::move(m_queue.front()); value = std::move(m_queue.front());
m_queue.pop(); 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 #ifdef OSMIUM_DEBUG_QUEUE_SIZE
++m_pop_counter; ++m_pop_counter;
#endif #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 #ifdef OSMIUM_DEBUG_QUEUE_SIZE
++m_empty_counter; ++m_empty_counter;
#endif #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; return true;
} }
bool empty() const { bool empty() const {
std::lock_guard<std::mutex> lock(m_mutex); std::lock_guard<std::mutex> lock{m_mutex};
return m_queue.empty(); return m_queue.empty();
} }
size_t size() const { size_t size() const {
std::lock_guard<std::mutex> lock(m_mutex); std::lock_guard<std::mutex> lock{m_mutex};
return m_queue.size(); return m_queue.size();
} }

View File

@ -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 }; // class ProgressBar
} // namespace osmium } // namespace osmium

View File

@ -34,9 +34,9 @@ DEALINGS IN THE SOFTWARE.
*/ */
#define LIBOSMIUM_VERSION_MAJOR 2 #define LIBOSMIUM_VERSION_MAJOR 2
#define LIBOSMIUM_VERSION_MINOR 9 #define LIBOSMIUM_VERSION_MINOR 10
#define LIBOSMIUM_VERSION_PATCH 0 #define LIBOSMIUM_VERSION_PATCH 0
#define LIBOSMIUM_VERSION_STRING "2.9.0" #define LIBOSMIUM_VERSION_STRING "2.10.0"
#endif // OSMIUM_VERSION_HPP #endif // OSMIUM_VERSION_HPP

View File

@ -112,12 +112,6 @@ if(NOT Threads_FOUND)
set(Threads_FOUND FALSE) set(Threads_FOUND FALSE)
endif() 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_area_id)
add_unit_test(area test_node_ref_segment) add_unit_test(area test_node_ref_segment)
add_unit_test(basic test_area) add_unit_test(osm test_area)
add_unit_test(basic test_box) add_unit_test(osm test_box)
add_unit_test(basic test_changeset) add_unit_test(osm test_changeset)
add_unit_test(basic test_crc) add_unit_test(osm test_crc)
add_unit_test(basic test_entity_bits) add_unit_test(osm test_entity_bits)
add_unit_test(basic test_location) add_unit_test(osm test_location)
add_unit_test(basic test_node) add_unit_test(osm test_node)
add_unit_test(basic test_node_ref) add_unit_test(osm test_node_ref)
add_unit_test(basic test_object_comparisons) add_unit_test(osm test_object_comparisons)
add_unit_test(basic test_relation) add_unit_test(osm test_relation)
add_unit_test(basic test_timestamp) add_unit_test(osm test_timestamp)
add_unit_test(basic test_types_from_string) add_unit_test(osm test_types_from_string)
add_unit_test(basic test_way) add_unit_test(osm test_way)
add_unit_test(buffer test_buffer_basics) add_unit_test(memory test_buffer_basics)
add_unit_test(buffer test_buffer_node) add_unit_test(memory test_buffer_node)
add_unit_test(buffer test_buffer_purge) add_unit_test(memory test_buffer_purge)
add_unit_test(builder test_attr) add_unit_test(builder test_attr)
add_unit_test(builder test_object_builder)
add_unit_test(geom test_factory_with_projection
ENABLE_IF ${GEOS_AND_PROJ_FOUND}
LIBS ${GEOS_LIBRARY} ${PROJ_LIBRARY})
add_unit_test(geom test_crs ENABLE_IF ${PROJ_FOUND} LIBS ${PROJ_LIBRARY}) add_unit_test(geom test_crs ENABLE_IF ${PROJ_FOUND} LIBS ${PROJ_LIBRARY})
add_unit_test(geom test_exception) 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_geojson)
add_unit_test(geom test_geos ENABLE_IF ${GEOS_FOUND} LIBS ${GEOS_LIBRARY}) 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_mercator)
add_unit_test(geom test_ogr ENABLE_IF ${GDAL_FOUND} LIBS ${GDAL_LIBRARY}) 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_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_wkb)
add_unit_test(geom test_wkt) 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_id_to_location ENABLE_IF ${SPARSEHASH_FOUND})
add_unit_test(index test_file_based_index) 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_bzip2 ENABLE_IF ${BZIP2_FOUND} LIBS ${BZIP2_LIBRARIES})
add_unit_test(io test_file_formats) add_unit_test(io test_file_formats)
add_unit_test(io test_reader LIBS "${OSMIUM_XML_LIBRARIES};${OSMIUM_PBF_LIBRARIES}") add_unit_test(io test_reader LIBS "${OSMIUM_XML_LIBRARIES};${OSMIUM_PBF_LIBRARIES}")

View File

@ -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::move(input));
osmium::io::detail::add_to_queue(input_queue, std::string{}); 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(); parser.parse();
header_buffer_type result; header_buffer_type result;

View File

@ -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")
#-----------------------------------------------------------------------------

View File

@ -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$")

View File

@ -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>

View File

@ -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$"
)

View File

@ -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>

View File

@ -1,6 +1,6 @@
/* /*
* Catch v1.5.6 * Catch v1.5.8
* Generated: 2016-06-09 19:20:41.460328 * Generated: 2016-10-26 12:07:30.938259
* ---------------------------------------------------------- * ----------------------------------------------------------
* This file has been merged from multiple headers. Please don't edit it directly * This file has been merged from multiple headers. Please don't edit it directly
* Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved.
@ -3223,10 +3223,11 @@ namespace Catch {
bool matches( TestCaseInfo const& testCase ) const { bool matches( TestCaseInfo const& testCase ) const {
// All patterns in a filter must match for the filter to be a match // 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 ) ) if( !(*it)->matches( testCase ) )
return false; return false;
return true; }
return true;
} }
}; };
@ -4719,8 +4720,11 @@ namespace Catch {
std::string line; std::string line;
while( std::getline( f, line ) ) { while( std::getline( f, line ) ) {
line = trim(line); line = trim(line);
if( !line.empty() && !startsWith( line, "#" ) ) if( !line.empty() && !startsWith( line, "#" ) ) {
addTestOrTags( config, "\"" + line + "\"," ); if( !startsWith( line, "\"" ) )
line = "\"" + line + "\"";
addTestOrTags( config, line + "," );
}
} }
} }
@ -5368,7 +5372,10 @@ namespace Catch {
++it ) { ++it ) {
matchedTests++; matchedTests++;
TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); 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; return matchedTests;
} }
@ -6454,7 +6461,7 @@ namespace Catch {
namespace Catch { namespace Catch {
struct RandomNumberGenerator { struct RandomNumberGenerator {
typedef int result_type; typedef std::ptrdiff_t result_type;
result_type operator()( result_type n ) const { return std::rand() % n; } result_type operator()( result_type n ) const { return std::rand() % n; }
@ -7571,7 +7578,7 @@ namespace Catch {
return os; 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 ) { bool contains( std::string const& s, std::string const& infix ) {
return s.find( infix ) != std::string::npos; return s.find( infix ) != std::string::npos;
} }
char toLowerCh(char c) {
return static_cast<char>( ::tolower( c ) );
}
void toLowerInPlace( std::string& s ) { 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 toLower( std::string const& s ) {
std::string lc = s; std::string lc = s;
@ -8951,9 +8961,10 @@ namespace Catch {
break; break;
default: 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' ) 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 else
os << c; os << c;
} }
@ -9008,13 +9019,20 @@ namespace Catch {
: m_tagIsOpen( false ), : m_tagIsOpen( false ),
m_needsNewline( false ), m_needsNewline( false ),
m_os( &Catch::cout() ) 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 ) XmlWriter( std::ostream& os )
: m_tagIsOpen( false ), : m_tagIsOpen( false ),
m_needsNewline( false ), m_needsNewline( false ),
m_os( &os ) m_os( &os )
{} {
*m_os << "<?xml version=\"1.1\" encoding=\"UTF-8\"?>\n";
}
~XmlWriter() { ~XmlWriter() {
while( !m_tags.empty() ) while( !m_tags.empty() )
@ -9181,7 +9199,7 @@ namespace Catch {
virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE {
StreamingReporterBase::testCaseStarting(testInfo); 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 ) if ( m_config->showDurations() == ShowDurations::Always )
m_testCaseTimer.start(); m_testCaseTimer.start();
@ -9243,7 +9261,7 @@ namespace Catch {
.writeText( assertionResult.getMessage() ); .writeText( assertionResult.getMessage() );
break; break;
case ResultWas::FatalErrorCondition: case ResultWas::FatalErrorCondition:
m_xml.scopedElement( "Fatal Error Condition" ) m_xml.scopedElement( "FatalErrorCondition" )
.writeAttribute( "filename", assertionResult.getSourceInfo().file ) .writeAttribute( "filename", assertionResult.getSourceInfo().file )
.writeAttribute( "line", assertionResult.getSourceInfo().line ) .writeAttribute( "line", assertionResult.getSourceInfo().line )
.writeText( assertionResult.getMessage() ); .writeText( assertionResult.getMessage() );

View File

@ -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));
}
}

View File

@ -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());
}

View File

@ -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

View File

@ -5,12 +5,12 @@
#include <osmium/geom/projection.hpp> #include <osmium/geom/projection.hpp>
TEST_CASE("CRS") { TEST_CASE("CRS") {
osmium::geom::CRS wgs84{4326}; const osmium::geom::CRS wgs84{4326};
osmium::geom::CRS mercator{3857}; const osmium::geom::CRS mercator{3857};
osmium::geom::Coordinates c{osmium::geom::deg_to_rad(1.2), osmium::geom::deg_to_rad(3.4)}; const 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); const auto ct = osmium::geom::transform(wgs84, mercator, c);
auto c2 = osmium::geom::transform(mercator, wgs84, ct); const auto c2 = osmium::geom::transform(mercator, wgs84, ct);
REQUIRE(c.x == Approx(c2.x)); REQUIRE(c.x == Approx(c2.x));
REQUIRE(c.y == Approx(c2.y)); REQUIRE(c.y == Approx(c2.y));

View File

@ -6,11 +6,9 @@
TEST_CASE("Geometry exception") { TEST_CASE("Geometry exception") {
SECTION("geometry_error") { osmium::geometry_error e{"some error message", "node", 17};
osmium::geometry_error e("some error message", "node", 17); REQUIRE(e.id() == 17);
REQUIRE(e.id() == 17); REQUIRE(std::string{e.what()} == "some error message (node_id=17)");
REQUIRE(std::string(e.what()) == "some error message (node_id=17)");
}
} }

View File

@ -1,41 +1,21 @@
#include "catch.hpp" #include "catch.hpp"
#include <osmium/geom/geos.hpp>
#include <osmium/geom/mercator_projection.hpp> #include <osmium/geom/mercator_projection.hpp>
#include <osmium/geom/projection.hpp> #include <osmium/geom/projection.hpp>
#include <osmium/geom/wkb.hpp> #include <osmium/geom/wkb.hpp>
#include <osmium/geom/wkt.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);
}
SECTION("cleanup") {
// trying to make valgrind happy, but there is still a memory leak in proj library
pj_deallocate_grids();
}
const std::string wkt{factory.create_point(osmium::Location{3.2, 4.2})};
REQUIRE(wkt == "POINT(356222.37 467961.14)");
} }
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)");
}

View File

@ -5,162 +5,143 @@
#include "area_helper.hpp" #include "area_helper.hpp"
#include "wnl_helper.hpp" #include "wnl_helper.hpp"
TEST_CASE("GeoJSON_Geometry") { TEST_CASE("GeoJSON point geometry") {
SECTION("point") {
osmium::geom::GeoJSONFactory<> factory; osmium::geom::GeoJSONFactory<> factory;
std::string json {factory.create_point(osmium::Location(3.2, 4.2))}; SECTION("point") {
REQUIRE(std::string{"{\"type\":\"Point\",\"coordinates\":[3.2,4.2]}"} == json); 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") {
REQUIRE_THROWS_AS(factory.create_point(osmium::Location{}), osmium::invalid_location);
}
} }
SECTION("empty_point") { TEST_CASE("GeoJSON linestring geometry") {
osmium::geom::GeoJSONFactory<> factory; osmium::geom::GeoJSONFactory<> factory;
osmium::memory::Buffer buffer{1000};
REQUIRE_THROWS_AS(factory.create_point(osmium::Location()), osmium::invalid_location); SECTION("linestring, default") {
} const auto& wnl = create_test_wnl_okay(buffer);
const std::string json{factory.create_linestring(wnl)};
SECTION("linestring") {
osmium::geom::GeoJSONFactory<> factory;
osmium::memory::Buffer buffer(1000);
auto &wnl = create_test_wnl_okay(buffer);
{
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); REQUIRE(std::string{"{\"type\":\"LineString\",\"coordinates\":[[3.2,4.2],[3.5,4.7],[3.6,4.9]]}"} == json);
} }
{ SECTION("linestring, unique, backwards") {
std::string json {factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward)}; 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); REQUIRE(std::string{"{\"type\":\"LineString\",\"coordinates\":[[3.6,4.9],[3.5,4.7],[3.2,4.2]]}"} == json);
} }
{ SECTION("linestring, all") {
std::string json {factory.create_linestring(wnl, osmium::geom::use_nodes::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); REQUIRE(std::string{"{\"type\":\"LineString\",\"coordinates\":[[3.2,4.2],[3.5,4.7],[3.5,4.7],[3.6,4.9]]}"} == json);
} }
{ SECTION("linestring, all, backwards") {
std::string json {factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward)}; 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); 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") { SECTION("empty_linestring") {
osmium::geom::GeoJSONFactory<> factory; const auto& wnl = create_test_wnl_empty(buffer);
osmium::memory::Buffer buffer(1000); REQUIRE_THROWS_AS(factory.create_linestring(wnl), osmium::geometry_error);
auto& wnl = create_test_wnl_empty(buffer); 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::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::geom::use_nodes::unique, osmium::geom::direction::backward), osmium::geometry_error);
REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::all), osmium::geometry_error);
REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward), osmium::geometry_error);
}
SECTION("linestring_with_two_same_locations") {
osmium::geom::GeoJSONFactory<> factory;
osmium::memory::Buffer buffer(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);
{
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);
} }
{ SECTION("linestring with two same locations") {
std::string json {factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward)}; const auto& wnl = create_test_wnl_same_location(buffer);
REQUIRE(std::string{"{\"type\":\"LineString\",\"coordinates\":[[3.5,4.7],[3.5,4.7]]}"} == json);
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);
}
{
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);
}
} }
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") { TEST_CASE("GeoJSON area geometry") {
osmium::geom::GeoJSONFactory<> factory; osmium::geom::GeoJSONFactory<> factory;
osmium::memory::Buffer buffer{1000};
osmium::memory::Buffer buffer(1000); SECTION("area_1outer_0inner") {
auto& wnl = create_test_wnl_undefined_location(buffer); const osmium::Area& area = create_test_area_1outer_0inner(buffer);
REQUIRE_THROWS_AS(factory.create_linestring(wnl), osmium::invalid_location); REQUIRE(!area.is_multipolygon());
} REQUIRE(std::distance(area.cbegin(), area.cend()) == 2);
REQUIRE(area.subitems<osmium::OuterRing>().size() == area.num_rings().first);
SECTION("area_1outer_0inner") { std::string json{factory.create_multipolygon(area)};
osmium::geom::GeoJSONFactory<> factory;
osmium::memory::Buffer buffer(1000);
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);
{
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); 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") { SECTION("area_1outer_1inner") {
osmium::geom::GeoJSONFactory<> factory; const osmium::Area& area = create_test_area_1outer_1inner(buffer);
osmium::memory::Buffer buffer(1000); REQUIRE(!area.is_multipolygon());
const osmium::Area& area = create_test_area_1outer_1inner(buffer); 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()); std::string json{factory.create_multipolygon(area)};
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)};
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); 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") { SECTION("area_2outer_2inner") {
osmium::geom::GeoJSONFactory<> factory; const osmium::Area& area = create_test_area_2outer_2inner(buffer);
osmium::memory::Buffer buffer(1000); REQUIRE(area.is_multipolygon());
const osmium::Area& area = create_test_area_2outer_2inner(buffer); 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);
REQUIRE(area.is_multipolygon()); int outer_ring=0;
REQUIRE(std::distance(area.cbegin(), area.cend()) == 5); int inner_ring=0;
REQUIRE(area.subitems<osmium::OuterRing>().size() == area.num_rings().first); for (const auto& outer : area.outer_rings()) {
REQUIRE(area.subitems<osmium::InnerRing>().size() == area.num_rings().second); if (outer_ring == 0) {
REQUIRE(outer.front().ref() == 1);
int outer_ring=0; } else if (outer_ring == 1) {
int inner_ring=0; REQUIRE(outer.front().ref() == 100);
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);
} else { } else {
REQUIRE(false); 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); 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);
} }
}
} }

View File

@ -1,6 +1,10 @@
#include "catch.hpp"
#include <osmium/geom/geos.hpp> #include <osmium/geom/geos.hpp>
#ifdef OSMIUM_WITH_GEOS
#include "catch.hpp"
#include <osmium/geom/mercator_projection.hpp> #include <osmium/geom/mercator_projection.hpp>
#include "area_helper.hpp" #include "area_helper.hpp"
@ -9,7 +13,7 @@
TEST_CASE("GEOS geometry factory - create point") { TEST_CASE("GEOS geometry factory - create point") {
osmium::geom::GEOSFactory<> factory; 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(3.2 == point->getX());
REQUIRE(4.2 == point->getY()); REQUIRE(4.2 == point->getY());
REQUIRE(4326 == point->getSRID()); 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") { TEST_CASE("GEOS geometry factory - create point in web mercator") {
osmium::geom::GEOSFactory<osmium::geom::MercatorProjection> factory; 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(356222.3705384755l) == point->getX());
REQUIRE(Approx(467961.143605213l) == point->getY()); REQUIRE(Approx(467961.143605213l) == point->getY());
REQUIRE(3857 == point->getSRID()); 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") { TEST_CASE("GEOS geometry factory - create point with externally created GEOS factory") {
geos::geom::GeometryFactory 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(3.2 == point->getX());
REQUIRE(4.2 == point->getY()); REQUIRE(4.2 == point->getY());
REQUIRE(0 == point->getSRID()); 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") { TEST_CASE("GEOS geometry factory - can not create from invalid location") {
osmium::geom::GEOSFactory<> factory; 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") { TEST_CASE("GEOS geometry factory - create linestring") {
osmium::geom::GEOSFactory<> factory; osmium::geom::GEOSFactory<> factory;
osmium::memory::Buffer buffer(10000); osmium::memory::Buffer buffer{10000};
auto &wnl = create_test_wnl_okay(buffer); const auto& wnl = create_test_wnl_okay(buffer);
SECTION("from way node list") { 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()); 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()); 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()); REQUIRE(3.6 == p2->getX());
} }
SECTION("without duplicates and backwards") { 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()); 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()); 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()); REQUIRE(3.2 == p2->getX());
} }
SECTION("with duplicates") { 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()); 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()); REQUIRE(3.2 == p0->getX());
} }
SECTION("with duplicates and backwards") { 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()); 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()); 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") { TEST_CASE("GEOS geometry factory - create area with one outer and no inner rings") {
osmium::geom::GEOSFactory<> factory; osmium::geom::GEOSFactory<> factory;
osmium::memory::Buffer buffer(10000); osmium::memory::Buffer buffer{10000};
const osmium::Area& area = create_test_area_1outer_0inner(buffer); 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()); REQUIRE(1 == mp->getNumGeometries());
const geos::geom::Polygon* p0 = dynamic_cast<const geos::geom::Polygon*>(mp->getGeometryN(0)); 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(); const geos::geom::LineString* l0e = p0->getExteriorRing();
REQUIRE(4 == l0e->getNumPoints()); 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()); REQUIRE(3.5 == l0e_p0->getX());
} }
TEST_CASE("GEOS geometry factory - create area with one outer and one inner ring") { TEST_CASE("GEOS geometry factory - create area with one outer and one inner ring") {
osmium::geom::GEOSFactory<> factory; osmium::geom::GEOSFactory<> factory;
osmium::memory::Buffer buffer(10000); osmium::memory::Buffer buffer{10000};
const osmium::Area& area = create_test_area_1outer_1inner(buffer); 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()); REQUIRE(1 == mp->getNumGeometries());
const geos::geom::Polygon* p0 = dynamic_cast<const geos::geom::Polygon*>(mp->getGeometryN(0)); 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") { TEST_CASE("GEOS geometry factory - create area with two outer and two inner rings") {
osmium::geom::GEOSFactory<> factory; osmium::geom::GEOSFactory<> factory;
osmium::memory::Buffer buffer(10000); osmium::memory::Buffer buffer{10000};
const osmium::Area& area = create_test_area_2outer_2inner(buffer); 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()); REQUIRE(2 == mp->getNumGeometries());
const geos::geom::Polygon* p0 = dynamic_cast<const geos::geom::Polygon*>(mp->getGeometryN(0)); 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()); REQUIRE(5 == l1e->getNumPoints());
} }
#endif

View File

@ -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);
}
}

View File

@ -5,121 +5,115 @@
#include "area_helper.hpp" #include "area_helper.hpp"
#include "wnl_helper.hpp" #include "wnl_helper.hpp"
TEST_CASE("OGR_Geometry") { TEST_CASE("OGR point geometry") {
SECTION("point") {
osmium::geom::OGRFactory<> factory; osmium::geom::OGRFactory<> factory;
std::unique_ptr<OGRPoint> point {factory.create_point(osmium::Location(3.2, 4.2))}; SECTION("point") {
REQUIRE(3.2 == point->getX()); std::unique_ptr<OGRPoint> point{factory.create_point(osmium::Location{3.2, 4.2})};
REQUIRE(4.2 == point->getY()); REQUIRE(3.2 == point->getX());
REQUIRE(4.2 == point->getY());
}
SECTION("empty_point") {
REQUIRE_THROWS_AS(factory.create_point(osmium::Location()), osmium::invalid_location);
}
} }
SECTION("empty_point") { TEST_CASE("OGR linestring geometry") {
osmium::geom::OGRFactory<> factory; osmium::geom::OGRFactory<> factory;
osmium::memory::Buffer buffer{10000};
const auto& wnl = create_test_wnl_okay(buffer);
REQUIRE_THROWS_AS(factory.create_point(osmium::Location()), osmium::invalid_location); SECTION("linestring, default") {
} std::unique_ptr<OGRLineString> linestring{factory.create_linestring(wnl)};
SECTION("linestring") {
osmium::geom::OGRFactory<> factory;
osmium::memory::Buffer buffer(10000);
auto &wnl = create_test_wnl_okay(buffer);
{
std::unique_ptr<OGRLineString> linestring {factory.create_linestring(wnl)};
REQUIRE(3 == linestring->getNumPoints()); REQUIRE(3 == linestring->getNumPoints());
REQUIRE(3.2 == linestring->getX(0)); REQUIRE(3.2 == linestring->getX(0));
REQUIRE(3.6 == linestring->getX(2)); REQUIRE(3.6 == linestring->getX(2));
} }
{ SECTION("linestring, unique nodes, backwards") {
std::unique_ptr<OGRLineString> linestring {factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward)}; std::unique_ptr<OGRLineString> linestring{factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward)};
REQUIRE(3 == linestring->getNumPoints()); REQUIRE(3 == linestring->getNumPoints());
REQUIRE(3.6 == linestring->getX(0)); REQUIRE(3.6 == linestring->getX(0));
REQUIRE(3.2 == linestring->getX(2)); REQUIRE(3.2 == linestring->getX(2));
} }
{ SECTION("linestring, all nodes") {
std::unique_ptr<OGRLineString> linestring {factory.create_linestring(wnl, osmium::geom::use_nodes::all)}; std::unique_ptr<OGRLineString> linestring{factory.create_linestring(wnl, osmium::geom::use_nodes::all)};
REQUIRE(4 == linestring->getNumPoints()); REQUIRE(4 == linestring->getNumPoints());
REQUIRE(3.2 == linestring->getX(0)); REQUIRE(3.2 == linestring->getX(0));
} }
{ SECTION("linestring, all nodes, backwards") {
std::unique_ptr<OGRLineString> linestring {factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward)}; std::unique_ptr<OGRLineString> linestring{factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward)};
REQUIRE(4 == linestring->getNumPoints()); REQUIRE(4 == linestring->getNumPoints());
REQUIRE(3.6 == linestring->getX(0)); REQUIRE(3.6 == linestring->getX(0));
} }
} }
SECTION("area_1outer_0inner") { TEST_CASE("OGR area geometry") {
osmium::geom::OGRFactory<> factory; osmium::geom::OGRFactory<> factory;
osmium::memory::Buffer buffer{10000};
osmium::memory::Buffer buffer(10000); SECTION("area_1outer_0inner") {
const osmium::Area& area = create_test_area_1outer_0inner(buffer); const osmium::Area& area = create_test_area_1outer_0inner(buffer);
std::unique_ptr<OGRMultiPolygon> mp {factory.create_multipolygon(area)}; std::unique_ptr<OGRMultiPolygon> mp {factory.create_multipolygon(area)};
REQUIRE(1 == mp->getNumGeometries()); REQUIRE(1 == mp->getNumGeometries());
const OGRPolygon* p0 = dynamic_cast<const OGRPolygon*>(mp->getGeometryRef(0)); const OGRPolygon* p0 = dynamic_cast<const OGRPolygon*>(mp->getGeometryRef(0));
REQUIRE(p0); REQUIRE(p0);
REQUIRE(0 == p0->getNumInteriorRings()); REQUIRE(0 == p0->getNumInteriorRings());
const OGRLineString* l0e = p0->getExteriorRing(); const OGRLineString* l0e = p0->getExteriorRing();
REQUIRE(4 == l0e->getNumPoints()); REQUIRE(4 == l0e->getNumPoints());
REQUIRE(3.5 == l0e->getX(1)); REQUIRE(3.5 == l0e->getX(1));
} }
SECTION("area_1outer_1inner") { SECTION("area_1outer_1inner") {
osmium::geom::OGRFactory<> factory; const osmium::Area& area = create_test_area_1outer_1inner(buffer);
osmium::memory::Buffer buffer(10000); std::unique_ptr<OGRMultiPolygon> mp {factory.create_multipolygon(area)};
const osmium::Area& area = create_test_area_1outer_1inner(buffer); REQUIRE(1 == mp->getNumGeometries());
std::unique_ptr<OGRMultiPolygon> mp {factory.create_multipolygon(area)}; const OGRPolygon* p0 = dynamic_cast<const OGRPolygon*>(mp->getGeometryRef(0));
REQUIRE(1 == mp->getNumGeometries()); REQUIRE(p0);
REQUIRE(1 == p0->getNumInteriorRings());
const OGRPolygon* p0 = dynamic_cast<const OGRPolygon*>(mp->getGeometryRef(0)); const OGRLineString* l0e = p0->getExteriorRing();
REQUIRE(p0); REQUIRE(5 == l0e->getNumPoints());
REQUIRE(1 == p0->getNumInteriorRings());
const OGRLineString* l0e = p0->getExteriorRing(); const OGRLineString* l0i0 = p0->getInteriorRing(0);
REQUIRE(5 == l0e->getNumPoints()); REQUIRE(5 == l0i0->getNumPoints());
}
const OGRLineString* l0i0 = p0->getInteriorRing(0); SECTION("area_2outer_2inner") {
REQUIRE(5 == l0i0->getNumPoints()); const osmium::Area& area = create_test_area_2outer_2inner(buffer);
}
SECTION("area_2outer_2inner") { std::unique_ptr<OGRMultiPolygon> mp {factory.create_multipolygon(area)};
osmium::geom::OGRFactory<> factory; REQUIRE(2 == mp->getNumGeometries());
osmium::memory::Buffer buffer(10000); const OGRPolygon* p0 = dynamic_cast<const OGRPolygon*>(mp->getGeometryRef(0));
const osmium::Area& area = create_test_area_2outer_2inner(buffer); REQUIRE(p0);
REQUIRE(2 == p0->getNumInteriorRings());
std::unique_ptr<OGRMultiPolygon> mp {factory.create_multipolygon(area)}; const OGRLineString* l0e = p0->getExteriorRing();
REQUIRE(2 == mp->getNumGeometries()); REQUIRE(5 == l0e->getNumPoints());
const OGRPolygon* p0 = dynamic_cast<const OGRPolygon*>(mp->getGeometryRef(0)); const OGRPolygon* p1 = dynamic_cast<const OGRPolygon*>(mp->getGeometryRef(1));
REQUIRE(p0); REQUIRE(p1);
REQUIRE(2 == p0->getNumInteriorRings()); REQUIRE(0 == p1->getNumInteriorRings());
const OGRLineString* l0e = p0->getExteriorRing(); const OGRLineString* l1e = p1->getExteriorRing();
REQUIRE(5 == l0e->getNumPoints()); REQUIRE(5 == l1e->getNumPoints());
}
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());
}
} }

View File

@ -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

View File

@ -6,144 +6,121 @@
#include <osmium/geom/mercator_projection.hpp> #include <osmium/geom/mercator_projection.hpp>
#include <osmium/geom/projection.hpp> #include <osmium/geom/projection.hpp>
TEST_CASE("Projection") { TEST_CASE("Indentity Projection") {
SECTION("identity_projection") {
osmium::geom::IdentityProjection projection; osmium::geom::IdentityProjection projection;
REQUIRE(4326 == projection.epsg()); REQUIRE(4326 == projection.epsg());
REQUIRE("+proj=longlat +datum=WGS84 +no_defs" == projection.proj_string()); REQUIRE("+proj=longlat +datum=WGS84 +no_defs" == projection.proj_string());
} }
SECTION("project_location_4326") { TEST_CASE("Projection 4326") {
osmium::geom::Projection projection(4326); osmium::geom::Projection projection{4326};
REQUIRE(4326 == projection.epsg()); REQUIRE(4326 == projection.epsg());
REQUIRE("+init=epsg:4326" == projection.proj_string()); REQUIRE("+init=epsg:4326" == projection.proj_string());
const osmium::Location loc(1.0, 2.0); const osmium::Location loc{1.0, 2.0};
const osmium::geom::Coordinates c {1.0, 2.0}; const osmium::geom::Coordinates c{1.0, 2.0};
REQUIRE(c == projection(loc)); REQUIRE(c == projection(loc));
} }
SECTION("project_location_4326_string") { TEST_CASE("Projection 4326 from init string") {
osmium::geom::Projection projection("+init=epsg:4326"); osmium::geom::Projection projection{"+init=epsg:4326"};
REQUIRE(-1 == projection.epsg()); REQUIRE(-1 == projection.epsg());
REQUIRE("+init=epsg:4326" == projection.proj_string()); REQUIRE("+init=epsg:4326" == projection.proj_string());
const osmium::Location loc(1.0, 2.0); const osmium::Location loc{1.0, 2.0};
const osmium::geom::Coordinates c {1.0, 2.0}; const osmium::geom::Coordinates c{1.0, 2.0};
REQUIRE(c == projection(loc)); REQUIRE(c == projection(loc));
} }
SECTION("unknown_projection_string") { TEST_CASE("Creating projection from unknown init string") {
REQUIRE_THROWS_AS(osmium::geom::Projection projection("abc"), osmium::projection_error); REQUIRE_THROWS_AS(osmium::geom::Projection projection{"abc"}, osmium::projection_error);
} }
SECTION("unknown_epsg_code") { TEST_CASE("Creating projection from unknown EPSG code") {
REQUIRE_THROWS_AS(osmium::geom::Projection projection(9999999), osmium::projection_error); REQUIRE_THROWS_AS(osmium::geom::Projection projection{9999999}, osmium::projection_error);
} }
SECTION("project_location_3857") { TEST_CASE("Projection 3857") {
osmium::geom::Projection projection(3857); osmium::geom::Projection projection{3857};
REQUIRE(3857 == projection.epsg()); REQUIRE(3857 == projection.epsg());
REQUIRE("+init=epsg:3857" == projection.proj_string()); REQUIRE("+init=epsg:3857" == projection.proj_string());
{ SECTION("Zero coordinates") {
const osmium::Location loc(0.0, 0.0); const osmium::Location loc{0.0, 0.0};
const osmium::geom::Coordinates c {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).x == Approx(c.x).epsilon(0.1));
REQUIRE(projection(loc).y == Approx(c.y).epsilon(0.1)); REQUIRE(projection(loc).y == Approx(c.y).epsilon(0.1));
} }
{
const osmium::Location loc(180.0, 0.0); SECTION("Max longitude") {
const osmium::geom::Coordinates c {20037508.34, 0.0}; 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).x == Approx(c.x).epsilon(0.1));
REQUIRE(projection(loc).y == Approx(c.y).epsilon(0.1)); REQUIRE(projection(loc).y == Approx(c.y).epsilon(0.1));
} }
{
const osmium::Location loc(180.0, 0.0); SECTION("Min longitude") {
const osmium::geom::Coordinates c {20037508.34, 0.0}; 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).x == Approx(c.x).epsilon(0.1));
REQUIRE(projection(loc).y == Approx(c.y).epsilon(0.1)); REQUIRE(projection(loc).y == Approx(c.y).epsilon(0.1));
} }
{
const osmium::Location loc(0.0, 85.0511288); SECTION("Max latitude") {
const osmium::geom::Coordinates c {0.0, 20037508.34}; 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).x == Approx(c.x).epsilon(0.1));
REQUIRE(projection(loc).y == Approx(c.y).epsilon(0.1)); REQUIRE(projection(loc).y == Approx(c.y).epsilon(0.1));
} }
} }
SECTION("project_location_mercator") { TEST_CASE("MercatorProjection") {
osmium::geom::MercatorProjection projection; osmium::geom::MercatorProjection projection;
{ SECTION("Zero coordinates") {
const osmium::Location loc(0.0, 0.0); const osmium::Location loc{0.0, 0.0};
const osmium::geom::Coordinates c {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).x == Approx(c.x).epsilon(0.1));
REQUIRE(projection(loc).y == Approx(c.y).epsilon(0.1)); REQUIRE(projection(loc).y == Approx(c.y).epsilon(0.1));
} }
{
const osmium::Location loc(180.0, 0.0); SECTION("Max longitude") {
const osmium::geom::Coordinates c {20037508.34, 0.0}; 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).x == Approx(c.x).epsilon(0.1));
REQUIRE(projection(loc).y == Approx(c.y).epsilon(0.1)); REQUIRE(projection(loc).y == Approx(c.y).epsilon(0.1));
} }
{
const osmium::Location loc(180.0, 0.0); SECTION("Min longitude") {
const osmium::geom::Coordinates c {20037508.34, 0.0}; 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).x == Approx(c.x).epsilon(0.1));
REQUIRE(projection(loc).y == Approx(c.y).epsilon(0.1)); REQUIRE(projection(loc).y == Approx(c.y).epsilon(0.1));
} }
{
const osmium::Location loc(0.0, 85.0511288); SECTION("Max latitude") {
const osmium::geom::Coordinates c {0.0, 20037508.34}; 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).x == Approx(c.x).epsilon(0.1));
REQUIRE(projection(loc).y == Approx(c.y).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::MercatorProjection projection_merc;
osmium::geom::Projection projection_3857(3857); osmium::geom::Projection projection_3857{3857};
REQUIRE(3857 == projection_3857.epsg());
REQUIRE("+init=epsg:3857" == projection_3857.proj_string());
{ SECTION("random coordinates") {
const osmium::Location loc(4.2, 27.3); std::random_device rd;
REQUIRE(projection_merc(loc).x == Approx(projection_3857(loc).x).epsilon(0.1)); std::mt19937 gen{rd()};
REQUIRE(projection_merc(loc).y == Approx(projection_3857(loc).y).epsilon(0.1)); std::uniform_real_distribution<> dis_x{-180.0, 180.0};
} std::uniform_real_distribution<> dis_y{-90.0, 90.0};
{
const osmium::Location loc(160.789, -42.42);
REQUIRE(projection_merc(loc).x == Approx(projection_3857(loc).x).epsilon(0.1));
REQUIRE(projection_merc(loc).y == Approx(projection_3857(loc).y).epsilon(0.1));
}
{
const osmium::Location loc(-0.001, 0.001);
REQUIRE(projection_merc(loc).x == Approx(projection_3857(loc).x).epsilon(0.1));
REQUIRE(projection_merc(loc).y == Approx(projection_3857(loc).y).epsilon(0.1));
}
{
const osmium::Location loc(-85.2, -85.2);
REQUIRE(projection_merc(loc).x == Approx(projection_3857(loc).x).epsilon(0.1));
REQUIRE(projection_merc(loc).y == Approx(projection_3857(loc).y).epsilon(0.1));
}
}
SECTION("compare_mercators") { for (int n = 0; n < 10000; ++n) {
osmium::geom::MercatorProjection projection_merc; const osmium::Location loc{dis_x(gen), dis_y(gen)};
osmium::geom::Projection projection_3857(3857); 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));
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));
} }
}
} }

View File

@ -4,8 +4,6 @@
#include <osmium/geom/tile.hpp> #include <osmium/geom/tile.hpp>
#include "helper.hpp"
#include "test_tile_data.hpp" #include "test_tile_data.hpp"
TEST_CASE("Tile from x0.0 y0.0 at zoom 0") { TEST_CASE("Tile from x0.0 y0.0 at zoom 0") {

Some files were not shown because too many files have changed in this diff Show More