Merge pull request #4456 from Project-OSRM/update/libosmium

Update libosmium to 2.13
This commit is contained in:
Patrick Niklaus 2017-08-30 18:30:25 +02:00 committed by GitHub
commit 28178b12c7
269 changed files with 16481 additions and 6739 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.11.3 OSMIUM_TAG=v2.13.1
VARIANT_REPO="https://github.com/mapbox/variant.git" VARIANT_REPO="https://github.com/mapbox/variant.git"
VARIANT_TAG=v1.1.3 VARIANT_TAG=v1.1.3

7
third_party/libosmium/.codecov.yml vendored Normal file
View File

@ -0,0 +1,7 @@
ignore:
- "include/gdalcpp.hpp"
- "include/protozero"
- "include/utf8"
- "test/include/catch.hpp"

View File

@ -1,4 +1,6 @@
*.swp *.swp
.ycm_extra_conf.pyc .ycm_extra_conf.pyc
/_build*
/build /build
/libosmium-deps /libosmium-deps
/.vs*

View File

@ -141,6 +141,14 @@ matrix:
packages: ['g++-6', 'libboost1.55-all-dev', 'libgdal-dev', 'libgeos++-dev', 'libproj-dev', 'libsparsehash-dev', 'spatialite-bin'] packages: ['g++-6', 'libboost1.55-all-dev', 'libgdal-dev', 'libgeos++-dev', 'libproj-dev', 'libsparsehash-dev', 'spatialite-bin']
env: COMPILER='g++-6' BUILD_TYPE='Dev' env: COMPILER='g++-6' BUILD_TYPE='Dev'
- os: linux
compiler: linux-gcc6-coverage
addons:
apt:
sources: ['ubuntu-toolchain-r-test', 'boost-latest']
packages: ['g++-6', 'libboost1.55-all-dev', 'libgdal-dev', 'libgeos++-dev', 'libproj-dev', 'libsparsehash-dev', 'spatialite-bin']
env: COMPILER='g++-6' BUILD_TYPE='Coverage'
# 3/ OSX Clang Builds # 3/ OSX Clang Builds
- os: osx - os: osx
@ -166,12 +174,12 @@ matrix:
- os: osx - os: osx
osx_image: xcode8 osx_image: xcode8.3
compiler: xcode8-clang-release compiler: xcode8-clang-release
env: COMPILER='clang++' BUILD_TYPE='Release' env: COMPILER='clang++' BUILD_TYPE='Release'
- os: osx - os: osx
osx_image: xcode8 osx_image: xcode8.3
compiler: xcode8-clang-dev compiler: xcode8-clang-dev
env: COMPILER='clang++' BUILD_TYPE='Dev' env: COMPILER='clang++' BUILD_TYPE='Dev'
@ -195,3 +203,16 @@ before_script:
script: script:
- make VERBOSE=1 && ctest --output-on-failure - make VERBOSE=1 && ctest --output-on-failure
after_success:
- |
if [ "${BUILD_TYPE}" = "Coverage" ]; then
curl -S -f https://codecov.io/bash -o codecov
chmod +x codecov
gcov-${COMPILER#g++-} -p $(find test/CMakeFiles -name '*.o')
./codecov -Z -c -F unit_tests
gcov-${COMPILER#g++-} -p $(find test/data-tests -name '*.o')
./codecov -Z -c -F data_tests
gcov-${COMPILER#g++-} -p $(find examples -name '*.o')
./codecov -Z -c -F examples
fi

View File

@ -6,9 +6,130 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## [unreleased] - ## [unreleased] -
### Added
### Changed
### Fixed ### Fixed
## [2.11.3] - 2017-05-03
## [2.13.1] - 2017-08-25
### Added
- New "blackhole" file format which throws away all data written into it.
Used for benchmarking.
### Changed
- When reading OPL files, CRLF file endings are now handled correctly.
- Reduce the max number of threads allowed for the `Pool` to 32. This should
still be plenty and might help with test failures on some architectures.
### Fixed
- Tests now run correctly independent of git `core.autocrlf` setting.
- Set binary mode for all files on Windows in example code.
- Low-level file functions now set an invalid parameter handler on Windows
to properly handle errors.
- Restore earlier behaviour allowing zero-length mmap. It is important to
allow zero-length memory mapping, because it is possible that such an index
is empty, for instance when one type of object is missing from an input
file as in https://github.com/osmcode/osmium-tool/issues/65. Drawback is
that files must be opened read-write for this to work, even if we only
want to read from them.
- Use Approx() to compare floating point values in tests.
- Fix broken `Item` test on 32 bit platforms.
## [2.13.0] - 2017-08-15
### Added
- New `RelationsManager` class superseeds the `relations::Collector` class.
The new class is much more modular and easier to extend. If you are using
the Collector class, you are encouraged to switch.
- New `MultipolygonManager` based on the `RelationsManager` class superseeds
the `MultipolygonCollector` class. The examples have been changed to use the
new class and all users are encouraged to switch. There is also a
`MultipolygonManagerLegacy` class if you still need old-style multipolygon
support (see below).
- New `FlexMem` index class that works with input files of any size and
stores the index in memory. This should now be used as the default index
for node location stores. Several example programs now use this index.
- New `CallbackBuffer` class, basically a convenient wrapper around the
`Buffer` class with an additional callback function that is called whenever
the buffer is full.
- Introduce new `ItemStash` class for storing OSM objects in memory.
- New `osmium::geom::overlaps()` function to check if two `Box` objects
overlap.
- Add function `IdSet::used_memory()` to get estimate of memory used in the
set.
- New `is_defined()` and `is_undefined()` methods on `Location` class.
- Tests for all provided example programs. (Some tests currently fail
on Windows for the `osmium_index_lookup` program.)
### Changed
- The area `Assembler` now doesn't work with old-style multipolygons (those
are multipolygon relations with the tags on the outer ways(s) instead of
on the relation) any more. Because old-style multipolygons are now (mostly)
gone from the OSM database this is usually what you want. The new
`AssemblerLegacy` class can be used if you actually need support for
old-style multipolygons, for instance if you are working with historical
data. (In that case you also need to use the `MultipolygonManagerLegacy`
class instead of the `MultipolygonManager` class.)
- Changes for consistent ordering of OSM data: OSM data can come in any order,
but usual OSM files are ordered by type, ID, and version. These changes
extend this ordering to negative IDs which are sometimes used for objects
that have not been uploaded to the OSM server yet. The negative IDs are
ordered now before the positive ones, both in order of their absolute value.
This is the same ordering as JOSM uses.
- Multipolygon assembler now checks for three or more overlapping segments
which are always an error and can report them.
- Enable use of user-provided `thread::Pool` instances in `Reader` and
`Writer` for special use cases.
- Growing a `Buffer` will now work with any capacity parameter, it is
always rounded up for proper alignment. Buffer constructor with three
arguments will now check that commmitted is not larger than capacity.
- Updated embedded protozero to 1.5.2.
- Update version of Catch unit test framework to 1.9.7.
- And, as always, lots of small code cleanups and more tests.
### Fixed
- Buffers larger than 2^32 bytes do now work.
- Output coordinate with value of -2^31 correctly.
- Changeset comments with more than 2^16 characters are now allowed. The new
maximum size is 2^32.
- `ChangesetDiscussionBuilder::add_comment_text()` could fail silently instead
of throwing an exception.
- Changeset bounding boxes are now always output to OSM files (any format)
if at least one of the corners is defined. This is needed to handle broken
data from the main OSM database which contains such cases. The OPL reader
has also been fixed to handle this case.
- In the example `osmium_location_cache_create`, the index file written is
always truncated first.
## [2.12.2] - 2017-05-03
### Added
- Add two argument (key, value) overload of `TagMatcher::operator()`.
### Changed
- Detect, report, and remove duplicate ways in multipolygon relations.
- Change EOF behaviour of Reader: The `Reader::read()` function will now
always return an invalid buffer exactly once to signal EOF.
- Update QGIS multipolygon project that is part of the test suite to show
more problem types.
- Copy multipolygon QGIS file for tests to build dir in cmake step.
- Some code cleanups and improved debug output in multipolygon code.
- Refactor I/O code to simplify code.
- Disable some warnings on MSVC.
- Various small code and build script changes.
### Fixed ### Fixed
@ -16,25 +137,94 @@ This project adheres to [Semantic Versioning](http://semver.org/).
multipolygons with overlapping or nearly overlapping lines. multipolygons with overlapping or nearly overlapping lines.
- Invalid use of iterators leading to undefined behaviour in area assembler - Invalid use of iterators leading to undefined behaviour in area assembler
code. code.
- Area assembler stats were not correctly counting inner rings that are
areas in their own right.
- Fix a thread problem valgrind found that might or might not be real.
- Read OPL file correctly even if trailing newline in file is missing. - Read OPL file correctly even if trailing newline in file is missing.
- Include order for `osmium/index/map` headers and
`osmium/index/node_locations_map.hpp` (or
`osmium/handler/node_locations_for_ways.hpp`) doesn't matter any more.
## [2.11.2] - 2017-04-10 ## [2.12.1] - 2017-04-10
### Added
- New `TagsFilter::set_default_result()` function.
### Changed
- Use larger capacity for `Buffer` if necessary for alignment instead of
throwing an exception. Minimum buffer size is now 64 bytes.
- Check order of input data in relations collector. The relations collector
can not deal with history data or a changes file. This was documented as a
requirement, but often lead to problems, because this was ignored by users.
So it now checks that the input data it gets is ordered and throws an
exception otherwise.
- When writing an OSM file, set generator to libosmium if not set by app.
### Fixed ### Fixed
- Use minimum size of 64 bytes for buffers. This fixes an infinite loop - Infinite loop in `Buffer::reserve_space()`. (Issue #202.)
when buffer size is zero. - `ObjectPointerCollection::unique()` now removes elements at end.
- Tests comparing double using `==` operator.
- Build on Cygwin.
## [2.11.1] - 2017-03-07 ## [2.12.0] - 2017-03-07
### Added
- `TagMatcher` and `TagsFilter` classes for more flexibly matching tags and
selecting objects based on tags. This obsoletes the less flexible classes
based on `osmium::tags::Filter` classes.
- Extended `index::RelationsMap(Stash|Index)` classes to also allow
parent-to-member lookups.
- New `nrw_array` helper class.
- `ObjectPointerCollection::unique()` function.
### Changed
- Area assembler can now detect invalid locations and report them in the
stats and through the problem reporter. If the new config option
`ignore_invalid_locations` is set, the Assembler will pretend they weren't
even referenced in the ways. (Issue #195.)
- `osmium::area::Assembler::operator()` will now return a boolean reporting
whether building of the area(s) was successful.
- Split up area `Assembler` class into three classes: The
`detail::BasicAssembler` is now the parent class. `Assembler` is the child
class for usual use. The new `GeomAssembler` also derives from
`BasicAssembler` and builds areas without taking tags into account at all.
This is to support osm2pgsql which does tag handling itself. (Issue #194.)
- The `Projection` class can do any projection supported by the Proj.4
library. As a special case it now uses our own Mercator projection
functions when the web mercator projection (EPSG 3857) is used. This is
much faster than going through Proj.4.
- Better error messages for low-level file utility functions.
- Mark `build_tag_list*` functions in `builder_helper.hpp` as deprecated. You
should use the functions from `osmium/builder/attr.hpp` instead.
- Improved performance of the `osmium::tags::match_(any|all|none)_of`
functions.
- Improved performance of string comparison in `tags::Filter`.
- Update version of Catch unit test framework to 1.8.1. This meant some
tests had to be updated.
- Use `get_noexcept()` in `NodeLocationsForWays` handler.
- And lots of code and test cleanups...
### Fixed ### Fixed
- Terminate called on full non-auto-growing buffer. (Issue #189.) - Terminate called on full non-auto-growing buffer. (Issue #189.)
- When file formats were used that were not compiled into the binary, it - When file formats were used that were not compiled into the binary, it
terminated instead of throwing. (Issue #197.) terminated instead of throwing. (Issue #197.)
- Windows build problem related to including two different winsock versions.
- Windows build problem related to forced build for old Windows versions.
(Issue #196.)
- Clear stream contents in ProblemReporterException correctly.
- Add `-pthread` compiler and linker options on Linux/OSX. This should fix
a problem where some linker versions will not link binaries correctly when
the `--as-needed` option is used.
- The `Filter::count()` method didn't compile at all. - The `Filter::count()` method didn't compile at all.
- XML reader doesn't fail on relation member ref=0 any more.
## [2.11.0] - 2017-01-14 ## [2.11.0] - 2017-01-14
@ -549,10 +739,12 @@ 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.11.3...HEAD [unreleased]: https://github.com/osmcode/libosmium/compare/v2.13.1...HEAD
[2.11.3]: https://github.com/osmcode/libosmium/compare/v2.11.2...v2.11.3 [2.13.1]: https://github.com/osmcode/libosmium/compare/v2.13.0...v2.13.1
[2.11.2]: https://github.com/osmcode/libosmium/compare/v2.11.1...v2.11.2 [2.13.0]: https://github.com/osmcode/libosmium/compare/v2.12.2...v2.13.0
[2.11.1]: https://github.com/osmcode/libosmium/compare/v2.11.0...v2.11.1 [2.12.2]: https://github.com/osmcode/libosmium/compare/v2.12.1...v2.12.2
[2.12.1]: https://github.com/osmcode/libosmium/compare/v2.12.0...v2.12.1
[2.12.0]: https://github.com/osmcode/libosmium/compare/v2.11.0...v2.12.0
[2.11.0]: https://github.com/osmcode/libosmium/compare/v2.10.3...v2.11.0 [2.11.0]: https://github.com/osmcode/libosmium/compare/v2.10.3...v2.11.0
[2.10.3]: https://github.com/osmcode/libosmium/compare/v2.10.2...v2.10.3 [2.10.3]: https://github.com/osmcode/libosmium/compare/v2.10.2...v2.10.3
[2.10.2]: https://github.com/osmcode/libosmium/compare/v2.10.1...v2.10.2 [2.10.2]: https://github.com/osmcode/libosmium/compare/v2.10.1...v2.10.2

View File

@ -24,8 +24,8 @@ 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 11) set(LIBOSMIUM_VERSION_MINOR 13)
set(LIBOSMIUM_VERSION_PATCH 3) set(LIBOSMIUM_VERSION_PATCH 1)
set(LIBOSMIUM_VERSION set(LIBOSMIUM_VERSION
"${LIBOSMIUM_VERSION_MAJOR}.${LIBOSMIUM_VERSION_MINOR}.${LIBOSMIUM_VERSION_PATCH}") "${LIBOSMIUM_VERSION_MAJOR}.${LIBOSMIUM_VERSION_MINOR}.${LIBOSMIUM_VERSION_PATCH}")
@ -43,8 +43,14 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
if(CMAKE_BUILD_TYPE STREQUAL "Dev") if(CMAKE_BUILD_TYPE STREQUAL "Dev")
set(dev_build ON) set(dev_build ON)
set(data_test_build ON)
else() else()
set(dev_build OFF) set(dev_build OFF)
set(data_test_build OFF)
endif()
if(CMAKE_BUILD_TYPE STREQUAL "Coverage")
set(data_test_build ON)
endif() endif()
option(BUILD_EXAMPLES "compile example programs" ON) option(BUILD_EXAMPLES "compile example programs" ON)
@ -52,7 +58,8 @@ option(BUILD_TESTING "compile unit tests, please run them with ctest" ON)
option(BUILD_HEADERS "compile every header file on its own" ${dev_build}) option(BUILD_HEADERS "compile every header file on its own" ${dev_build})
option(BUILD_BENCHMARKS "compile benchmark programs" ${dev_build}) option(BUILD_BENCHMARKS "compile benchmark programs" ${dev_build})
option(BUILD_DATA_TESTS "compile data tests, please run them with ctest" ${dev_build})
option(BUILD_DATA_TESTS "compile data tests, please run them with ctest" ${data_test_build})
option(INSTALL_GDALCPP "also install gdalcpp headers" OFF) option(INSTALL_GDALCPP "also install gdalcpp headers" OFF)
option(INSTALL_PROTOZERO "also install protozero headers" OFF) option(INSTALL_PROTOZERO "also install protozero headers" OFF)
@ -88,11 +95,12 @@ endif()
# #
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
include(CheckCXXCompilerFlag) ## This leads to all sorts of compile problems, so disable for now
check_cxx_compiler_flag("-fkeep-inline-functions" HAS_KEEP_INLINE_FUNCTIONS) #include(CheckCXXCompilerFlag)
if(HAS_KEEP_INLINE_FUNCTIONS) #check_cxx_compiler_flag("-fkeep-inline-functions" HAS_KEEP_INLINE_FUNCTIONS)
set(extra_coverage_flags_ "-fkeep-inline-functions") #if(HAS_KEEP_INLINE_FUNCTIONS)
endif() # set(extra_coverage_flags_ "-fkeep-inline-functions")
#endif()
set(CMAKE_CXX_FLAGS_COVERAGE set(CMAKE_CXX_FLAGS_COVERAGE
"-g -O0 -fno-inline-functions -fno-inline --coverage ${extra_coverage_flags_}" "-g -O0 -fno-inline-functions -fno-inline --coverage ${extra_coverage_flags_}"
@ -103,8 +111,8 @@ set(CMAKE_EXE_LINKER_FLAGS_COVERAGE
CACHE STRING "Flags used by the linker during coverage builds.") CACHE STRING "Flags used by the linker during coverage builds.")
if(CMAKE_BUILD_TYPE STREQUAL "Coverage") if(CMAKE_BUILD_TYPE STREQUAL "Coverage")
if(BUILD_EXAMPLES OR BUILD_HEADERS OR BUILD_BENCHMARKS OR BUILD_DATA_TESTS) if(BUILD_EXAMPLES OR BUILD_HEADERS OR BUILD_BENCHMARKS)
message(WARNING "Coverage builds don't work for anything but the unit tests") message(WARNING "Coverage builds don't work for anything but the tests")
endif() endif()
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
@ -184,8 +192,12 @@ endif()
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
if(NOT MSVC) if(NOT MSVC)
if(NOT USE_CPP_VERSION) if(NOT USE_CPP_VERSION)
if(CYGWIN)
set(USE_CPP_VERSION gnu++11)
else()
set(USE_CPP_VERSION c++11) set(USE_CPP_VERSION c++11)
endif() endif()
endif()
message(STATUS "Use C++ version: ${USE_CPP_VERSION}") message(STATUS "Use C++ version: ${USE_CPP_VERSION}")
# following only available from cmake 2.8.12: # following only available from cmake 2.8.12:
# add_compile_options(-std=${USE_CPP_VERSION}) # add_compile_options(-std=${USE_CPP_VERSION})
@ -201,15 +213,15 @@ endif()
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
if(MSVC) if(MSVC)
set(USUAL_COMPILE_OPTIONS "/Ox") set(USUAL_COMPILE_OPTIONS "/Ox")
set(USUAL_LINK_OPTIONS "/debug") # do not show warnings caused by missing .pdb files for libraries
set(USUAL_LINK_OPTIONS "/debug /ignore:4099")
else() else()
set(USUAL_COMPILE_OPTIONS "-O3 -g") set(USUAL_COMPILE_OPTIONS "-O3 -g")
set(USUAL_LINK_OPTIONS "") set(USUAL_LINK_OPTIONS "")
endif() endif()
if(WIN32) if(WIN32)
add_definitions(-DWIN32 -D_WIN32 -DMSWIN32 -DBGDWIN32 add_definitions(-DWIN32 -D_WIN32 -DMSWIN32 -DBGDWIN32)
-DWINVER=0x0500 -D_WIN32_WINNT=0x0500 -D_WIN32_IE=0x0600)
endif() endif()
set(CMAKE_CXX_FLAGS_DEV "${USUAL_COMPILE_OPTIONS}" set(CMAKE_CXX_FLAGS_DEV "${USUAL_COMPILE_OPTIONS}"
@ -228,6 +240,15 @@ set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${USUAL_COMPILE_OPTIONS}"
CACHE STRING "Flags used by the compiler during RELWITHDEBINFO builds." CACHE STRING "Flags used by the compiler during RELWITHDEBINFO builds."
FORCE) FORCE)
set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${USUAL_LINK_OPTIONS}"
CACHE STRING "Flags used by the linker during RELWITHDEBINFO builds."
FORCE)
mark_as_advanced(
CMAKE_CXX_FLAGS_RELWITHDEBINFO
CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO
)
if(WITH_PROFILING) if(WITH_PROFILING)
add_definitions(-fno-omit-frame-pointer) add_definitions(-fno-omit-frame-pointer)
endif() endif()
@ -301,7 +322,13 @@ find_program(CPPCHECK cppcheck)
if(CPPCHECK) if(CPPCHECK)
message(STATUS "Looking for cppcheck - found") message(STATUS "Looking for cppcheck - found")
set(CPPCHECK_OPTIONS set(CPPCHECK_OPTIONS
--enable=warning,style,performance,portability,information,missingInclude --force -Uassert) --language=c++
--quiet
-j4
--inline-suppr
--enable=warning,style,performance,portability,information,missingInclude
--force
-Uassert -DPROTOZERO_STRICT_API -DPROTOZERO_USE_BUILTIN_BSWAP -UPROTOZERO_USE_VIEW)
# cpp doesn't find system includes for some reason, suppress that report # cpp doesn't find system includes for some reason, suppress that report
set(CPPCHECK_OPTIONS ${CPPCHECK_OPTIONS} --suppress=missingIncludeSystem) set(CPPCHECK_OPTIONS ${CPPCHECK_OPTIONS} --suppress=missingIncludeSystem)
@ -460,10 +487,12 @@ if(CLANG_TIDY)
list(APPEND CT_CHECKS "misc-*" list(APPEND CT_CHECKS "misc-*"
"-misc-argument-comment") "-misc-argument-comment")
list(APPEND CT_CHECKS "modernize-*") list(APPEND CT_CHECKS "modernize-*"
"-modernize-make-unique") # not available in C++11
list(APPEND CT_CHECKS "readability-*" list(APPEND CT_CHECKS "readability-*"
"-readability-identifier-naming" "-readability-identifier-naming"
"-readability-implicit-bool-cast"
"-readability-named-parameter") "-readability-named-parameter")
string(REPLACE ";" "," ALL_CHECKS "${CT_CHECKS}") string(REPLACE ";" "," ALL_CHECKS "${CT_CHECKS}")

View File

@ -12,7 +12,7 @@ All Osmium code MUST be in the `osmium` namespace or one of its sub-namespaces.
## Include-Only ## Include-Only
Osmium is a include-only library. You can't compile the library itself. There Osmium is a include-only library. You can't compile the library itself. There
is no libosmium.so. is no `libosmium.so` or `libosmium.dll`.
One drawback ist that you can't have static data in classes, because there One drawback ist that you can't have static data in classes, because there
is no place to put this data. is no place to put this data.
@ -69,7 +69,7 @@ different.
* Template parameters are single uppercase letters or start with uppercase `T` * Template parameters are single uppercase letters or start with uppercase `T`
and use CamelCase. and use CamelCase.
* Always use `typename` in templates, not `class`: `template <typename T>`. * Always use `typename` in templates, not `class`: `template <typename T>`.
* The ellipsis in variadic template never has a space to the left of it and * The ellipsis in a variadic template never has a space to the left of it and
always has a space to the right: `template <typename... TArgs>` etc. always has a space to the right: `template <typename... TArgs>` etc.
Keep to the indentation and other styles used in the code. Keep to the indentation and other styles used in the code.
@ -92,6 +92,19 @@ between compilers due to different C++11 support.
Usually all code must work on Linux, OSX, and Windows. Execptions are allowed Usually all code must work on Linux, OSX, and Windows. Execptions are allowed
for some minor functionality, but please discuss this first. for some minor functionality, but please discuss this first.
When writing code and tests, care must be taken that everything works with the
CR line ending convention used on Linux and OSX and the CRLF line ending used
on Windows. Note that `git` can be run with different settings regarding line
ending rewritings on different machines making things more difficult. Some
files have been "forced" to LF line endings using `.gitattributes` files.
## 32bit systems
Libosmium tries to work on 32bit systems whereever possible. But there are
some parts which will not work on 32bit systems, mainly because the amount
of main memory available is not enough for it to work anyway.
## Checking your code ## Checking your code
@ -118,9 +131,20 @@ used to define mappings for iwyu. See the IWYU tool at
## Testing ## Testing
There are a unit tests using the Catch Unit Test Framework in the `test` There are unit tests using the Catch Unit Test Framework in the `test`
directory and some data tests in `test/osm-testdata`. They are built by the directory, some data tests in `test/osm-testdata` and tests of the examples in
default cmake config. Run `ctest` to run them. Many more tests are needed. `test/examples`. They are built by the default cmake config. Run `ctest` to
run them. We can always use more tests.
Tests are run automatically using the Travis (Linux/Mac) and Appveyor (Windows)
services. We automatically create coverage reports on Codevoc.io. Note that
the coverage percentages reported are not always accurate, because code that
is not used in tests at all will not necessarily end up in the binary and
the code coverage tool will not know it is there.
[![Travis Build Status](https://secure.travis-ci.org/osmcode/libosmium.svg)](https://travis-ci.org/osmcode/libosmium)
[![Appveyor Build Status](https://ci.appveyor.com/api/projects/status/github/osmcode/libosmium?svg=true)](https://ci.appveyor.com/project/Mapbox/libosmium)
[![Coverage Status](https://codecov.io/gh/osmcode/libosmium/branch/master/graph/badge.svg)](https://codecov.io/gh/osmcode/libosmium)
## Documenting the code ## Documenting the code

View File

@ -6,8 +6,9 @@ A fast and flexible C++ library for working with OpenStreetMap data.
Libosmium works on Linux, Mac OSX and Windows. Libosmium works on Linux, Mac OSX and Windows.
[![Build Status](https://secure.travis-ci.org/osmcode/libosmium.svg)](https://travis-ci.org/osmcode/libosmium) [![Travis Build Status](https://secure.travis-ci.org/osmcode/libosmium.svg)](https://travis-ci.org/osmcode/libosmium)
[![Build status](https://ci.appveyor.com/api/projects/status/github/osmcode/libosmium?svg=true)](https://ci.appveyor.com/project/Mapbox/libosmium) [![Appveyor Build Status](https://ci.appveyor.com/api/projects/status/github/osmcode/libosmium?svg=true)](https://ci.appveyor.com/project/Mapbox/libosmium)
[![Coverage Status](https://codecov.io/gh/osmcode/libosmium/branch/master/graph/badge.svg)](https://codecov.io/gh/osmcode/libosmium)
Please see the [Libosmium manual](http://osmcode.org/libosmium/manual.html) Please see the [Libosmium manual](http://osmcode.org/libosmium/manual.html)
for more details than this README can provide. for more details than this README can provide.

View File

@ -7,7 +7,13 @@
environment: environment:
matrix: matrix:
- config: Dev - config: Dev
autocrlf: true
- config: Dev
autocrlf: false
- config: RelWithDebInfo - config: RelWithDebInfo
autocrlf: true
- config: RelWithDebInfo
autocrlf: false
shallow_clone: true shallow_clone: true
@ -16,6 +22,8 @@ os: Visual Studio 2015
# scripts that are called at very beginning, before repo cloning # scripts that are called at very beginning, before repo cloning
init: init:
- git config --global core.autocrlf %autocrlf%
- git config --get core.autocrlf
# clone directory # clone directory
clone_folder: c:\projects\libosmium clone_folder: c:\projects\libosmium
@ -24,3 +32,8 @@ platform: x64
build_script: build_script:
- build-appveyor.bat - build-appveyor.bat
# remove garbage VS messages
# http://help.appveyor.com/discussions/problems/4569-the-target-_convertpdbfiles-listed-in-a-beforetargets-attribute-at-c-does-not-exist-in-the-project-and-will-be-ignored
before_build:
- del "C:\Program Files (x86)\MSBuild\14.0\Microsoft.Common.targets\ImportAfter\Xamarin.Common.targets"

View File

@ -33,6 +33,7 @@ foreach(benchmark ${BENCHMARKS})
target_link_libraries(osmium_benchmark_${benchmark} target_link_libraries(osmium_benchmark_${benchmark}
${OSMIUM_IO_LIBRARIES} ${OSMIUM_IO_LIBRARIES}
${BENCHMARK_LIBS_${benchmark}}) ${BENCHMARK_LIBS_${benchmark}})
set_pthread_on_target(osmium_benchmark_${benchmark})
configure_file(run_benchmark_${benchmark}.sh configure_file(run_benchmark_${benchmark}.sh
${CMAKE_CURRENT_BINARY_DIR}/run_benchmark_${benchmark}.sh ${CMAKE_CURRENT_BINARY_DIR}/run_benchmark_${benchmark}.sh
@ONLY) @ONLY)

View File

@ -97,11 +97,14 @@ ECHO calling^: %CMAKE_CMD%
%CMAKE_CMD% %CMAKE_CMD%
IF %ERRORLEVEL% NEQ 0 GOTO ERROR IF %ERRORLEVEL% NEQ 0 GOTO ERROR
SET avlogger=
IF /I "%APPVEYOR%"=="True" SET avlogger=/logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"
msbuild libosmium.sln ^ msbuild libosmium.sln ^
/p:Configuration=%config% ^ /p:Configuration=%config% ^
/toolsversion:14.0 ^ /toolsversion:14.0 ^
/p:Platform=x64 ^ /p:Platform=x64 ^
/p:PlatformToolset=v140 /p:PlatformToolset=v140 %avlogger%
IF %ERRORLEVEL% NEQ 0 GOTO ERROR IF %ERRORLEVEL% NEQ 0 GOTO ERROR
ctest --output-on-failure ^ ctest --output-on-failure ^

View File

@ -296,6 +296,20 @@ find_package_handle_standard_args(Osmium
VERSION_VAR _libosmium_version) VERSION_VAR _libosmium_version)
unset(OSMIUM_EXTRA_FIND_VARS) unset(OSMIUM_EXTRA_FIND_VARS)
#----------------------------------------------------------------------
#
# A function for setting the -pthread option in compilers/linkers
#
#----------------------------------------------------------------------
function(set_pthread_on_target _target)
if(NOT MSVC)
set_target_properties(${_target} PROPERTIES COMPILE_FLAGS "-pthread")
if(NOT APPLE)
set_target_properties(${_target} PROPERTIES LINK_FLAGS "-pthread")
endif()
endif()
endfunction()
#---------------------------------------------------------------------- #----------------------------------------------------------------------
# #
# Add compiler flags # Add compiler flags
@ -319,6 +333,10 @@ if(MSVC)
# old compilers anyway. # old compilers anyway.
add_definitions(-wd4351) add_definitions(-wd4351)
# Disable warning C4503: "decorated name length exceeded, name was truncated"
# there are more than 150 of generated names in libosmium longer than 4096 symbols supported in MSVC
add_definitions(-wd4503)
add_definitions(-DNOMINMAX -DWIN32_LEAN_AND_MEAN -D_CRT_SECURE_NO_WARNINGS) add_definitions(-DNOMINMAX -DWIN32_LEAN_AND_MEAN -D_CRT_SECURE_NO_WARNINGS)
endif() endif()

View File

@ -58,7 +58,12 @@ message(STATUS "Configuring examples - Building these examples:")
foreach(example ${EXAMPLES}) foreach(example ${EXAMPLES})
message(STATUS " - osmium_${example}") message(STATUS " - osmium_${example}")
add_executable(osmium_${example} "osmium_${example}.cpp") add_executable(osmium_${example} "osmium_${example}.cpp")
set_pthread_on_target(osmium_${example})
target_link_libraries(osmium_${example} ${OSMIUM_IO_LIBRARIES} ${EXAMPLE_LIBS_${example}}) target_link_libraries(osmium_${example} ${OSMIUM_IO_LIBRARIES} ${EXAMPLE_LIBS_${example}})
add_test(NAME examples_usage_${example} COMMAND osmium_${example})
set_tests_properties(examples_usage_${example} PROPERTIES
PASS_REGULAR_EXPRESSION "^Usage: "
)
endforeach() endforeach()

View File

@ -9,7 +9,7 @@
DEMONSTRATES USE OF: DEMONSTRATES USE OF:
* file input * file input
* location indexes and the NodeLocationsForWays handler * location indexes and the NodeLocationsForWays handler
* the MultipolygonCollector and Assembler to assemble areas (multipolygons) * the MultipolygonManager and Assembler to assemble areas (multipolygons)
* your own handler that works with areas (multipolygons) * your own handler that works with areas (multipolygons)
* accessing tags * accessing tags
* osmium::geom::Coordinates * osmium::geom::Coordinates
@ -29,17 +29,22 @@
#include <iostream> // for std::cerr #include <iostream> // for std::cerr
#include <string> // for std::string #include <string> // for std::string
// For memory based sparse index // For the location index. There are different types of indexes available.
#include <osmium/index/map/sparse_mem_array.hpp> // This will work for all input files keeping the index in memory.
#include <osmium/index/map/flex_mem.hpp>
// For the NodeLocationForWays handler // For the NodeLocationForWays handler
#include <osmium/handler/node_locations_for_ways.hpp> #include <osmium/handler/node_locations_for_ways.hpp>
using index_type = osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, osmium::Location>;
// The type of index used. This must match the include file above
using index_type = osmium::index::map::FlexMem<osmium::unsigned_object_id_type, osmium::Location>;
// The location handler always depends on the index type
using location_handler_type = osmium::handler::NodeLocationsForWays<index_type>; using location_handler_type = osmium::handler::NodeLocationsForWays<index_type>;
// For assembling multipolygons // For assembling multipolygons
#include <osmium/area/assembler.hpp> #include <osmium/area/assembler.hpp>
#include <osmium/area/multipolygon_collector.hpp> #include <osmium/area/multipolygon_manager.hpp>
// Allow any format of input files (XML, PBF, ...) // Allow any format of input files (XML, PBF, ...)
#include <osmium/io/any_input.hpp> #include <osmium/io/any_input.hpp>
@ -108,8 +113,8 @@ int main(int argc, char* argv[]) {
std::exit(1); std::exit(1);
} }
// The input file name // The input file
const std::string input_file_name{argv[1]}; const osmium::io::File input_file{argv[1]};
// Configuration for the multipolygon assembler. We disable the option to // Configuration for the multipolygon assembler. We disable the option to
// create empty areas when invalid multipolygons are encountered. This // create empty areas when invalid multipolygons are encountered. This
@ -118,21 +123,16 @@ int main(int argc, char* argv[]) {
osmium::area::Assembler::config_type assembler_config; osmium::area::Assembler::config_type assembler_config;
assembler_config.create_empty_areas = false; assembler_config.create_empty_areas = false;
// Initialize the MultipolygonCollector. Its job is to collect all // Initialize the MultipolygonManager. Its job is to collect all
// relations and member ways needed for each area. It then calls an // relations and member ways needed for each area. It then calls an
// instance of the osmium::area::Assembler class (with the given config) // instance of the osmium::area::Assembler class (with the given config)
// to actually assemble one area. // to actually assemble one area.
osmium::area::MultipolygonCollector<osmium::area::Assembler> collector{assembler_config}; osmium::area::MultipolygonManager<osmium::area::Assembler> mp_manager{assembler_config};
// We read the input file twice. In the first pass, only relations are // We read the input file twice. In the first pass, only relations are
// read and fed into the multipolygon collector. The read_meta::no option // read and fed into the multipolygon manager.
// disables reading of meta data (such as version numbers, timestamps, etc.)
// which are not needed in this case. Disabling this can speed up your
// program.
std::cerr << "Pass 1...\n"; std::cerr << "Pass 1...\n";
osmium::io::Reader reader1{input_file_name, osmium::osm_entity_bits::relation, osmium::io::read_meta::no}; osmium::relations::read_relations(input_file, mp_manager);
collector.read_relations(reader1);
reader1.close();
std::cerr << "Pass 1 done\n"; std::cerr << "Pass 1 done\n";
// The index storing all node locations. // The index storing all node locations.
@ -151,17 +151,21 @@ int main(int argc, char* argv[]) {
AmenityHandler data_handler; AmenityHandler data_handler;
// On the second pass we read all objects and run them first through the // On the second pass we read all objects and run them first through the
// node location handler and then the multipolygon collector. The collector // node location handler and then the multipolygon manager. The manager
// will put the areas it has created into the "buffer" which are then // will put the areas it has created into the "buffer" which are then
// fed through our handler. // fed through our handler.
//
// The read_meta::no option disables reading of meta data (such as version
// numbers, timestamps, etc.) which are not needed in this case. Disabling
// this can speed up your program.
std::cerr << "Pass 2...\n"; std::cerr << "Pass 2...\n";
osmium::io::Reader reader2{input_file_name, osmium::io::read_meta::no}; osmium::io::Reader reader{input_file, osmium::io::read_meta::no};
osmium::apply(reader2, location_handler, data_handler, collector.handler([&data_handler](const osmium::memory::Buffer& area_buffer) { osmium::apply(reader, location_handler, data_handler, mp_manager.handler([&data_handler](const osmium::memory::Buffer& area_buffer) {
osmium::apply(area_buffer, data_handler); osmium::apply(area_buffer, data_handler);
})); }));
reader2.close(); reader.close();
std::cerr << "Pass 2 done\n"; std::cerr << "Pass 2 done\n";
} }

View File

@ -8,7 +8,7 @@
DEMONSTRATES USE OF: DEMONSTRATES USE OF:
* file input * file input
* location indexes and the NodeLocationsForWays handler * location indexes and the NodeLocationsForWays handler
* the MultipolygonCollector and Assembler to assemble areas (multipolygons) * the MultipolygonManager and Assembler to assemble areas (multipolygons)
* your own handler that works with areas (multipolygons) * your own handler that works with areas (multipolygons)
* the WKTFactory to write geometries in WKT format * the WKTFactory to write geometries in WKT format
* the Dump handler * the Dump handler
@ -31,7 +31,7 @@
// For assembling multipolygons // For assembling multipolygons
#include <osmium/area/assembler.hpp> #include <osmium/area/assembler.hpp>
#include <osmium/area/multipolygon_collector.hpp> #include <osmium/area/multipolygon_manager.hpp>
// For the DynamicHandler class // For the DynamicHandler class
#include <osmium/dynamic_handler.hpp> #include <osmium/dynamic_handler.hpp>
@ -52,11 +52,11 @@
#include <osmium/visitor.hpp> #include <osmium/visitor.hpp>
// For the location index. There are different types of indexes available. // For the location index. There are different types of indexes available.
// This will work for small and medium sized input files. // This will work for all input files keeping the index in memory.
#include <osmium/index/map/sparse_mem_array.hpp> #include <osmium/index/map/flex_mem.hpp>
// The type of index used. This must match the include file above // The type of index used. This must match the include file above
using index_type = osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, osmium::Location>; using index_type = osmium::index::map::FlexMem<osmium::unsigned_object_id_type, osmium::Location>;
// The location handler always depends on the index type // The location handler always depends on the index type
using location_handler_type = osmium::handler::NodeLocationsForWays<index_type>; using location_handler_type = osmium::handler::NodeLocationsForWays<index_type>;
@ -93,10 +93,10 @@ void print_help() {
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
static struct option long_options[] = { static struct option long_options[] = {
{"help", no_argument, 0, 'h'}, {"help", no_argument, nullptr, 'h'},
{"dump-wkt", no_argument, 0, 'w'}, {"dump-wkt", no_argument, nullptr, 'w'},
{"dump-objects", no_argument, 0, 'o'}, {"dump-objects", no_argument, nullptr, 'o'},
{0, 0, 0, 0} {nullptr, 0, nullptr, 0}
}; };
// Initialize an empty DynamicHandler. Later it will be associated // Initialize an empty DynamicHandler. Later it will be associated
@ -107,7 +107,7 @@ int main(int argc, char* argv[]) {
// Read options from command line. // Read options from command line.
while (true) { while (true) {
const int c = getopt_long(argc, argv, "hwo", long_options, 0); const int c = getopt_long(argc, argv, "hwo", long_options, nullptr);
if (c == -1) { if (c == -1) {
break; break;
} }
@ -139,24 +139,29 @@ int main(int argc, char* argv[]) {
// are used, but you could change multiple settings. // are used, but you could change multiple settings.
osmium::area::Assembler::config_type assembler_config; osmium::area::Assembler::config_type assembler_config;
// Initialize the MultipolygonCollector. Its job is to collect all // Set up a filter matching only forests. This will be used to only build
// areas with matching tags.
osmium::TagsFilter filter{false};
filter.add_rule(true, "landuse", "forest");
filter.add_rule(true, "natural", "wood");
// Initialize the MultipolygonManager. Its job is to collect all
// relations and member ways needed for each area. It then calls an // relations and member ways needed for each area. It then calls an
// instance of the osmium::area::Assembler class (with the given config) // instance of the osmium::area::Assembler class (with the given config)
// to actually assemble one area. // to actually assemble one area. The filter parameter is optional, if
osmium::area::MultipolygonCollector<osmium::area::Assembler> collector{assembler_config}; // it is not set, all areas will be built.
osmium::area::MultipolygonManager<osmium::area::Assembler> mp_manager{assembler_config, filter};
// We read the input file twice. In the first pass, only relations are // We read the input file twice. In the first pass, only relations are
// read and fed into the multipolygon collector. // read and fed into the multipolygon manager.
std::cerr << "Pass 1...\n"; std::cerr << "Pass 1...\n";
osmium::io::Reader reader1{input_file, osmium::osm_entity_bits::relation}; osmium::relations::read_relations(input_file, mp_manager);
collector.read_relations(reader1);
reader1.close();
std::cerr << "Pass 1 done\n"; std::cerr << "Pass 1 done\n";
// Output the amount of main memory used so far. All multipolygon relations // Output the amount of main memory used so far. All multipolygon relations
// are in memory now. // are in memory now.
std::cerr << "Memory:\n"; std::cerr << "Memory:\n";
collector.used_memory(); osmium::relations::print_used_memory(std::cerr, mp_manager.used_memory());
// The index storing all node locations. // The index storing all node locations.
index_type index; index_type index;
@ -175,26 +180,29 @@ int main(int argc, char* argv[]) {
// will put the areas it has created into the "buffer" which are then // will put the areas it has created into the "buffer" which are then
// fed through our "handler". // fed through our "handler".
std::cerr << "Pass 2...\n"; std::cerr << "Pass 2...\n";
osmium::io::Reader reader2{input_file}; osmium::io::Reader reader{input_file};
osmium::apply(reader2, location_handler, collector.handler([&handler](osmium::memory::Buffer&& buffer) { osmium::apply(reader, location_handler, mp_manager.handler([&handler](osmium::memory::Buffer&& buffer) {
osmium::apply(buffer, handler); osmium::apply(buffer, handler);
})); }));
reader2.close(); reader.close();
std::cerr << "Pass 2 done\n"; std::cerr << "Pass 2 done\n";
// Output the amount of main memory used so far. All complete multipolygon // Output the amount of main memory used so far. All complete multipolygon
// relations have been cleaned up. // relations have been cleaned up.
std::cerr << "Memory:\n"; std::cerr << "Memory:\n";
collector.used_memory(); osmium::relations::print_used_memory(std::cerr, mp_manager.used_memory());
// If there were multipolgyon relations in the input, but some of their // If there were multipolgyon relations in the input, but some of their
// members are not in the input file (which often happens for extracts) // members are not in the input file (which often happens for extracts)
// this will write the IDs of the incomplete relations to stderr. // this will write the IDs of the incomplete relations to stderr.
std::vector<const osmium::Relation*> incomplete_relations = collector.get_incomplete_relations(); std::vector<osmium::object_id_type> incomplete_relations_ids;
if (!incomplete_relations.empty()) { mp_manager.for_each_incomplete_relation([&](const osmium::relations::RelationHandle& handle){
incomplete_relations_ids.push_back(handle->id());
});
if (!incomplete_relations_ids.empty()) {
std::cerr << "Warning! Some member ways missing for these multipolygon relations:"; std::cerr << "Warning! Some member ways missing for these multipolygon relations:";
for (const auto* relation : incomplete_relations) { for (const auto id : incomplete_relations_ids) {
std::cerr << " " << relation->id(); std::cerr << " " << id;
} }
std::cerr << "\n"; std::cerr << "\n";
} }

View File

@ -91,7 +91,7 @@ class RewriteHandler : public osmium::handler::Handler {
public: public:
// Constructor. New data will be added to the given buffer. // Constructor. New data will be added to the given buffer.
RewriteHandler(osmium::memory::Buffer& buffer) : explicit RewriteHandler(osmium::memory::Buffer& buffer) :
m_buffer(buffer) { m_buffer(buffer) {
} }
@ -119,7 +119,7 @@ public:
m_buffer.commit(); m_buffer.commit();
} }
// The way handler is called for each node in the input data. // The way handler is called for each way in the input data.
void way(const osmium::Way& way) { void way(const osmium::Way& way) {
{ {
osmium::builder::WayBuilder builder{m_buffer}; osmium::builder::WayBuilder builder{m_buffer};
@ -132,7 +132,7 @@ public:
m_buffer.commit(); m_buffer.commit();
} }
// The relation handler is called for each node in the input data. // The relation handler is called for each relation in the input data.
void relation(const osmium::Relation& relation) { void relation(const osmium::Relation& relation) {
{ {
osmium::builder::RelationBuilder builder{m_buffer}; osmium::builder::RelationBuilder builder{m_buffer};

View File

@ -53,10 +53,10 @@ void print_help() {
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
static struct option long_options[] = { static struct option long_options[] = {
{"help", no_argument, 0, 'h'}, {"help", no_argument, nullptr, 'h'},
{"from-format", required_argument, 0, 'f'}, {"from-format", required_argument, nullptr, 'f'},
{"to-format", required_argument, 0, 't'}, {"to-format", required_argument, nullptr, 't'},
{0, 0, 0, 0} {nullptr, 0, nullptr, 0}
}; };
// Input and output format are empty by default. Later this will mean that // Input and output format are empty by default. Later this will mean that
@ -67,7 +67,7 @@ int main(int argc, char* argv[]) {
// Read options from command line. // Read options from command line.
while (true) { while (true) {
const int c = getopt_long(argc, argv, "dhf:t:", long_options, 0); const int c = getopt_long(argc, argv, "dhf:t:", long_options, nullptr);
if (c == -1) { if (c == -1) {
break; break;
} }
@ -88,7 +88,7 @@ int main(int argc, char* argv[]) {
} }
const int remaining_args = argc - optind; const int remaining_args = argc - optind;
if (remaining_args > 2) { if (remaining_args == 0 || remaining_args > 2) {
std::cerr << "Usage: " << argv[0] << " [OPTIONS] [INFILE [OUTFILE]]\n"; std::cerr << "Usage: " << argv[0] << " [OPTIONS] [INFILE [OUTFILE]]\n";
std::exit(1); std::exit(1);
} }
@ -108,8 +108,8 @@ int main(int argc, char* argv[]) {
// This declares the input and output files using either the suffix of // This declares the input and output files using either the suffix of
// the file names or the format in the 2nd argument. It does not yet open // the file names or the format in the 2nd argument. It does not yet open
// the files. // the files.
osmium::io::File input_file{input_file_name, input_format}; const osmium::io::File input_file{input_file_name, input_format};
osmium::io::File output_file{output_file_name, output_format}; const osmium::io::File output_file{output_file_name, output_format};
// Input and output files can be OSM data files (without history) or // Input and output files can be OSM data files (without history) or
// OSM history files. History files are detected if they use the '.osh' // OSM history files. History files are detected if they use the '.osh'

View File

@ -46,6 +46,10 @@ int main(int argc, char* argv[]) {
// Get output file name from command line. // Get output file name from command line.
std::string output_file_name{argv[1]}; std::string output_file_name{argv[1]};
// If output file name is "-", this means STDOUT. Set the OPL file type
// in this case. Otherwise take the file type from the file name suffix.
osmium::io::File output_file{output_file_name, output_file_name == "-" ? ".opl" : ""};
try { try {
// Create a buffer where all objects will live. Use a sensible initial // Create a buffer where all objects will live. Use a sensible initial
// buffer size and set the buffer to automatically grow if needed. // buffer size and set the buffer to automatically grow if needed.
@ -78,7 +82,7 @@ int main(int argc, char* argv[]) {
// Initialize Writer using the header from above and tell it that it // 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_name, header, osmium::io::overwrite::allow}; osmium::io::Writer writer{output_file, header, osmium::io::overwrite::allow};
// Write out the contents of the output buffer. // Write out the contents of the output buffer.
writer(std::move(buffer)); writer(std::move(buffer));

View File

@ -44,10 +44,18 @@ int main(int argc, char* argv[]) {
if (argc == 3) { if (argc == 3) {
read_types = osmium::osm_entity_bits::nothing; read_types = osmium::osm_entity_bits::nothing;
std::string types = argv[2]; std::string types = argv[2];
if (types.find('n') != std::string::npos) read_types |= osmium::osm_entity_bits::node; if (types.find('n') != std::string::npos) {
if (types.find('w') != std::string::npos) read_types |= osmium::osm_entity_bits::way; read_types |= osmium::osm_entity_bits::node;
if (types.find('r') != std::string::npos) read_types |= osmium::osm_entity_bits::relation; }
if (types.find('c') != std::string::npos) read_types |= osmium::osm_entity_bits::changeset; if (types.find('w') != std::string::npos) {
read_types |= osmium::osm_entity_bits::way;
}
if (types.find('r') != std::string::npos) {
read_types |= osmium::osm_entity_bits::relation;
}
if (types.find('c') != std::string::npos) {
read_types |= osmium::osm_entity_bits::changeset;
}
} }
// Initialize Reader with file name and the types of entities we want to // Initialize Reader with file name and the types of entities we want to

View File

@ -6,7 +6,7 @@
indexes to find objects and object relations. indexes to find objects and object relations.
Note that this example programm will only work with small and medium sized Note that this example programm will only work with small and medium sized
OSM file, not with the planet. OSM files, not with the planet.
You can use the osmium_index example program to inspect the indexes. You can use the osmium_index example program to inspect the indexes.
@ -36,6 +36,10 @@
#include <sys/stat.h> // for open #include <sys/stat.h> // for open
#include <sys/types.h> // for open #include <sys/types.h> // for open
#ifdef _WIN32
# include <io.h> // for _setmode
#endif
#ifdef _MSC_VER #ifdef _MSC_VER
# include <direct.h> # include <direct.h>
#endif #endif
@ -66,12 +70,15 @@ class IndexFile {
public: public:
IndexFile(const std::string& filename) : explicit IndexFile(const std::string& filename) :
m_fd(::open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666)) { m_fd(::open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666)) {
if (m_fd < 0) { if (m_fd < 0) {
std::cerr << "Can't open index file '" << filename << "': " << std::strerror(errno) << "\n"; std::cerr << "Can't open index file '" << filename << "': " << std::strerror(errno) << "\n";
std::exit(2); std::exit(2);
} }
#ifdef _WIN32
_setmode(m_fd, _O_BINARY);
#endif
} }
~IndexFile() { ~IndexFile() {
@ -114,6 +121,10 @@ int main(int argc, char* argv[]) {
std::exit(2); std::exit(2);
} }
#ifdef _WIN32
_setmode(data_fd, _O_BINARY);
#endif
// These indexes store the offset in the data file where each node, way, // These indexes store the offset in the data file where each node, way,
// or relation is stored. // or relation is stored.
offset_index_type node_index; offset_index_type node_index;

View File

@ -33,6 +33,10 @@
#include <sys/types.h> // for open #include <sys/types.h> // for open
#include <vector> // for std::vector #include <vector> // for std::vector
#ifdef _WIN32
# include <io.h> // for _setmode
#endif
// Disk-based indexes // Disk-based indexes
#include <osmium/index/map/dense_file_array.hpp> #include <osmium/index/map/dense_file_array.hpp>
#include <osmium/index/map/sparse_file_array.hpp> #include <osmium/index/map/sparse_file_array.hpp>
@ -52,7 +56,7 @@ class IndexAccess {
public: public:
IndexAccess(int fd) : explicit IndexAccess(int fd) :
m_fd(fd) { m_fd(fd) {
} }
@ -83,7 +87,7 @@ class IndexAccessDense : public IndexAccess<TValue> {
public: public:
IndexAccessDense(int fd) : explicit IndexAccessDense(int fd) :
IndexAccess<TValue>(fd) { IndexAccess<TValue>(fd) {
} }
@ -122,7 +126,7 @@ class IndexAccessSparse : public IndexAccess<TValue> {
public: public:
IndexAccessSparse(int fd) : explicit IndexAccessSparse(int fd) :
IndexAccess<TValue>(fd) { IndexAccess<TValue>(fd) {
} }
@ -192,17 +196,17 @@ public:
} }
static struct option long_options[] = { static struct option long_options[] = {
{"array", required_argument, 0, 'a'}, {"array", required_argument, nullptr, 'a'},
{"dump", no_argument, 0, 'd'}, {"dump", no_argument, nullptr, 'd'},
{"help", no_argument, 0, 'h'}, {"help", no_argument, nullptr, 'h'},
{"list", required_argument, 0, 'l'}, {"list", required_argument, nullptr, 'l'},
{"search", required_argument, 0, 's'}, {"search", required_argument, nullptr, 's'},
{"type", required_argument, 0, 't'}, {"type", required_argument, nullptr, 't'},
{0, 0, 0, 0} {nullptr, 0, nullptr, 0}
}; };
while (true) { while (true) {
const int c = getopt_long(argc, argv, "a:dhl:s:t:", long_options, 0); const int c = getopt_long(argc, argv, "a:dhl:s:t:", long_options, nullptr);
if (c == -1) { if (c == -1) {
break; break;
} }
@ -243,7 +247,7 @@ public:
std::exit(2); std::exit(2);
} }
if (m_dump && !m_ids.empty()) { if (m_dump == !m_ids.empty()) {
std::cerr << "Need option --dump or --search, but not both\n"; std::cerr << "Need option --dump or --search, but not both\n";
std::exit(2); std::exit(2);
} }
@ -308,13 +312,18 @@ int main(int argc, char* argv[]) {
Options options{argc, argv}; Options options{argc, argv};
// Open the index file. // Open the index file.
const int fd = open(options.filename(), O_RDWR); const int fd = ::open(options.filename(), O_RDWR);
if (fd < 0) { if (fd < 0) {
std::cerr << "Can not open file '" << options.filename() std::cerr << "Can not open file '" << options.filename()
<< "': " << std::strerror(errno) << '\n'; << "': " << std::strerror(errno) << '\n';
std::exit(2); std::exit(2);
} }
#ifdef _WIN32
_setmode(fd, _O_BINARY);
#endif
try {
// Depending on the type of index, we have different implementations. // Depending on the type of index, we have different implementations.
if (options.type_is("location")) { if (options.type_is("location")) {
// index id -> location // index id -> location
@ -329,5 +338,9 @@ int main(int argc, char* argv[]) {
const auto index = create<std::size_t>(options.dense_format(), fd); const auto index = create<std::size_t>(options.dense_format(), fd);
return run(*index, options); return run(*index, options);
} }
} catch(const std::exception& e) {
std::cerr << "Error: " << e.what() << '\n';
std::exit(1);
}
} }

View File

@ -33,6 +33,10 @@
#include <sys/stat.h> // for open #include <sys/stat.h> // for open
#include <sys/types.h> // for open #include <sys/types.h> // for open
#ifdef _WIN32
# include <io.h> // for _setmode
#endif
// Allow any format of input files (XML, PBF, ...) // Allow any format of input files (XML, PBF, ...)
#include <osmium/io/any_input.hpp> #include <osmium/io/any_input.hpp>
@ -68,11 +72,14 @@ int main(int argc, char* argv[]) {
osmium::io::Reader reader{input_filename, osmium::osm_entity_bits::node}; osmium::io::Reader reader{input_filename, osmium::osm_entity_bits::node};
// Initialize location index on disk creating a new file. // Initialize location index on disk creating a new file.
const int fd = open(cache_filename.c_str(), O_RDWR | O_CREAT, 0666); const int fd = ::open(cache_filename.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0666);
if (fd == -1) { if (fd == -1) {
std::cerr << "Can not open location cache file '" << cache_filename << "': " << std::strerror(errno) << "\n"; std::cerr << "Can not open location cache file '" << cache_filename << "': " << std::strerror(errno) << "\n";
std::exit(1); std::exit(1);
} }
#ifdef _WIN32
_setmode(fd, _O_BINARY);
#endif
index_type index{fd}; index_type index{fd};
// The handler that stores all node locations in the index. // The handler that stores all node locations in the index.

View File

@ -33,6 +33,10 @@
#include <sys/stat.h> // for open #include <sys/stat.h> // for open
#include <sys/types.h> // for open #include <sys/types.h> // for open
#ifdef _WIN32
# include <io.h> // for _setmode
#endif
// Allow any format of input files (XML, PBF, ...) // Allow any format of input files (XML, PBF, ...)
#include <osmium/io/any_input.hpp> #include <osmium/io/any_input.hpp>
@ -81,11 +85,14 @@ int main(int argc, char* argv[]) {
osmium::io::Reader reader{input_filename, osmium::osm_entity_bits::way}; osmium::io::Reader reader{input_filename, osmium::osm_entity_bits::way};
// Initialize location index on disk using an existing file // Initialize location index on disk using an existing file
const int fd = open(cache_filename.c_str(), O_RDWR); const int fd = ::open(cache_filename.c_str(), O_RDWR);
if (fd == -1) { if (fd == -1) {
std::cerr << "Can not open location cache file '" << cache_filename << "': " << std::strerror(errno) << "\n"; std::cerr << "Can not open location cache file '" << cache_filename << "': " << std::strerror(errno) << "\n";
return 1; return 1;
} }
#ifdef _WIN32
_setmode(fd, _O_BINARY);
#endif
index_type index{fd}; index_type index{fd};
// The handler that adds node locations from the index to the ways. // The handler that adds node locations from the index to the ways.

View File

@ -33,14 +33,14 @@
#include <osmium/visitor.hpp> #include <osmium/visitor.hpp>
// For the location index. There are different types of indexes available. // For the location index. There are different types of indexes available.
// This will work for small and medium sized input files. // This will work for all input files keeping the index in memory.
#include <osmium/index/map/sparse_mem_array.hpp> #include <osmium/index/map/flex_mem.hpp>
// For the NodeLocationForWays handler // For the NodeLocationForWays handler
#include <osmium/handler/node_locations_for_ways.hpp> #include <osmium/handler/node_locations_for_ways.hpp>
// The type of index used. This must match the include file above // The type of index used. This must match the include file above
using index_type = osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, osmium::Location>; using index_type = osmium::index::map::FlexMem<osmium::unsigned_object_id_type, osmium::Location>;
// The location handler always depends on the index type // The location handler always depends on the index type
using location_handler_type = osmium::handler::NodeLocationsForWays<index_type>; using location_handler_type = osmium::handler::NodeLocationsForWays<index_type>;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,154 @@
#ifndef OSMIUM_AREA_ASSEMBLER_CONFIG_HPP
#define OSMIUM_AREA_ASSEMBLER_CONFIG_HPP
/*
This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2013-2017 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 <osmium/util/compatibility.hpp>
namespace osmium {
namespace area {
class ProblemReporter;
/**
* Configuration for osmium::area::Assembler objects. Create this
* once, set the options you want and then re-use it every time you
* create an Assembler object.
*/
struct AssemblerConfig {
/**
* Optional pointer to problem reporter.
*/
ProblemReporter* problem_reporter = nullptr;
/**
* Debug level. If this is greater than zero, debug messages will
* be printed to stderr. Available levels are 1 to 3. Note that
* level 2 and above will generate a lot of messages!
*/
int debug_level = 0;
/**
* The roles of multipolygon members are ignored when assembling
* multipolygons, because they are often missing or wrong. If this
* is set, the roles are checked after the multipolygons are built
* against what the assembly process decided where the inner and
* outer rings are. This slows down the processing, so it only
* makes sense if you want to get the problem reports.
*/
bool check_roles = false;
/**
* When the assembler can't create an area, usually because its
* geometry would be invalid, it will create an "empty" area object
* without rings. This allows you to detect where an area was
* invalid.
*
* If this is set to false, invalid areas will simply be discarded.
*/
bool create_empty_areas = true;
/**
* Create areas for (multi)polygons where the tags are on the
* relation.
*
* If this is set to false, those areas will simply be discarded.
*/
bool create_new_style_polygons = true;
/**
* Create areas for (multi)polygons where the tags are on the
* outer way(s). This is ignored by the area::Assembler which
* doesn't support old-style multipolygons any more. Use the
* area::AssemblerLegacy if you need this.
*
* If this is set to false, those areas will simply be discarded.
*/
bool create_old_style_polygons = true;
/**
* Create areas for polygons created from ways.
*
* If this is set to false, those areas will simply be discarded.
*/
bool create_way_polygons = true;
/**
* Keep the type tag from multipolygon relations on the area
* object. By default this is false, and the type tag will be
* removed.
*/
bool keep_type_tag = false;
/**
* If there is an invalid location in any of the ways needed for
* assembling the multipolygon, the assembler will normally fail.
* If this is set, the assembler will silently ignore the invalid
* locations pretending them to be not referenced from the ways.
* This will allow some areas to be built, others will now be
* incorrect. This can sometimes be useful to assemble areas
* crossing the boundary of an extract, but you will also get
* geometrically valid but wrong (multi)polygons.
*/
bool ignore_invalid_locations = false;
AssemblerConfig() noexcept = default;
/**
* Constructor
* @deprecated Use default constructor and set values afterwards.
*/
explicit AssemblerConfig(ProblemReporter* pr, bool d = false) :
problem_reporter(pr),
debug_level(d) {
}
/**
* Enable or disable debug output to stderr. This is for Osmium
* developers only.
*
* @deprecated Set debug_level directly.
*/
OSMIUM_DEPRECATED void enable_debug_output(bool d = true) {
debug_level = d;
}
}; // struct AssemblerConfig
} // namespace area
} // namespace osmium
#endif // OSMIUM_AREA_ASSEMBLER_CONFIG_HPP

View File

@ -0,0 +1,382 @@
#ifndef OSMIUM_AREA_ASSEMBLER_LEGACY_HPP
#define OSMIUM_AREA_ASSEMBLER_LEGACY_HPP
/*
This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2013-2017 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 <functional>
#include <iostream>
#include <iterator>
#include <set>
#include <string>
#include <map>
#include <utility>
#include <vector>
#include <osmium/area/assembler_config.hpp>
#include <osmium/area/detail/basic_assembler_with_tags.hpp>
#include <osmium/area/detail/proto_ring.hpp>
#include <osmium/area/detail/segment_list.hpp>
#include <osmium/area/problem_reporter.hpp>
#include <osmium/area/stats.hpp>
#include <osmium/builder/osm_object_builder.hpp>
#include <osmium/memory/buffer.hpp>
#include <osmium/memory/collection.hpp>
#include <osmium/osm/area.hpp>
#include <osmium/osm/item_type.hpp>
#include <osmium/osm/node_ref.hpp>
#include <osmium/osm/relation.hpp>
#include <osmium/osm/tag.hpp>
#include <osmium/osm/way.hpp>
#include <osmium/tags/filter.hpp>
namespace osmium {
namespace area {
/**
* Assembles area objects from closed ways or multipolygon relations
* and their members.
*/
class AssemblerLegacy : public detail::BasicAssemblerWithTags {
void add_tags_to_area(osmium::builder::AreaBuilder& builder, const osmium::Way& way) const {
builder.add_item(way.tags());
}
void add_common_tags(osmium::builder::TagListBuilder& tl_builder, std::set<const osmium::Way*>& ways) const {
std::map<std::string, std::size_t> counter;
for (const osmium::Way* way : ways) {
for (const auto& tag : way->tags()) {
std::string kv{tag.key()};
kv.append(1, '\0');
kv.append(tag.value());
++counter[kv];
}
}
const std::size_t num_ways = ways.size();
for (const auto& t_c : counter) {
if (debug()) {
std::cerr << " tag " << t_c.first << " is used " << t_c.second << " times in " << num_ways << " ways\n";
}
if (t_c.second == num_ways) {
const std::size_t len = std::strlen(t_c.first.c_str());
tl_builder.add_tag(t_c.first.c_str(), t_c.first.c_str() + len + 1);
}
}
}
struct MPFilter : public osmium::tags::KeyFilter {
MPFilter() : osmium::tags::KeyFilter(true) {
add(false, "type");
add(false, "created_by");
add(false, "source");
add(false, "note");
add(false, "test:id");
add(false, "test:section");
}
}; // struct MPFilter
static const MPFilter& filter() noexcept {
static const MPFilter filter;
return filter;
}
void add_tags_to_area(osmium::builder::AreaBuilder& builder, const osmium::Relation& relation) {
const auto count = std::count_if(relation.tags().cbegin(), relation.tags().cend(), std::cref(filter()));
if (debug()) {
std::cerr << " found " << count << " tags on relation (without ignored ones)\n";
}
if (count > 0) {
if (debug()) {
std::cerr << " use tags from relation\n";
}
if (config().keep_type_tag) {
builder.add_item(relation.tags());
} else {
copy_tags_without_type(builder, relation.tags());
}
} else {
++stats().no_tags_on_relation;
if (debug()) {
std::cerr << " use tags from outer ways\n";
}
std::set<const osmium::Way*> ways;
for (const auto& ring : rings()) {
if (ring.is_outer()) {
ring.get_ways(ways);
}
}
if (ways.size() == 1) {
if (debug()) {
std::cerr << " only one outer way\n";
}
builder.add_item((*ways.cbegin())->tags());
} else {
if (debug()) {
std::cerr << " multiple outer ways, get common tags\n";
}
osmium::builder::TagListBuilder tl_builder{builder};
add_common_tags(tl_builder, ways);
}
}
}
bool create_area(osmium::memory::Buffer& out_buffer, const osmium::Way& way) {
osmium::builder::AreaBuilder builder{out_buffer};
builder.initialize_from_object(way);
const bool area_okay = create_rings();
if (area_okay || config().create_empty_areas) {
add_tags_to_area(builder, way);
}
if (area_okay) {
add_rings_to_area(builder);
}
if (report_ways()) {
config().problem_reporter->report_way(way);
}
return area_okay || config().create_empty_areas;
}
bool create_area(osmium::memory::Buffer& out_buffer, const osmium::Relation& relation, const std::vector<const osmium::Way*>& members) {
set_num_members(members.size());
osmium::builder::AreaBuilder builder{out_buffer};
builder.initialize_from_object(relation);
const bool area_okay = create_rings();
if (area_okay || config().create_empty_areas) {
add_tags_to_area(builder, relation);
}
if (area_okay) {
add_rings_to_area(builder);
}
if (report_ways()) {
for (const osmium::Way* way : members) {
config().problem_reporter->report_way(*way);
}
}
return area_okay || config().create_empty_areas;
}
public:
explicit AssemblerLegacy(const config_type& config) :
detail::BasicAssemblerWithTags(config) {
}
~AssemblerLegacy() noexcept = default;
/**
* Assemble an area from the given way.
* The resulting area is put into the out_buffer.
*
* @returns false if there was some kind of error building the
* area, true otherwise.
*/
bool operator()(const osmium::Way& way, osmium::memory::Buffer& out_buffer) {
if (!config().create_way_polygons) {
return true;
}
if (way.tags().has_tag("area", "no")) {
return true;
}
if (config().problem_reporter) {
config().problem_reporter->set_object(osmium::item_type::way, way.id());
config().problem_reporter->set_nodes(way.nodes().size());
}
// Ignore (but count) ways without segments.
if (way.nodes().size() < 2) {
++stats().short_ways;
return false;
}
if (!way.ends_have_same_id()) {
++stats().duplicate_nodes;
if (config().problem_reporter) {
config().problem_reporter->report_duplicate_node(way.nodes().front().ref(), way.nodes().back().ref(), way.nodes().front().location());
}
}
++stats().from_ways;
stats().invalid_locations = segment_list().extract_segments_from_way(config().problem_reporter,
stats().duplicate_nodes,
way);
if (!config().ignore_invalid_locations && stats().invalid_locations > 0) {
return false;
}
if (config().debug_level > 0) {
std::cerr << "\nAssembling way " << way.id() << " containing " << segment_list().size() << " nodes\n";
}
// Now create the Area object and add the attributes and tags
// from the way.
const bool okay = create_area(out_buffer, way);
if (okay) {
out_buffer.commit();
} else {
out_buffer.rollback();
}
if (debug()) {
std::cerr << "Done: " << stats() << "\n";
}
return okay;
}
/**
* Assemble an area from the given relation and its members.
* The resulting area is put into the out_buffer.
*
* @returns false if there was some kind of error building the
* area(s), true otherwise.
*/
bool operator()(const osmium::Relation& relation, const std::vector<const osmium::Way*>& members, osmium::memory::Buffer& out_buffer) {
assert(relation.members().size() >= members.size());
if (config().problem_reporter) {
config().problem_reporter->set_object(osmium::item_type::relation, relation.id());
}
if (relation.members().empty()) {
++stats().no_way_in_mp_relation;
return false;
}
++stats().from_relations;
stats().invalid_locations = segment_list().extract_segments_from_ways(config().problem_reporter,
stats().duplicate_nodes,
stats().duplicate_ways,
relation,
members);
if (!config().ignore_invalid_locations && stats().invalid_locations > 0) {
return false;
}
stats().member_ways = members.size();
if (stats().member_ways == 1) {
++stats().single_way_in_mp_relation;
}
if (config().debug_level > 0) {
std::cerr << "\nAssembling relation " << relation.id() << " containing " << members.size() << " way members with " << segment_list().size() << " nodes\n";
}
const std::size_t area_offset = out_buffer.committed();
// Now create the Area object and add the attributes and tags
// from the relation.
bool okay = create_area(out_buffer, relation, members);
if (okay) {
if ((config().create_new_style_polygons && stats().no_tags_on_relation == 0) ||
(config().create_old_style_polygons && stats().no_tags_on_relation != 0)) {
out_buffer.commit();
} else {
out_buffer.rollback();
}
} else {
out_buffer.rollback();
}
const osmium::TagList& area_tags = out_buffer.get<osmium::Area>(area_offset).tags(); // tags of the area we just built
// Find all closed ways that are inner rings and check their
// tags. If they are not the same as the tags of the area we
// just built, add them to a list and later build areas for
// them, too.
std::vector<const osmium::Way*> ways_that_should_be_areas;
if (stats().wrong_role == 0) {
detail::for_each_member(relation, members, [this, &ways_that_should_be_areas, &area_tags](const osmium::RelationMember& member, const osmium::Way& way) {
if (!std::strcmp(member.role(), "inner")) {
if (!way.nodes().empty() && way.is_closed() && way.tags().size() > 0) {
const auto d = std::count_if(way.tags().cbegin(), way.tags().cend(), std::cref(filter()));
if (d > 0) {
osmium::tags::KeyFilter::iterator way_fi_begin(std::cref(filter()), way.tags().cbegin(), way.tags().cend());
osmium::tags::KeyFilter::iterator way_fi_end(std::cref(filter()), way.tags().cend(), way.tags().cend());
osmium::tags::KeyFilter::iterator area_fi_begin(std::cref(filter()), area_tags.cbegin(), area_tags.cend());
osmium::tags::KeyFilter::iterator area_fi_end(std::cref(filter()), area_tags.cend(), area_tags.cend());
if (!std::equal(way_fi_begin, way_fi_end, area_fi_begin) || d != std::distance(area_fi_begin, area_fi_end)) {
ways_that_should_be_areas.push_back(&way);
} else {
++stats().inner_with_same_tags;
if (config().problem_reporter) {
config().problem_reporter->report_inner_with_same_tags(way);
}
}
}
}
}
});
}
if (debug()) {
std::cerr << "Done: " << stats() << "\n";
}
// Now build areas for all ways found in the last step.
for (const osmium::Way* way : ways_that_should_be_areas) {
AssemblerLegacy assembler{config()};
if (!assembler(*way, out_buffer)) {
okay = false;
}
stats() += assembler.stats();
}
return okay;
}
}; // class AssemblerLegacy
} // namespace area
} // namespace osmium
#endif // OSMIUM_AREA_ASSEMBLER_LEGACY_HPP

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,93 @@
#ifndef OSMIUM_AREA_DETAIL_BASIC_ASSEMBLER_WITH_TAGS_HPP
#define OSMIUM_AREA_DETAIL_BASIC_ASSEMBLER_WITH_TAGS_HPP
/*
This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2013-2017 Jochen Topf <jochen@topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#include <cstring>
#include <osmium/area/assembler_config.hpp>
#include <osmium/area/detail/basic_assembler.hpp>
#include <osmium/area/stats.hpp>
#include <osmium/builder/osm_object_builder.hpp>
#include <osmium/osm/tag.hpp>
namespace osmium {
namespace area {
namespace detail {
class BasicAssemblerWithTags : public detail::BasicAssembler {
protected:
bool report_ways() const noexcept {
if (!config().problem_reporter) {
return false;
}
return stats().duplicate_nodes ||
stats().duplicate_segments ||
stats().intersections ||
stats().open_rings ||
stats().short_ways ||
stats().touching_rings ||
stats().ways_in_multiple_rings ||
stats().wrong_role;
}
static void copy_tags_without_type(osmium::builder::AreaBuilder& builder, const osmium::TagList& tags) {
osmium::builder::TagListBuilder tl_builder{builder};
for (const osmium::Tag& tag : tags) {
if (std::strcmp(tag.key(), "type")) {
tl_builder.add_tag(tag.key(), tag.value());
}
}
}
public:
using config_type = osmium::area::AssemblerConfig;
explicit BasicAssemblerWithTags(const config_type& config) :
BasicAssembler(config) {
}
}; // class BasicAssemblerWithTags
} // namespace detail
} // namespace area
} // namespace osmium
#endif // OSMIUM_AREA_DETAIL_BASIC_ASSEMBLER_WITH_TAGS_HPP

View File

@ -106,7 +106,7 @@ namespace osmium {
m_role(role_type::unknown) { m_role(role_type::unknown) {
} }
NodeRefSegment(const osmium::NodeRef& nr1, const osmium::NodeRef& nr2, role_type role = role_type::unknown, const osmium::Way* way = nullptr) noexcept : NodeRefSegment(const osmium::NodeRef& nr1, const osmium::NodeRef& nr2, role_type role, const osmium::Way* way) noexcept :
m_first(nr1), m_first(nr1),
m_second(nr2), m_second(nr2),
m_way(way), m_way(way),
@ -262,18 +262,6 @@ namespace osmium {
return lhs.first().location() < rhs.first().location(); return lhs.first().location() < rhs.first().location();
} }
inline bool operator>(const NodeRefSegment& lhs, const NodeRefSegment& rhs) noexcept {
return rhs < lhs;
}
inline bool operator<=(const NodeRefSegment& lhs, const NodeRefSegment& rhs) noexcept {
return ! (rhs < lhs);
}
inline bool operator>=(const NodeRefSegment& lhs, const NodeRefSegment& rhs) noexcept {
return ! (lhs < rhs);
}
template <typename TChar, typename TTraits> template <typename TChar, typename TTraits>
inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const NodeRefSegment& segment) { inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const NodeRefSegment& segment) {
return out << segment.start() << "--" << segment.stop() return out << segment.start() << "--" << segment.stop()
@ -283,19 +271,13 @@ namespace osmium {
} }
inline bool outside_x_range(const NodeRefSegment& s1, const NodeRefSegment& s2) noexcept { inline bool outside_x_range(const NodeRefSegment& s1, const NodeRefSegment& s2) noexcept {
if (s1.first().location().x() > s2.second().location().x()) { return s1.first().location().x() > s2.second().location().x();
return true;
}
return false;
} }
inline bool y_range_overlap(const NodeRefSegment& s1, const NodeRefSegment& s2) noexcept { inline bool y_range_overlap(const NodeRefSegment& s1, const NodeRefSegment& s2) noexcept {
const std::pair<int32_t, int32_t> m1 = std::minmax(s1.first().location().y(), s1.second().location().y()); const std::pair<int32_t, int32_t> m1 = std::minmax(s1.first().location().y(), s1.second().location().y());
const std::pair<int32_t, int32_t> m2 = std::minmax(s2.first().location().y(), s2.second().location().y()); const std::pair<int32_t, int32_t> m2 = std::minmax(s2.first().location().y(), s2.second().location().y());
if (m1.first > m2.second || m2.first > m1.second) { return !(m1.first > m2.second || m2.first > m1.second);
return false;
}
return true;
} }
/** /**
@ -331,7 +313,7 @@ namespace osmium {
if ((p0 == q0 && p1 == q1) || if ((p0 == q0 && p1 == q1) ||
(p0 == q1 && p1 == q0)) { (p0 == q1 && p1 == q0)) {
// segments are the same // segments are the same
return osmium::Location(); return osmium::Location{};
} }
const vec pd = p1 - p0; const vec pd = p1 - p0;
@ -342,7 +324,7 @@ namespace osmium {
if (p0 == q0 || p0 == q1 || p1 == q0 || p1 == q1) { if (p0 == q0 || p0 == q1 || p1 == q0 || p1 == q1) {
// touching at an end point // touching at an end point
return osmium::Location(); return osmium::Location{};
} }
// intersection in a point // intersection in a point
@ -357,10 +339,10 @@ namespace osmium {
(d < 0 && na <= 0 && na >= d && nb <= 0 && nb >= d)) { (d < 0 && na <= 0 && na >= d && nb <= 0 && nb >= d)) {
const double ua = double(na) / d; const double ua = double(na) / d;
const vec i = p0 + ua * (p1 - p0); const vec i = p0 + ua * (p1 - p0);
return osmium::Location(int32_t(i.x), int32_t(i.y)); return osmium::Location{int32_t(i.x), int32_t(i.y)};
} }
return osmium::Location(); return osmium::Location{};
} }
// segments are collinear // segments are collinear
@ -390,13 +372,12 @@ namespace osmium {
if (sl[0].segment != sl[1].segment) { if (sl[0].segment != sl[1].segment) {
if (sl[0].location == sl[1].location) { if (sl[0].location == sl[1].location) {
return sl[2].location; return sl[2].location;
} else { }
return sl[1].location; return sl[1].location;
} }
} }
}
return osmium::Location(); return osmium::Location{};
} }
} // namespace detail } // namespace detail

View File

@ -77,6 +77,15 @@ namespace osmium {
// If this is an inner ring, points to the outer ring. // If this is an inner ring, points to the outer ring.
ProtoRing* m_outer_ring; ProtoRing* m_outer_ring;
#ifdef OSMIUM_DEBUG_RING_NO
static int64_t next_num() noexcept {
static int64_t counter = 0;
return ++counter;
}
int64_t m_num;
#endif
int64_t m_sum; int64_t m_sum;
public: public:
@ -86,6 +95,9 @@ namespace osmium {
m_inner(), m_inner(),
m_min_segment(segment), m_min_segment(segment),
m_outer_ring(nullptr), m_outer_ring(nullptr),
#ifdef OSMIUM_DEBUG_RING_NO
m_num(next_num()),
#endif
m_sum(0) { m_sum(0) {
add_segment_back(segment); add_segment_back(segment);
} }
@ -200,7 +212,11 @@ namespace osmium {
} }
void print(std::ostream& out) const { void print(std::ostream& out) const {
out << "["; #ifdef OSMIUM_DEBUG_RING_NO
out << "Ring #" << m_num << " [";
#else
out << "Ring [";
#endif
if (!m_segments.empty()) { if (!m_segments.empty()) {
out << m_segments.front()->start().ref(); out << m_segments.front()->start().ref();
} }

View File

@ -40,6 +40,7 @@ DEALINGS IN THE SOFTWARE.
#include <iostream> #include <iostream>
#include <iterator> #include <iterator>
#include <numeric> #include <numeric>
#include <unordered_set>
#include <vector> #include <vector>
#include <osmium/area/detail/node_ref_segment.hpp> #include <osmium/area/detail/node_ref_segment.hpp>
@ -48,6 +49,7 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/osm/location.hpp> #include <osmium/osm/location.hpp>
#include <osmium/osm/node_ref.hpp> #include <osmium/osm/node_ref.hpp>
#include <osmium/osm/relation.hpp> #include <osmium/osm/relation.hpp>
#include <osmium/osm/types.hpp>
#include <osmium/osm/way.hpp> #include <osmium/osm/way.hpp>
namespace osmium { namespace osmium {
@ -89,9 +91,11 @@ namespace osmium {
static role_type parse_role(const char* role) noexcept { static role_type parse_role(const char* role) noexcept {
if (role[0] == '\0') { if (role[0] == '\0') {
return role_type::empty; return role_type::empty;
} else if (!std::strcmp(role, "outer")) { }
if (!std::strcmp(role, "outer")) {
return role_type::outer; return role_type::outer;
} else if (!std::strcmp(role, "inner")) { }
if (!std::strcmp(role, "inner")) {
return role_type::inner; return role_type::inner;
} }
return role_type::unknown; return role_type::unknown;
@ -100,21 +104,27 @@ 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 std::size_t get_num_segments(const std::vector<const osmium::Way*>& members) noexcept {
return std::accumulate(members.cbegin(), members.cend(), static_cast<size_t>(0), [](size_t sum, const osmium::Way* way) { return std::accumulate(members.cbegin(), members.cend(), static_cast<std::size_t>(0), [](std::size_t sum, const osmium::Way* way) {
if (way->nodes().empty()) { if (way->nodes().empty()) {
return sum; return sum;
} else {
return sum + way->nodes().size() - 1;
} }
return sum + way->nodes().size() - 1;
}); });
} }
uint32_t extract_segments_from_way_impl(osmium::area::ProblemReporter* problem_reporter, const osmium::Way& way, role_type role) { uint32_t extract_segments_from_way_impl(ProblemReporter* problem_reporter, uint64_t& duplicate_nodes, const osmium::Way& way, role_type role) {
uint32_t duplicate_nodes = 0; uint32_t invalid_locations = 0;
osmium::NodeRef previous_nr; osmium::NodeRef previous_nr;
for (const osmium::NodeRef& nr : way.nodes()) { for (const osmium::NodeRef& nr : way.nodes()) {
if (!nr.location().valid()) {
++invalid_locations;
if (problem_reporter) {
problem_reporter->report_invalid_location(way.id(), nr.ref());
}
continue;
}
if (previous_nr.location()) { if (previous_nr.location()) {
if (previous_nr.location() != nr.location()) { if (previous_nr.location() != nr.location()) {
m_segments.emplace_back(previous_nr, nr, role, &way); m_segments.emplace_back(previous_nr, nr, role, &way);
@ -128,7 +138,7 @@ namespace osmium {
previous_nr = nr; previous_nr = nr;
} }
return duplicate_nodes; return invalid_locations;
} }
public: public:
@ -147,7 +157,7 @@ namespace osmium {
SegmentList& operator=(SegmentList&&) = delete; SegmentList& operator=(SegmentList&&) = delete;
/// The number of segments in the list. /// The number of segments in the list.
size_t size() const noexcept { std::size_t size() const noexcept {
return m_segments.size(); return m_segments.size();
} }
@ -167,12 +177,12 @@ namespace osmium {
return m_segments.back(); return m_segments.back();
} }
const NodeRefSegment& operator[](size_t n) const noexcept { const NodeRefSegment& operator[](std::size_t n) const noexcept {
assert(n < m_segments.size()); assert(n < m_segments.size());
return m_segments[n]; return m_segments[n];
} }
NodeRefSegment& operator[](size_t n) noexcept { NodeRefSegment& operator[](std::size_t n) noexcept {
assert(n < m_segments.size()); assert(n < m_segments.size());
return m_segments[n]; return m_segments[n];
} }
@ -213,33 +223,48 @@ namespace osmium {
* same node or different nodes with same location) are * same node or different nodes with same location) are
* removed after reporting the duplicate node. * removed after reporting the duplicate node.
*/ */
uint32_t extract_segments_from_way(osmium::area::ProblemReporter* problem_reporter, const osmium::Way& way) { uint32_t extract_segments_from_way(ProblemReporter* problem_reporter, uint64_t& duplicate_nodes, const osmium::Way& way) {
if (way.nodes().empty()) { if (way.nodes().empty()) {
return 0; return 0;
} }
m_segments.reserve(way.nodes().size() - 1); m_segments.reserve(way.nodes().size() - 1);
return extract_segments_from_way_impl(problem_reporter, way, role_type::outer); return extract_segments_from_way_impl(problem_reporter, duplicate_nodes, way, role_type::outer);
} }
/** /**
* Extract all segments from all ways that make up this * Extract all segments from all ways that make up this
* multipolygon relation and add them to the list. * multipolygon relation and add them to the list.
*/ */
uint32_t extract_segments_from_ways(osmium::area::ProblemReporter* problem_reporter, const osmium::Relation& relation, const std::vector<const osmium::Way*>& members) { uint32_t extract_segments_from_ways(ProblemReporter* problem_reporter,
assert(relation.members().size() >= members.size()); uint64_t& duplicate_nodes,
uint64_t& duplicate_ways,
const osmium::Relation& relation,
const std::vector<const osmium::Way*>& members) {
assert(relation.cmembers().size() >= members.size());
const size_t num_segments = get_num_segments(members); const std::size_t num_segments = get_num_segments(members);
if (problem_reporter) { if (problem_reporter) {
problem_reporter->set_nodes(num_segments); problem_reporter->set_nodes(num_segments);
} }
m_segments.reserve(num_segments); m_segments.reserve(num_segments);
uint32_t duplicate_nodes = 0; std::unordered_set<osmium::object_id_type> ids;
for_each_member(relation, members, [this, &problem_reporter, &duplicate_nodes](const osmium::RelationMember& member, const osmium::Way& way) { ids.reserve(members.size());
duplicate_nodes += extract_segments_from_way_impl(problem_reporter, way, parse_role(member.role())); uint32_t invalid_locations = 0;
for_each_member(relation, members, [&](const osmium::RelationMember& member, const osmium::Way& way) {
if (ids.count(way.id()) == 0) {
ids.insert(way.id());
const auto role = parse_role(member.role());
invalid_locations += extract_segments_from_way_impl(problem_reporter, duplicate_nodes, way, role);
} else {
++duplicate_ways;
if (problem_reporter) {
problem_reporter->report_duplicate_way(way);
}
}
}); });
return duplicate_nodes; return invalid_locations;
} }
/** /**
@ -248,9 +273,7 @@ namespace osmium {
* same segment. So if there are three, for instance, two will * same segment. So if there are three, for instance, two will
* be removed and one will be left. * be removed and one will be left.
*/ */
uint32_t erase_duplicate_segments(osmium::area::ProblemReporter* problem_reporter) { void erase_duplicate_segments(ProblemReporter* problem_reporter, uint64_t& duplicate_segments, uint64_t& overlapping_segments) {
uint32_t duplicate_segments = 0;
while (true) { while (true) {
auto it = std::adjacent_find(m_segments.begin(), m_segments.end()); auto it = std::adjacent_find(m_segments.begin(), m_segments.end());
if (it == m_segments.end()) { if (it == m_segments.end()) {
@ -273,10 +296,16 @@ namespace osmium {
problem_reporter->report_duplicate_segment(it->first(), it->second()); problem_reporter->report_duplicate_segment(it->first(), it->second());
} }
} }
m_segments.erase(it, it+2);
if (it+2 != m_segments.end() && *it == *(it+2)) {
++overlapping_segments;
if (problem_reporter) {
problem_reporter->report_overlapping_segment(it->first(), it->second());
}
} }
return duplicate_segments; m_segments.erase(it, it+2);
}
} }
/** /**
@ -286,14 +315,14 @@ namespace osmium {
* reported to this object. * reported to this object.
* @returns true if there are intersections. * @returns true if there are intersections.
*/ */
uint32_t find_intersections(osmium::area::ProblemReporter* problem_reporter) const { uint32_t find_intersections(ProblemReporter* problem_reporter) const {
if (m_segments.empty()) { if (m_segments.empty()) {
return 0; return 0;
} }
uint32_t found_intersections = 0; uint32_t found_intersections = 0;
for (auto it1 = m_segments.cbegin(); it1 != m_segments.cend()-1; ++it1) { for (auto it1 = m_segments.cbegin(); it1 != m_segments.cend() - 1; ++it1) {
const NodeRefSegment& s1 = *it1; const NodeRefSegment& s1 = *it1;
for (auto it2 = it1+1; it2 != m_segments.end(); ++it2) { for (auto it2 = it1+1; it2 != m_segments.end(); ++it2) {
const NodeRefSegment& s2 = *it2; const NodeRefSegment& s2 = *it2;
@ -305,7 +334,7 @@ namespace osmium {
} }
if (y_range_overlap(s1, s2)) { if (y_range_overlap(s1, s2)) {
osmium::Location intersection = calculate_intersection(s1, s2); osmium::Location intersection{calculate_intersection(s1, s2)};
if (intersection) { if (intersection) {
++found_intersections; ++found_intersections;
if (m_debug) { if (m_debug) {

View File

@ -0,0 +1,132 @@
#ifndef OSMIUM_AREA_GEOM_ASSEMBLER_HPP
#define OSMIUM_AREA_GEOM_ASSEMBLER_HPP
/*
This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2013-2017 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 <osmium/area/assembler_config.hpp>
#include <osmium/area/detail/basic_assembler.hpp>
#include <osmium/area/detail/segment_list.hpp>
#include <osmium/area/stats.hpp>
#include <osmium/builder/osm_object_builder.hpp>
#include <osmium/memory/buffer.hpp>
#include <osmium/osm/relation.hpp>
#include <osmium/osm/way.hpp>
namespace osmium {
namespace area {
/**
* Assembles area objects from closed ways or multipolygon relations
* and their members. Unlike the Assembler, this one doesn't take
* tags into account at all. And it doesn't interpret all the config
* settings and doesn't do all the checks and error reporting the
* Assembler does.
*
* This class was developed specifically for the need of osm2pgsql.
* Unless you know what you are doing, use the Assembler class instead
* of this class. Contact the Libosmium developers if you want to use
* this class.
*/
class GeomAssembler : public detail::BasicAssembler {
public:
using config_type = osmium::area::AssemblerConfig;
explicit GeomAssembler(const config_type& config) :
detail::BasicAssembler(config) {
}
~GeomAssembler() noexcept = default;
/**
* Assemble an area from the given way.
*
* The resulting area is put into the out_buffer.
*
* @returns false if there was some kind of error building the
* area, true otherwise.
*/
bool operator()(const osmium::Way& way, osmium::memory::Buffer& out_buffer) {
segment_list().extract_segments_from_way(config().problem_reporter, stats().duplicate_nodes, way);
if (!create_rings()) {
return false;
}
{
osmium::builder::AreaBuilder builder{out_buffer};
builder.initialize_from_object(way);
add_rings_to_area(builder);
}
out_buffer.commit();
return true;
}
/**
* Assemble an area from the given relation and its member ways
* which are in the ways_buffer.
*
* The resulting area is put into the out_buffer.
*
* @returns false if there was some kind of error building the
* area, true otherwise.
*/
bool operator()(const osmium::Relation& relation, const osmium::memory::Buffer& ways_buffer, osmium::memory::Buffer& out_buffer) {
for (const auto& way : ways_buffer.select<osmium::Way>()) {
segment_list().extract_segments_from_way(config().problem_reporter, stats().duplicate_nodes, way);
}
if (!create_rings()) {
return false;
}
{
osmium::builder::AreaBuilder builder{out_buffer};
builder.initialize_from_object(relation);
add_rings_to_area(builder);
}
out_buffer.commit();
return true;
}
}; // class GeomAssembler
} // namespace area
} // namespace osmium
#endif // OSMIUM_AREA_GEOM_ASSEMBLER_HPP

View File

@ -81,7 +81,7 @@ namespace osmium {
osmium::memory::Buffer m_output_buffer; osmium::memory::Buffer m_output_buffer;
osmium::area::area_stats m_stats; area_stats m_stats;
static constexpr size_t initial_output_buffer_size = 1024 * 1024; static constexpr size_t initial_output_buffer_size = 1024 * 1024;
static constexpr size_t max_buffer_size_for_flush = 100 * 1024; static constexpr size_t max_buffer_size_for_flush = 100 * 1024;
@ -109,7 +109,7 @@ namespace osmium {
m_output_buffer(initial_output_buffer_size, osmium::memory::Buffer::auto_grow::yes) { m_output_buffer(initial_output_buffer_size, osmium::memory::Buffer::auto_grow::yes) {
} }
const osmium::area::area_stats& stats() const noexcept { const area_stats& stats() const noexcept {
return m_stats; return m_stats;
} }
@ -127,11 +127,7 @@ namespace osmium {
return false; return false;
} }
if ((!std::strcmp(type, "multipolygon")) || (!std::strcmp(type, "boundary"))) { return (!std::strcmp(type, "multipolygon")) || (!std::strcmp(type, "boundary"));
return true;
}
return false;
} }
/** /**
@ -155,11 +151,11 @@ namespace osmium {
} }
try { try {
if (!way.nodes().front().location() || !way.nodes().back().location()) { if (!way.nodes().front().location() || !way.nodes().back().location()) {
throw osmium::invalid_location("invalid location"); throw osmium::invalid_location{"invalid location"};
} }
if (way.ends_have_same_location()) { if (way.ends_have_same_location()) {
// way is closed and has enough nodes, build simple multipolygon // way is closed and has enough nodes, build simple multipolygon
TAssembler assembler(m_assembler_config); TAssembler assembler{m_assembler_config};
assembler(way, m_output_buffer); assembler(way, m_output_buffer);
m_stats += assembler.stats(); m_stats += assembler.stats();
possibly_flush_output_buffer(); possibly_flush_output_buffer();
@ -174,6 +170,7 @@ namespace osmium {
const osmium::memory::Buffer& buffer = this->members_buffer(); const osmium::memory::Buffer& buffer = this->members_buffer();
std::vector<const osmium::Way*> ways; std::vector<const osmium::Way*> ways;
ways.reserve(relation.members().size());
for (const auto& member : relation.members()) { for (const auto& member : relation.members()) {
if (member.ref() != 0) { if (member.ref() != 0) {
const size_t offset = this->get_offset(member.type(), member.ref()); const size_t offset = this->get_offset(member.type(), member.ref());
@ -182,7 +179,7 @@ namespace osmium {
} }
try { try {
TAssembler assembler(m_assembler_config); TAssembler assembler{m_assembler_config};
assembler(relation, ways, m_output_buffer); assembler(relation, ways, m_output_buffer);
m_stats += assembler.stats(); m_stats += assembler.stats();
possibly_flush_output_buffer(); possibly_flush_output_buffer();

View File

@ -0,0 +1,189 @@
#ifndef OSMIUM_AREA_MULTIPOLYGON_MANAGER_HPP
#define OSMIUM_AREA_MULTIPOLYGON_MANAGER_HPP
/*
This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2013-2017 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 <cstddef>
#include <cstdint>
#include <cstring>
#include <vector>
#include <osmium/area/stats.hpp>
#include <osmium/osm/item_type.hpp>
#include <osmium/osm/relation.hpp>
#include <osmium/osm/tag.hpp>
#include <osmium/osm/way.hpp>
#include <osmium/relations/manager_util.hpp>
#include <osmium/relations/members_database.hpp>
#include <osmium/relations/relations_database.hpp>
#include <osmium/relations/relations_manager.hpp>
#include <osmium/storage/item_stash.hpp>
#include <osmium/tags/taglist.hpp>
#include <osmium/tags/tags_filter.hpp>
namespace osmium {
/**
* @brief Code related to the building of areas (multipolygons) from relations.
*/
namespace area {
/**
* This class collects all data needed for creating areas from
* relations tagged with type=multipolygon or type=boundary.
* Most of its functionality is derived from the parent class
* osmium::relations::Collector.
*
* The actual assembling of the areas is done by the assembler
* class given as template argument.
*
* @tparam TAssembler Multipolygon Assembler class.
* @pre The Ids of all objects must be unique in the input data.
*/
template <typename TAssembler>
class MultipolygonManager : public osmium::relations::RelationsManager<MultipolygonManager<TAssembler>, false, true, false> {
using assembler_config_type = typename TAssembler::config_type;
const assembler_config_type m_assembler_config;
area_stats m_stats;
osmium::TagsFilter m_filter;
public:
/**
* Construct a MultipolygonManager.
*
* @param assembler_config The configuration that will be given to
* any newly constructed area assembler.
* @param filter An optional filter specifying what tags are
* needed on closed ways or multipolygon relations
* to build the area.
*/
explicit MultipolygonManager(const assembler_config_type& assembler_config, const osmium::TagsFilter& filter = osmium::TagsFilter{true}) :
m_assembler_config(assembler_config),
m_filter(filter) {
}
/**
* Access the aggregated statistics generated by the assemblers
* called from the manager.
*/
const area_stats& stats() const noexcept {
return m_stats;
}
/**
* We are interested in all relations tagged with type=multipolygon
* or type=boundary with at least one way member.
*/
bool new_relation(const osmium::Relation& relation) const {
const char* type = relation.tags().get_value_by_key("type");
// ignore relations without "type" tag
if (type == nullptr) {
return false;
}
if (((!std::strcmp(type, "multipolygon")) || (!std::strcmp(type, "boundary"))) && osmium::tags::match_any_of(relation.tags(), m_filter)) {
return std::any_of(relation.members().cbegin(), relation.members().cend(), [](const RelationMember& member) {
return member.type() == osmium::item_type::way;
});
}
return false;
}
/**
* This is called when a relation is complete, ie. all members
* were found in the input. It will build the area using the
* assembler.
*/
void complete_relation(const osmium::Relation& relation) {
std::vector<const osmium::Way*> ways;
ways.reserve(relation.members().size());
for (const auto& member : relation.members()) {
if (member.ref() != 0) {
ways.push_back(this->get_member_way(member.ref()));
assert(ways.back() != nullptr);
}
}
try {
TAssembler assembler{m_assembler_config};
assembler(relation, ways, this->buffer());
m_stats += assembler.stats();
} catch (const osmium::invalid_location&) {
// XXX ignore
}
}
void after_way(const osmium::Way& way) {
// you need at least 4 nodes to make up a polygon
if (way.nodes().size() <= 3) {
return;
}
try {
if (!way.nodes().front().location() || !way.nodes().back().location()) {
throw osmium::invalid_location{"invalid location"};
}
if (way.ends_have_same_location()) {
if (way.tags().has_tag("area", "no")) {
return;
}
if (osmium::tags::match_none_of(way.tags(), m_filter)) {
return;
}
TAssembler assembler{m_assembler_config};
assembler(way, this->buffer());
m_stats += assembler.stats();
this->possibly_flush();
}
} catch (const osmium::invalid_location&) {
// XXX ignore
}
}
}; // class MultipolygonManager
} // namespace area
} // namespace osmium
#endif // OSMIUM_AREA_MULTIPOLYGON_MANAGER_HPP

View File

@ -0,0 +1,180 @@
#ifndef OSMIUM_AREA_MULTIPOLYGON_MANAGER_LEGACY_HPP
#define OSMIUM_AREA_MULTIPOLYGON_MANAGER_LEGACY_HPP
/*
This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2013-2017 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 <cstddef>
#include <cstdint>
#include <cstring>
#include <vector>
#include <osmium/area/stats.hpp>
#include <osmium/handler.hpp>
#include <osmium/handler/check_order.hpp>
#include <osmium/memory/buffer.hpp>
#include <osmium/memory/callback_buffer.hpp>
#include <osmium/osm/item_type.hpp>
#include <osmium/osm/relation.hpp>
#include <osmium/osm/tag.hpp>
#include <osmium/osm/way.hpp>
#include <osmium/relations/manager_util.hpp>
#include <osmium/relations/members_database.hpp>
#include <osmium/relations/relations_database.hpp>
#include <osmium/relations/relations_manager.hpp>
#include <osmium/storage/item_stash.hpp>
namespace osmium {
/**
* @brief Code related to the building of areas (multipolygons) from relations.
*/
namespace area {
/**
* This class collects all data needed for creating areas from
* relations tagged with type=multipolygon or type=boundary.
* Most of its functionality is derived from the parent class
* osmium::relations::Collector.
*
* The actual assembling of the areas is done by the assembler
* class given as template argument.
*
* @tparam TAssembler Multipolygon Assembler class.
* @pre The Ids of all objects must be unique in the input data.
*/
template <typename TAssembler>
class MultipolygonManagerLegacy : public osmium::relations::RelationsManager<MultipolygonManagerLegacy<TAssembler>, false, true, false> {
using assembler_config_type = typename TAssembler::config_type;
const assembler_config_type m_assembler_config;
area_stats m_stats;
public:
/**
* Construct a MultipolygonManagerLegacy.
*
* @param assembler_config The configuration that will be given to
* any newly constructed area assembler.
*/
explicit MultipolygonManagerLegacy(const assembler_config_type& assembler_config) :
m_assembler_config(assembler_config) {
}
/**
* Access the aggregated statistics generated by the assemblers
* called from the manager.
*/
const area_stats& stats() const noexcept {
return m_stats;
}
/**
* We are interested in all relations tagged with type=multipolygon
* or type=boundary with at least one way member.
*/
bool new_relation(const osmium::Relation& relation) const {
const char* type = relation.tags().get_value_by_key("type");
// ignore relations without "type" tag
if (!type) {
return false;
}
if ((!std::strcmp(type, "multipolygon")) || (!std::strcmp(type, "boundary"))) {
return std::any_of(relation.members().cbegin(), relation.members().cend(), [](const RelationMember& member) {
return member.type() == osmium::item_type::way;
});
}
return false;
}
/**
* This is called when a relation is complete, ie. all members
* were found in the input. It will build the area using the
* assembler.
*/
void complete_relation(const osmium::Relation& relation) {
std::vector<const osmium::Way*> ways;
ways.reserve(relation.members().size());
for (const auto& member : relation.members()) {
if (member.ref() != 0) {
ways.push_back(this->get_member_way(member.ref()));
assert(ways.back() != nullptr);
}
}
try {
TAssembler assembler{m_assembler_config};
assembler(relation, ways, this->buffer());
m_stats += assembler.stats();
} catch (const osmium::invalid_location&) {
// XXX ignore
}
}
/**
* This is called when a way is not in any multipolygon
* relation.
*/
void way_not_in_any_relation(const osmium::Way& way) {
// you need at least 4 nodes to make up a polygon
if (way.nodes().size() <= 3) {
return;
}
try {
if (!way.nodes().front().location() || !way.nodes().back().location()) {
throw osmium::invalid_location{"invalid location"};
}
if (way.ends_have_same_location()) {
// way is closed and has enough nodes, build simple multipolygon
TAssembler assembler{m_assembler_config};
assembler(way, this->buffer());
m_stats += assembler.stats();
}
} catch (const osmium::invalid_location&) {
// XXX ignore
}
}
}; // class MultipolygonManagerLegacy
} // namespace area
} // namespace osmium
#endif // OSMIUM_AREA_MULTIPOLYGON_MANAGER_LEGACY_HPP

View File

@ -143,6 +143,18 @@ namespace osmium {
virtual void report_duplicate_segment(const osmium::NodeRef& nr1, const osmium::NodeRef& nr2) { virtual void report_duplicate_segment(const osmium::NodeRef& nr1, const osmium::NodeRef& nr2) {
} }
/**
* Report a duplicate segments. Two or more segments are directly
* on top of each other. This can be a problem, if there is a
* spike for instance, or it could be okay, if there are touching
* inner rings.
*
* @param nr1 NodeRef of one end of the segment.
* @param nr2 NodeRef of the other end of the segment.
*/
virtual void report_overlapping_segment(const osmium::NodeRef& nr1, const osmium::NodeRef& nr2) {
}
/** /**
* Report an open ring. * Report an open ring.
* *
@ -189,6 +201,23 @@ namespace osmium {
virtual void report_inner_with_same_tags(const osmium::Way& way) { virtual void report_inner_with_same_tags(const osmium::Way& way) {
} }
/**
* Report an invalid location in a way.
*
* @param way_id ID of the way the node is in.
* @param node_id ID of the node with the invalid location.
*/
virtual void report_invalid_location(osmium::object_id_type way_id, osmium::object_id_type node_id) {
}
/**
* Report a way that is more than once in a relation.
*
* @param way The way
*/
virtual void report_duplicate_way(const osmium::Way& way) {
}
/** /**
* In addition to reporting specific problems, this is used to * In addition to reporting specific problems, this is used to
* report all ways belonging to areas having problems. * report all ways belonging to areas having problems.

View File

@ -60,58 +60,76 @@ namespace osmium {
~ProblemReporterException() override = default; ~ProblemReporterException() override = default;
void report_duplicate_node(osmium::object_id_type node_id1, osmium::object_id_type node_id2, osmium::Location location) override { void report_duplicate_node(osmium::object_id_type node_id1, osmium::object_id_type node_id2, osmium::Location location) override {
m_sstream.str(); m_sstream.str("");
ProblemReporterStream::report_duplicate_node(node_id1, node_id2, location); ProblemReporterStream::report_duplicate_node(node_id1, node_id2, location);
throw std::runtime_error(m_sstream.str()); throw std::runtime_error{m_sstream.str()};
} }
void report_touching_ring(osmium::object_id_type node_id, osmium::Location location) override { void report_touching_ring(osmium::object_id_type node_id, osmium::Location location) override {
m_sstream.str(); m_sstream.str("");
ProblemReporterStream::report_touching_ring(node_id, location); ProblemReporterStream::report_touching_ring(node_id, location);
throw std::runtime_error(m_sstream.str()); throw std::runtime_error{m_sstream.str()};
} }
void report_intersection(osmium::object_id_type way1_id, osmium::Location way1_seg_start, osmium::Location way1_seg_end, void report_intersection(osmium::object_id_type way1_id, osmium::Location way1_seg_start, osmium::Location way1_seg_end,
osmium::object_id_type way2_id, osmium::Location way2_seg_start, osmium::Location way2_seg_end, osmium::Location intersection) override { osmium::object_id_type way2_id, osmium::Location way2_seg_start, osmium::Location way2_seg_end, osmium::Location intersection) override {
m_sstream.str(); m_sstream.str("");
ProblemReporterStream::report_intersection(way1_id, way1_seg_start, way1_seg_end, way2_id, way2_seg_start, way2_seg_end, intersection); ProblemReporterStream::report_intersection(way1_id, way1_seg_start, way1_seg_end, way2_id, way2_seg_start, way2_seg_end, intersection);
throw std::runtime_error(m_sstream.str()); throw std::runtime_error{m_sstream.str()};
} }
void report_duplicate_segment(const osmium::NodeRef& nr1, const osmium::NodeRef& nr2) override { void report_duplicate_segment(const osmium::NodeRef& nr1, const osmium::NodeRef& nr2) override {
m_sstream.str(); m_sstream.str("");
ProblemReporterStream::report_duplicate_segment(nr1, nr2); ProblemReporterStream::report_duplicate_segment(nr1, nr2);
throw std::runtime_error(m_sstream.str()); throw std::runtime_error{m_sstream.str()};
}
void report_overlapping_segment(const osmium::NodeRef& nr1, const osmium::NodeRef& nr2) override {
m_sstream.str("");
ProblemReporterStream::report_overlapping_segment(nr1, nr2);
throw std::runtime_error{m_sstream.str()};
} }
void report_ring_not_closed(const osmium::NodeRef& nr, const osmium::Way* way = nullptr) override { void report_ring_not_closed(const osmium::NodeRef& nr, const osmium::Way* way = nullptr) override {
m_sstream.str(); m_sstream.str("");
ProblemReporterStream::report_ring_not_closed(nr, way); ProblemReporterStream::report_ring_not_closed(nr, way);
throw std::runtime_error(m_sstream.str()); throw std::runtime_error{m_sstream.str()};
} }
void report_role_should_be_outer(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) override { void report_role_should_be_outer(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) override {
m_sstream.str(); m_sstream.str("");
ProblemReporterStream::report_role_should_be_outer(way_id, seg_start, seg_end); ProblemReporterStream::report_role_should_be_outer(way_id, seg_start, seg_end);
throw std::runtime_error(m_sstream.str()); throw std::runtime_error{m_sstream.str()};
} }
void report_role_should_be_inner(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) override { void report_role_should_be_inner(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) override {
m_sstream.str(); m_sstream.str("");
ProblemReporterStream::report_role_should_be_inner(way_id, seg_start, seg_end); ProblemReporterStream::report_role_should_be_inner(way_id, seg_start, seg_end);
throw std::runtime_error(m_sstream.str()); throw std::runtime_error{m_sstream.str()};
} }
void report_way_in_multiple_rings(const osmium::Way& way) override { void report_way_in_multiple_rings(const osmium::Way& way) override {
m_sstream.str(); m_sstream.str("");
ProblemReporterStream::report_way_in_multiple_rings(way); ProblemReporterStream::report_way_in_multiple_rings(way);
throw std::runtime_error(m_sstream.str()); throw std::runtime_error{m_sstream.str()};
} }
void report_inner_with_same_tags(const osmium::Way& way) override { void report_inner_with_same_tags(const osmium::Way& way) override {
m_sstream.str(); m_sstream.str("");
ProblemReporterStream::report_inner_with_same_tags(way); ProblemReporterStream::report_inner_with_same_tags(way);
throw std::runtime_error(m_sstream.str()); throw std::runtime_error{m_sstream.str()};
}
void report_invalid_location(osmium::object_id_type way_id, osmium::object_id_type node_id) override {
m_sstream.str("");
ProblemReporterStream::report_invalid_location(way_id, node_id);
throw std::runtime_error{m_sstream.str()};
}
void report_duplicate_way(const osmium::Way& way) override {
m_sstream.str("");
ProblemReporterStream::report_duplicate_way(way);
throw std::runtime_error{m_sstream.str()};
} }
}; // class ProblemReporterException }; // class ProblemReporterException

View File

@ -73,14 +73,14 @@ namespace osmium {
gdalcpp::Layer m_layer_ways; gdalcpp::Layer m_layer_ways;
void set_object(gdalcpp::Feature& feature) { void set_object(gdalcpp::Feature& feature) {
const char t[2] = { osmium::item_type_to_char(m_object_type), '\0' }; const char t[2] = {osmium::item_type_to_char(m_object_type), '\0'};
feature.set_field("obj_type", t); feature.set_field("obj_type", t);
feature.set_field("obj_id", int32_t(m_object_id)); feature.set_field("obj_id", int32_t(m_object_id));
feature.set_field("nodes", int32_t(m_nodes)); feature.set_field("nodes", int32_t(m_nodes));
} }
void write_point(const char* problem_type, osmium::object_id_type id1, osmium::object_id_type id2, osmium::Location location) { void write_point(const char* problem_type, osmium::object_id_type id1, osmium::object_id_type id2, osmium::Location location) {
gdalcpp::Feature feature(m_layer_perror, m_ogr_factory.create_point(location)); gdalcpp::Feature feature{m_layer_perror, m_ogr_factory.create_point(location)};
set_object(feature); set_object(feature);
feature.set_field("id1", double(id1)); feature.set_field("id1", double(id1));
feature.set_field("id2", double(id2)); feature.set_field("id2", double(id2));
@ -93,7 +93,7 @@ namespace osmium {
ogr_linestring->addPoint(loc1.lon(), loc1.lat()); ogr_linestring->addPoint(loc1.lon(), loc1.lat());
ogr_linestring->addPoint(loc2.lon(), loc2.lat()); ogr_linestring->addPoint(loc2.lon(), loc2.lat());
gdalcpp::Feature feature(m_layer_lerror, std::move(ogr_linestring)); gdalcpp::Feature feature{m_layer_lerror, std::move(ogr_linestring)};
set_object(feature); set_object(feature);
feature.set_field("id1", static_cast<double>(id1)); feature.set_field("id1", static_cast<double>(id1));
feature.set_field("id2", static_cast<double>(id2)); feature.set_field("id2", static_cast<double>(id2));
@ -158,6 +158,10 @@ namespace osmium {
write_line("duplicate_segment", nr1.ref(), nr2.ref(), nr1.location(), nr2.location()); write_line("duplicate_segment", nr1.ref(), nr2.ref(), nr1.location(), nr2.location());
} }
void report_overlapping_segment(const osmium::NodeRef& nr1, const osmium::NodeRef& nr2) override {
write_line("overlapping_segment", nr1.ref(), nr2.ref(), nr1.location(), nr2.location());
}
void report_ring_not_closed(const osmium::NodeRef& nr, const osmium::Way* way = nullptr) override { void report_ring_not_closed(const osmium::NodeRef& nr, const osmium::Way* way = nullptr) override {
write_point("ring_not_closed", nr.ref(), way ? way->id() : 0, nr.location()); write_point("ring_not_closed", nr.ref(), way ? way->id() : 0, nr.location());
} }
@ -175,7 +179,7 @@ namespace osmium {
return; return;
} }
try { try {
gdalcpp::Feature feature(m_layer_lerror, m_ogr_factory.create_linestring(way)); gdalcpp::Feature feature{m_layer_lerror, m_ogr_factory.create_linestring(way)};
set_object(feature); set_object(feature);
feature.set_field("id1", int32_t(way.id())); feature.set_field("id1", int32_t(way.id()));
feature.set_field("id2", 0); feature.set_field("id2", 0);
@ -191,7 +195,7 @@ namespace osmium {
return; return;
} }
try { try {
gdalcpp::Feature feature(m_layer_lerror, m_ogr_factory.create_linestring(way)); gdalcpp::Feature feature{m_layer_lerror, m_ogr_factory.create_linestring(way)};
set_object(feature); set_object(feature);
feature.set_field("id1", int32_t(way.id())); feature.set_field("id1", int32_t(way.id()));
feature.set_field("id2", 0); feature.set_field("id2", 0);
@ -202,6 +206,22 @@ namespace osmium {
} }
} }
void report_duplicate_way(const osmium::Way& way) override {
if (way.nodes().size() < 2) {
return;
}
try {
gdalcpp::Feature feature{m_layer_lerror, m_ogr_factory.create_linestring(way)};
set_object(feature);
feature.set_field("id1", int32_t(way.id()));
feature.set_field("id2", 0);
feature.set_field("problem", "duplicate_way");
feature.add_to_layer();
} catch (const osmium::geometry_error&) {
// XXX
}
}
void report_way(const osmium::Way& way) override { void report_way(const osmium::Way& way) override {
if (way.nodes().empty()) { if (way.nodes().empty()) {
return; return;
@ -212,7 +232,7 @@ namespace osmium {
return; return;
} }
try { try {
gdalcpp::Feature feature(m_layer_ways, m_ogr_factory.create_linestring(way)); gdalcpp::Feature feature{m_layer_ways, m_ogr_factory.create_linestring(way)};
set_object(feature); set_object(feature);
feature.set_field("way_id", int32_t(way.id())); feature.set_field("way_id", int32_t(way.id()));
feature.add_to_layer(); feature.add_to_layer();

View File

@ -85,6 +85,12 @@ namespace osmium {
<< " node_id2=" << nr2.ref() << " location2=" << nr2.location() << "\n"; << " node_id2=" << nr2.ref() << " location2=" << nr2.location() << "\n";
} }
void report_overlapping_segment(const osmium::NodeRef& nr1, const osmium::NodeRef& nr2) override {
header("overlapping segment");
*m_out << "node_id1=" << nr1.ref() << " location1=" << nr1.location()
<< " node_id2=" << nr2.ref() << " location2=" << nr2.location() << "\n";
}
void report_ring_not_closed(const osmium::NodeRef& nr, const osmium::Way* way = nullptr) override { void report_ring_not_closed(const osmium::NodeRef& nr, const osmium::Way* way = nullptr) override {
header("ring not closed"); header("ring not closed");
*m_out << "node_id=" << nr.ref() << " location=" << nr.location(); *m_out << "node_id=" << nr.ref() << " location=" << nr.location();
@ -114,6 +120,16 @@ namespace osmium {
*m_out << "way_id=" << way.id() << '\n'; *m_out << "way_id=" << way.id() << '\n';
} }
void report_invalid_location(osmium::object_id_type way_id, osmium::object_id_type node_id) override {
header("invalid location");
*m_out << "way_id=" << way_id << " node_id=" << node_id << '\n';
}
void report_duplicate_way(const osmium::Way& way) override {
header("duplicate way");
*m_out << "way_id=" << way.id() << '\n';
}
}; // class ProblemReporterStream }; // class ProblemReporterStream
} // namespace area } // namespace area

View File

@ -52,6 +52,7 @@ namespace osmium {
uint64_t area_touching_rings_case = 0; ///< More difficult case with touching rings uint64_t area_touching_rings_case = 0; ///< More difficult case with touching rings
uint64_t duplicate_nodes = 0; ///< Consecutive identical nodes or consecutive nodes with same location uint64_t duplicate_nodes = 0; ///< Consecutive identical nodes or consecutive nodes with same location
uint64_t duplicate_segments = 0; ///< Segments duplicated (going back and forth) uint64_t duplicate_segments = 0; ///< Segments duplicated (going back and forth)
uint64_t duplicate_ways = 0; ///< Ways that are in relation more than once
uint64_t from_relations = 0; ///< Area created from multipolygon relation uint64_t from_relations = 0; ///< Area created from multipolygon relation
uint64_t from_ways = 0; ///< Area created from way uint64_t from_ways = 0; ///< Area created from way
uint64_t inner_rings = 0; ///< Number of inner rings uint64_t inner_rings = 0; ///< Number of inner rings
@ -63,11 +64,13 @@ namespace osmium {
uint64_t nodes = 0; ///< Number of nodes in the area uint64_t nodes = 0; ///< Number of nodes in the area
uint64_t open_rings = 0; ///< Number of open rings in the area uint64_t open_rings = 0; ///< Number of open rings in the area
uint64_t outer_rings = 0; ///< Number of outer rings in the area uint64_t outer_rings = 0; ///< Number of outer rings in the area
uint64_t overlapping_segments = 0; ///< Three or more segments with same end points
uint64_t short_ways = 0; ///< Number of ways with less than two nodes uint64_t short_ways = 0; ///< Number of ways with less than two nodes
uint64_t single_way_in_mp_relation = 0; ///< Multipolygon relation containing a single way uint64_t single_way_in_mp_relation = 0; ///< Multipolygon relation containing a single way
uint64_t touching_rings = 0; ///< Rings touching in a node uint64_t touching_rings = 0; ///< Rings touching in a node
uint64_t ways_in_multiple_rings = 0; ///< Different segments of a way ended up in different rings uint64_t ways_in_multiple_rings = 0; ///< Different segments of a way ended up in different rings
uint64_t wrong_role = 0; ///< Member has wrong role (not "outer", "inner", or empty) uint64_t wrong_role = 0; ///< Member has wrong role (not "outer", "inner", or empty)
uint64_t invalid_locations = 0; ///< Invalid location found
area_stats& operator+=(const area_stats& other) noexcept { area_stats& operator+=(const area_stats& other) noexcept {
area_really_complex_case += other.area_really_complex_case; area_really_complex_case += other.area_really_complex_case;
@ -75,6 +78,7 @@ namespace osmium {
area_touching_rings_case += other.area_touching_rings_case; area_touching_rings_case += other.area_touching_rings_case;
duplicate_nodes += other.duplicate_nodes; duplicate_nodes += other.duplicate_nodes;
duplicate_segments += other.duplicate_segments; duplicate_segments += other.duplicate_segments;
duplicate_ways += other.duplicate_ways;
from_relations += other.from_relations; from_relations += other.from_relations;
from_ways += other.from_ways; from_ways += other.from_ways;
inner_rings += other.inner_rings; inner_rings += other.inner_rings;
@ -91,6 +95,7 @@ namespace osmium {
touching_rings += other.touching_rings; touching_rings += other.touching_rings;
ways_in_multiple_rings += other.ways_in_multiple_rings; ways_in_multiple_rings += other.ways_in_multiple_rings;
wrong_role += other.wrong_role; wrong_role += other.wrong_role;
invalid_locations += invalid_locations;
return *this; return *this;
} }
@ -103,6 +108,7 @@ namespace osmium {
<< " area_touching_rings_case=" << s.area_touching_rings_case << " area_touching_rings_case=" << s.area_touching_rings_case
<< " duplicate_nodes=" << s.duplicate_nodes << " duplicate_nodes=" << s.duplicate_nodes
<< " duplicate_segments=" << s.duplicate_segments << " duplicate_segments=" << s.duplicate_segments
<< " duplicate_ways=" << s.duplicate_ways
<< " from_relations=" << s.from_relations << " from_relations=" << s.from_relations
<< " from_ways=" << s.from_ways << " from_ways=" << s.from_ways
<< " inner_rings=" << s.inner_rings << " inner_rings=" << s.inner_rings
@ -118,7 +124,8 @@ namespace osmium {
<< " single_way_in_mp_relation=" << s.single_way_in_mp_relation << " single_way_in_mp_relation=" << s.single_way_in_mp_relation
<< " touching_rings=" << s.touching_rings << " touching_rings=" << s.touching_rings
<< " ways_in_multiple_rings=" << s.ways_in_multiple_rings << " ways_in_multiple_rings=" << s.ways_in_multiple_rings
<< " wrong_role=" << s.wrong_role; << " wrong_role=" << s.wrong_role
<< " invalid_locations=" << s.invalid_locations;
} }
} // namespace area } // namespace area

View File

@ -35,16 +35,12 @@ DEALINGS IN THE SOFTWARE.
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
#include <cstddef>
#include <cstdint> #include <cstdint>
#include <cstring> #include <cstring>
#include <new>
#include <string>
#include <type_traits>
#include <osmium/memory/buffer.hpp> #include <osmium/memory/buffer.hpp>
#include <osmium/memory/item.hpp> #include <osmium/memory/item.hpp>
#include <osmium/osm/types.hpp>
#include <osmium/util/cast.hpp>
#include <osmium/util/compatibility.hpp> #include <osmium/util/compatibility.hpp>
namespace osmium { namespace osmium {
@ -62,7 +58,7 @@ namespace osmium {
osmium::memory::Buffer& m_buffer; osmium::memory::Buffer& m_buffer;
Builder* m_parent; Builder* m_parent;
size_t m_item_offset; std::size_t m_item_offset;
Builder(const Builder&) = delete; Builder(const Builder&) = delete;
Builder(Builder&&) = delete; Builder(Builder&&) = delete;
@ -101,7 +97,7 @@ namespace osmium {
return *reinterpret_cast<osmium::memory::Item*>(m_buffer.data() + m_item_offset); return *reinterpret_cast<osmium::memory::Item*>(m_buffer.data() + m_item_offset);
} }
unsigned char* reserve_space(size_t size) { unsigned char* reserve_space(std::size_t size) {
return m_buffer.reserve_space(size); return m_buffer.reserve_space(size);
} }
@ -119,7 +115,9 @@ 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); // We know the padding is only a very small number, so it will
// always fit.
const auto padding = static_cast<osmium::memory::item_size_type>(osmium::memory::align_bytes - (size() % osmium::memory::align_bytes));
if (padding != osmium::memory::align_bytes) { if (padding != osmium::memory::align_bytes) {
std::fill_n(reserve_space(padding), padding, 0); std::fill_n(reserve_space(padding), padding, 0);
if (self) { if (self) {
@ -131,7 +129,7 @@ namespace osmium {
} }
} }
void add_size(uint32_t size) { void add_size(osmium::memory::item_size_type size) {
item().add_size(size); item().add_size(size);
if (m_parent) { if (m_parent) {
m_parent->add_size(size); m_parent->add_size(size);

View File

@ -71,7 +71,7 @@ namespace osmium {
* @deprecated * @deprecated
* Use osmium::builder::add_tag_list() instead. * Use osmium::builder::add_tag_list() instead.
*/ */
inline const osmium::TagList& build_tag_list(osmium::memory::Buffer& buffer, const std::initializer_list<std::pair<const char*, const char*>>& tags) { OSMIUM_DEPRECATED inline const osmium::TagList& build_tag_list(osmium::memory::Buffer& buffer, const std::initializer_list<std::pair<const char*, const char*>>& tags) {
const size_t pos = buffer.committed(); const size_t pos = buffer.committed();
{ {
osmium::builder::TagListBuilder tl_builder(buffer); osmium::builder::TagListBuilder tl_builder(buffer);
@ -87,7 +87,7 @@ namespace osmium {
* @deprecated * @deprecated
* Use osmium::builder::add_tag_list() instead. * Use osmium::builder::add_tag_list() instead.
*/ */
inline const osmium::TagList& build_tag_list_from_map(osmium::memory::Buffer& buffer, const std::map<const char*, const char*>& tags) { OSMIUM_DEPRECATED inline const osmium::TagList& build_tag_list_from_map(osmium::memory::Buffer& buffer, const std::map<const char*, const char*>& tags) {
const size_t pos = buffer.committed(); const size_t pos = buffer.committed();
{ {
osmium::builder::TagListBuilder tl_builder(buffer); osmium::builder::TagListBuilder tl_builder(buffer);
@ -103,7 +103,7 @@ namespace osmium {
* @deprecated * @deprecated
* Use osmium::builder::add_tag_list() instead. * Use osmium::builder::add_tag_list() instead.
*/ */
inline const osmium::TagList& build_tag_list_from_func(osmium::memory::Buffer& buffer, std::function<void(osmium::builder::TagListBuilder&)> func) { OSMIUM_DEPRECATED inline const osmium::TagList& build_tag_list_from_func(osmium::memory::Buffer& buffer, std::function<void(osmium::builder::TagListBuilder&)> func) {
const size_t pos = buffer.committed(); const size_t pos = buffer.committed();
{ {
osmium::builder::TagListBuilder tl_builder(buffer); osmium::builder::TagListBuilder tl_builder(buffer);

View File

@ -33,7 +33,10 @@ DEALINGS IN THE SOFTWARE.
*/ */
#include <algorithm>
#include <cassert> #include <cassert>
#include <cstdint>
#include <cstddef>
#include <cstring> #include <cstring>
#include <initializer_list> #include <initializer_list>
#include <limits> #include <limits>
@ -43,25 +46,25 @@ DEALINGS IN THE SOFTWARE.
#include <utility> #include <utility>
#include <osmium/builder/builder.hpp> #include <osmium/builder/builder.hpp>
#include <osmium/memory/item.hpp>
#include <osmium/osm/area.hpp>
#include <osmium/osm/box.hpp>
#include <osmium/osm/changeset.hpp>
#include <osmium/osm/item_type.hpp> #include <osmium/osm/item_type.hpp>
#include <osmium/osm/location.hpp> #include <osmium/osm/location.hpp>
#include <osmium/osm/node.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/types.hpp>
#include <osmium/memory/item.hpp>
#include <osmium/osm/area.hpp>
#include <osmium/osm/changeset.hpp>
#include <osmium/osm/relation.hpp> #include <osmium/osm/relation.hpp>
#include <osmium/osm/tag.hpp>
#include <osmium/osm/timestamp.hpp> #include <osmium/osm/timestamp.hpp>
#include <osmium/osm/types.hpp>
#include <osmium/osm/way.hpp> #include <osmium/osm/way.hpp>
#include <osmium/util/cast.hpp>
#include <osmium/util/compatibility.hpp> #include <osmium/util/compatibility.hpp>
namespace osmium { namespace osmium {
class Node;
namespace memory { namespace memory {
class Buffer; class Buffer;
} // namespace memory } // namespace memory
@ -74,12 +77,12 @@ namespace osmium {
explicit TagListBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) : explicit TagListBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
Builder(buffer, parent, sizeof(TagList)) { Builder(buffer, parent, sizeof(TagList)) {
new (&item()) TagList(); new (&item()) TagList{};
} }
explicit TagListBuilder(Builder& parent) : explicit TagListBuilder(Builder& parent) :
Builder(parent.buffer(), &parent, sizeof(TagList)) { Builder(parent.buffer(), &parent, sizeof(TagList)) {
new (&item()) TagList(); new (&item()) TagList{};
} }
~TagListBuilder() { ~TagListBuilder() {
@ -94,10 +97,10 @@ namespace osmium {
*/ */
void add_tag(const char* key, const char* value) { void add_tag(const char* key, const char* value) {
if (std::strlen(key) > osmium::max_osm_string_length) { if (std::strlen(key) > osmium::max_osm_string_length) {
throw std::length_error("OSM tag key is too long"); throw std::length_error{"OSM tag key is too long"};
} }
if (std::strlen(value) > osmium::max_osm_string_length) { if (std::strlen(value) > osmium::max_osm_string_length) {
throw std::length_error("OSM tag value is too long"); throw std::length_error{"OSM tag value is too long"};
} }
add_size(append(key)); add_size(append(key));
add_size(append(value)); add_size(append(value));
@ -111,12 +114,12 @@ namespace osmium {
* @param value Pointer to tag value. * @param value Pointer to tag value.
* @param value_length Length of value (not including the \0 byte). * @param value_length Length of value (not including the \0 byte).
*/ */
void add_tag(const char* key, const size_t key_length, const char* value, const size_t value_length) { void add_tag(const char* key, const std::size_t key_length, const char* value, const std::size_t value_length) {
if (key_length > osmium::max_osm_string_length) { if (key_length > osmium::max_osm_string_length) {
throw std::length_error("OSM tag key is too long"); throw std::length_error{"OSM tag key is too long"};
} }
if (value_length > osmium::max_osm_string_length) { if (value_length > osmium::max_osm_string_length) {
throw std::length_error("OSM tag value is too long"); throw std::length_error{"OSM tag value is too long"};
} }
add_size(append_with_zero(key, osmium::memory::item_size_type(key_length))); add_size(append_with_zero(key, osmium::memory::item_size_type(key_length)));
add_size(append_with_zero(value, osmium::memory::item_size_type(value_length))); add_size(append_with_zero(value, osmium::memory::item_size_type(value_length)));
@ -130,10 +133,10 @@ namespace osmium {
*/ */
void add_tag(const std::string& key, const std::string& value) { void add_tag(const std::string& key, const std::string& value) {
if (key.size() > osmium::max_osm_string_length) { if (key.size() > osmium::max_osm_string_length) {
throw std::length_error("OSM tag key is too long"); throw std::length_error{"OSM tag key is too long"};
} }
if (value.size() > osmium::max_osm_string_length) { if (value.size() > osmium::max_osm_string_length) {
throw std::length_error("OSM tag value is too long"); throw std::length_error{"OSM tag value is too long"};
} }
add_size(append(key.data(), osmium::memory::item_size_type(key.size()) + 1)); add_size(append(key.data(), osmium::memory::item_size_type(key.size()) + 1));
add_size(append(value.data(), osmium::memory::item_size_type(value.size()) + 1)); add_size(append(value.data(), osmium::memory::item_size_type(value.size()) + 1));
@ -185,12 +188,12 @@ namespace osmium {
explicit NodeRefListBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) : explicit NodeRefListBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
Builder(buffer, parent, sizeof(T)) { Builder(buffer, parent, sizeof(T)) {
new (&item()) T(); new (&item()) T{};
} }
explicit NodeRefListBuilder(Builder& parent) : explicit NodeRefListBuilder(Builder& parent) :
Builder(parent.buffer(), &parent, sizeof(T)) { Builder(parent.buffer(), &parent, sizeof(T)) {
new (&item()) T(); new (&item()) T{};
} }
~NodeRefListBuilder() { ~NodeRefListBuilder() {
@ -198,12 +201,12 @@ namespace osmium {
} }
void add_node_ref(const NodeRef& node_ref) { void add_node_ref(const NodeRef& node_ref) {
new (reserve_space_for<osmium::NodeRef>()) osmium::NodeRef(node_ref); new (reserve_space_for<osmium::NodeRef>()) osmium::NodeRef{node_ref};
add_size(sizeof(osmium::NodeRef)); add_size(sizeof(osmium::NodeRef));
} }
void add_node_ref(const object_id_type ref, const osmium::Location& location = Location{}) { void add_node_ref(const object_id_type ref, const osmium::Location& location = Location{}) {
add_node_ref(NodeRef(ref, location)); add_node_ref(NodeRef{ref, location});
} }
}; // class NodeRefListBuilder }; // class NodeRefListBuilder
@ -223,9 +226,9 @@ namespace osmium {
* @param length Length of role (without \0 termination). * @param length Length of role (without \0 termination).
* @throws std:length_error If role is longer than osmium::max_osm_string_length * @throws std:length_error If role is longer than osmium::max_osm_string_length
*/ */
void add_role(osmium::RelationMember& member, const char* role, const size_t length) { void add_role(osmium::RelationMember& member, const char* role, const std::size_t length) {
if (length > osmium::max_osm_string_length) { if (length > osmium::max_osm_string_length) {
throw std::length_error("OSM relation member role is too long"); throw std::length_error{"OSM relation member role is too long"};
} }
member.set_role_size(osmium::string_size_type(length) + 1); member.set_role_size(osmium::string_size_type(length) + 1);
add_size(append_with_zero(role, osmium::memory::item_size_type(length))); add_size(append_with_zero(role, osmium::memory::item_size_type(length)));
@ -236,12 +239,12 @@ namespace osmium {
explicit RelationMemberListBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) : explicit RelationMemberListBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
Builder(buffer, parent, sizeof(RelationMemberList)) { Builder(buffer, parent, sizeof(RelationMemberList)) {
new (&item()) RelationMemberList(); new (&item()) RelationMemberList{};
} }
explicit RelationMemberListBuilder(Builder& parent) : explicit RelationMemberListBuilder(Builder& parent) :
Builder(parent.buffer(), &parent, sizeof(RelationMemberList)) { Builder(parent.buffer(), &parent, sizeof(RelationMemberList)) {
new (&item()) RelationMemberList(); new (&item()) RelationMemberList{};
} }
~RelationMemberListBuilder() { ~RelationMemberListBuilder() {
@ -261,9 +264,9 @@ namespace osmium {
* @throws std:length_error If role_length is greater than * @throws std:length_error If role_length is greater than
* osmium::max_osm_string_length * osmium::max_osm_string_length
*/ */
void add_member(osmium::item_type type, object_id_type ref, const char* role, const size_t role_length, const osmium::OSMObject* full_member = nullptr) { void add_member(osmium::item_type type, object_id_type ref, const char* role, const std::size_t role_length, const osmium::OSMObject* full_member = nullptr) {
osmium::RelationMember* member = reserve_space_for<osmium::RelationMember>(); osmium::RelationMember* member = reserve_space_for<osmium::RelationMember>();
new (member) osmium::RelationMember(ref, type, full_member != nullptr); new (member) osmium::RelationMember{ref, type, full_member != nullptr};
add_size(sizeof(RelationMember)); add_size(sizeof(RelationMember));
add_role(*member, role, role_length); add_role(*member, role, role_length);
if (full_member) { if (full_member) {
@ -307,23 +310,19 @@ namespace osmium {
osmium::ChangesetComment* m_comment = nullptr; osmium::ChangesetComment* m_comment = nullptr;
void add_user(osmium::ChangesetComment& comment, const char* user, const size_t length) { void add_user(osmium::ChangesetComment& comment, const char* user, const std::size_t length) {
if (length > osmium::max_osm_string_length) { if (length > osmium::max_osm_string_length) {
throw std::length_error("OSM user name is too long"); throw std::length_error{"OSM user name is too long"};
} }
comment.set_user_size(osmium::string_size_type(length) + 1); comment.set_user_size(osmium::string_size_type(length) + 1);
add_size(append_with_zero(user, osmium::memory::item_size_type(length))); add_size(append_with_zero(user, osmium::memory::item_size_type(length)));
} }
void add_text(osmium::ChangesetComment& comment, const char* text, const size_t length) { void add_text(osmium::ChangesetComment& comment, const char* text, const std::size_t length) {
// XXX There is no limit on the length of a comment text. We if (length > std::numeric_limits<osmium::changeset_comment_size_type>::max() - 1) {
// limit it here to 2^16-2 characters, because that's all that throw std::length_error{"OSM changeset comment is too long"};
// will fit into our internal data structure. This is not ideal,
// and will have to be discussed and cleared up.
if (length > std::numeric_limits<osmium::string_size_type>::max() - 1) {
throw std::length_error("OSM changeset comment is too long");
} }
comment.set_text_size(osmium::string_size_type(length) + 1); comment.set_text_size(osmium::changeset_comment_size_type(length) + 1);
add_size(append_with_zero(text, osmium::memory::item_size_type(length))); add_size(append_with_zero(text, osmium::memory::item_size_type(length)));
add_padding(true); add_padding(true);
} }
@ -332,12 +331,12 @@ namespace osmium {
explicit ChangesetDiscussionBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) : explicit ChangesetDiscussionBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
Builder(buffer, parent, sizeof(ChangesetDiscussion)) { Builder(buffer, parent, sizeof(ChangesetDiscussion)) {
new (&item()) ChangesetDiscussion(); new (&item()) ChangesetDiscussion{};
} }
explicit ChangesetDiscussionBuilder(Builder& parent) : explicit ChangesetDiscussionBuilder(Builder& parent) :
Builder(parent.buffer(), &parent, sizeof(ChangesetDiscussion)) { Builder(parent.buffer(), &parent, sizeof(ChangesetDiscussion)) {
new (&item()) ChangesetDiscussion(); new (&item()) ChangesetDiscussion{};
} }
~ChangesetDiscussionBuilder() { ~ChangesetDiscussionBuilder() {
@ -348,21 +347,23 @@ namespace osmium {
void add_comment(osmium::Timestamp date, osmium::user_id_type uid, const char* user) { void add_comment(osmium::Timestamp date, osmium::user_id_type uid, const char* user) {
assert(!m_comment && "You have to always call both add_comment() and then add_comment_text() in that order for each comment!"); assert(!m_comment && "You have to always call both add_comment() and then add_comment_text() in that order for each comment!");
m_comment = reserve_space_for<osmium::ChangesetComment>(); m_comment = reserve_space_for<osmium::ChangesetComment>();
new (m_comment) osmium::ChangesetComment(date, uid); new (m_comment) osmium::ChangesetComment{date, uid};
add_size(sizeof(ChangesetComment)); add_size(sizeof(ChangesetComment));
add_user(*m_comment, user, std::strlen(user)); add_user(*m_comment, user, std::strlen(user));
} }
void add_comment_text(const char* text) { void add_comment_text(const char* text) {
assert(m_comment && "You have to always call both add_comment() and then add_comment_text() in that order for each comment!"); assert(m_comment && "You have to always call both add_comment() and then add_comment_text() in that order for each comment!");
add_text(*m_comment, text, std::strlen(text)); osmium::ChangesetComment& comment = *m_comment;
m_comment = nullptr; m_comment = nullptr;
add_text(comment, text, std::strlen(text));
} }
void add_comment_text(const std::string& text) { void add_comment_text(const std::string& text) {
assert(m_comment && "You have to always call both add_comment() and then add_comment_text() in that order for each comment!"); assert(m_comment && "You have to always call both add_comment() and then add_comment_text() in that order for each comment!");
add_text(*m_comment, text.c_str(), text.size()); osmium::ChangesetComment& comment = *m_comment;
m_comment = nullptr; m_comment = nullptr;
add_text(comment, text.c_str(), text.size());
} }
}; // class ChangesetDiscussionBuilder }; // class ChangesetDiscussionBuilder
@ -379,13 +380,13 @@ namespace osmium {
using type = TDerived; using type = TDerived;
constexpr static const size_t min_size_for_user = osmium::memory::padded_length(sizeof(string_size_type) + 1); constexpr static const std::size_t min_size_for_user = osmium::memory::padded_length(sizeof(string_size_type) + 1);
public: public:
explicit OSMObjectBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) : explicit OSMObjectBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
Builder(buffer, parent, sizeof(T) + min_size_for_user) { Builder(buffer, parent, sizeof(T) + min_size_for_user) {
new (&item()) T(); new (&item()) T{};
add_size(min_size_for_user); add_size(min_size_for_user);
std::fill_n(object().data() + sizeof(T), min_size_for_user, 0); std::fill_n(object().data() + sizeof(T), min_size_for_user, 0);
object().set_user_size(1); object().set_user_size(1);
@ -402,6 +403,17 @@ namespace osmium {
return static_cast<T&>(item()); return static_cast<T&>(item());
} }
/**
* Get a const reference to the object buing built.
*
* Note that this reference will be invalidated by every action
* on the builder that might make the buffer grow. This includes
* calls to set_user() and any time a new sub-builder is created.
*/
const T& cobject() const noexcept {
return static_cast<const T&>(item());
}
/** /**
* Set user name. * Set user name.
* *
@ -410,7 +422,7 @@ namespace osmium {
*/ */
TDerived& set_user(const char* user, const string_size_type length) { TDerived& set_user(const char* user, const string_size_type length) {
const auto size_of_object = sizeof(T) + sizeof(string_size_type); const auto size_of_object = sizeof(T) + sizeof(string_size_type);
assert(object().user_size() == 1 && (size() <= size_of_object + osmium::memory::padded_length(1)) assert(cobject().user_size() == 1 && (size() <= size_of_object + osmium::memory::padded_length(1))
&& "set_user() must be called at most once and before any sub-builders"); && "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; const auto available_space = min_size_for_user - sizeof(string_size_type) - 1;
if (length > available_space) { if (length > available_space) {
@ -558,13 +570,13 @@ namespace osmium {
using type = ChangesetBuilder; using type = ChangesetBuilder;
constexpr static const size_t min_size_for_user = osmium::memory::padded_length(1); constexpr static const std::size_t min_size_for_user = osmium::memory::padded_length(1);
public: public:
explicit ChangesetBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) : explicit ChangesetBuilder(osmium::memory::Buffer& buffer, Builder* parent = nullptr) :
Builder(buffer, parent, sizeof(Changeset) + min_size_for_user) { Builder(buffer, parent, sizeof(Changeset) + min_size_for_user) {
new (&item()) Changeset(); new (&item()) Changeset{};
add_size(min_size_for_user); add_size(min_size_for_user);
std::fill_n(object().data() + sizeof(Changeset), min_size_for_user, 0); std::fill_n(object().data() + sizeof(Changeset), min_size_for_user, 0);
object().set_user_size(1); object().set_user_size(1);
@ -581,6 +593,17 @@ namespace osmium {
return static_cast<Changeset&>(item()); return static_cast<Changeset&>(item());
} }
/**
* Get a const reference to the changeset buing built.
*
* Note that this reference will be invalidated by every action
* on the builder that might make the buffer grow. This includes
* calls to set_user() and any time a new sub-builder is created.
*/
const Changeset& cobject() const noexcept {
return static_cast<const Changeset&>(item());
}
OSMIUM_FORWARD(set_id) OSMIUM_FORWARD(set_id)
OSMIUM_FORWARD(set_uid) OSMIUM_FORWARD(set_uid)
OSMIUM_FORWARD(set_uid_from_signed) OSMIUM_FORWARD(set_uid_from_signed)
@ -608,7 +631,7 @@ namespace osmium {
* @param length Length of user name (without \0 termination). * @param length Length of user name (without \0 termination).
*/ */
ChangesetBuilder& set_user(const char* user, const string_size_type length) { ChangesetBuilder& set_user(const char* user, const string_size_type length) {
assert(object().user_size() == 1 && (size() <= sizeof(Changeset) + osmium::memory::padded_length(1)) assert(cobject().user_size() == 1 && (size() <= sizeof(Changeset) + osmium::memory::padded_length(1))
&& "set_user() must be called at most once and before any sub-builders"); && "set_user() must be called at most once and before any sub-builders");
const auto available_space = min_size_for_user - 1; const auto available_space = min_size_for_user - 1;
if (length > available_space) { if (length > available_space) {

View File

@ -48,13 +48,13 @@ namespace osmium {
DiffHandler() = default; DiffHandler() = default;
void node(const osmium::DiffNode&) const { void node(const osmium::DiffNode&) const noexcept {
} }
void way(const osmium::DiffWay&) const { void way(const osmium::DiffWay&) const noexcept {
} }
void relation(const osmium::DiffRelation&) const { void relation(const osmium::DiffRelation&) const noexcept {
} }
}; // class DiffHandler }; // class DiffHandler

View File

@ -66,8 +66,8 @@ namespace osmium {
void set_diff() const noexcept { void set_diff() const noexcept {
assert(m_curr != m_end); assert(m_curr != m_end);
bool use_curr_for_prev = m_prev->type() != m_curr->type() || m_prev->id() != m_curr->id(); const bool use_curr_for_prev = m_prev->type() != m_curr->type() || m_prev->id() != m_curr->id();
bool use_curr_for_next = m_next == m_end || m_next->type() != m_curr->type() || m_next->id() != m_curr->id(); const bool use_curr_for_next = m_next == m_end || m_next->type() != m_curr->type() || m_next->id() != m_curr->id();
m_diff = std::move(osmium::DiffObject{ m_diff = std::move(osmium::DiffObject{
*(use_curr_for_prev ? m_curr : m_prev), *(use_curr_for_prev ? m_curr : m_prev),
@ -104,7 +104,7 @@ namespace osmium {
} }
DiffIterator operator++(int) { DiffIterator operator++(int) {
DiffIterator tmp(*this); DiffIterator tmp{*this};
operator++(); operator++();
return tmp; return tmp;
} }

View File

@ -56,7 +56,7 @@ namespace osmium {
handler.relation(static_cast<const osmium::DiffRelation&>(diff)); handler.relation(static_cast<const osmium::DiffRelation&>(diff));
break; break;
default: default:
throw osmium::unknown_type(); throw osmium::unknown_type{};
} }
} }
@ -72,8 +72,8 @@ namespace osmium {
inline void apply_diff(TIterator it, TIterator end, THandlers&... handlers) { inline void apply_diff(TIterator it, TIterator end, THandlers&... handlers) {
using diff_iterator = osmium::DiffIterator<TIterator>; using diff_iterator = osmium::DiffIterator<TIterator>;
diff_iterator dit(it, end); diff_iterator dit{it, end};
diff_iterator dend(end, end); diff_iterator dend{end, end};
for (; dit != dend; ++dit) { for (; dit != dend; ++dit) {
detail::apply_diff_iterator_recurse(*dit, handlers...); detail::apply_diff_iterator_recurse(*dit, handlers...);

View File

@ -54,8 +54,7 @@ namespace osmium {
public: public:
virtual ~HandlerWrapperBase() { virtual ~HandlerWrapperBase() = default;
}
virtual void node(const osmium::Node&) { virtual void node(const osmium::Node&) {
} }
@ -115,7 +114,7 @@ auto _name_##_dispatch(THandler& handler, const osmium::_type_& object, long) ->
public: public:
template <typename... TArgs> template <typename... TArgs>
HandlerWrapper(TArgs&&... args) : explicit HandlerWrapper(TArgs&&... args) :
m_handler(std::forward<TArgs>(args)...) { m_handler(std::forward<TArgs>(args)...) {
} }
@ -155,12 +154,12 @@ auto _name_##_dispatch(THandler& handler, const osmium::_type_& object, long) ->
public: public:
DynamicHandler() : DynamicHandler() :
m_impl(impl_ptr(new osmium::handler::detail::HandlerWrapperBase)) { m_impl(new osmium::handler::detail::HandlerWrapperBase) {
} }
template <typename THandler, typename... TArgs> template <typename THandler, typename... TArgs>
void set(TArgs&&... args) { void set(TArgs&&... args) {
m_impl = impl_ptr(new osmium::handler::detail::HandlerWrapper<THandler>(std::forward<TArgs>(args)...)); m_impl.reset(new osmium::handler::detail::HandlerWrapper<THandler>{std::forward<TArgs>(args)...});
} }
void node(const osmium::Node& node) { void node(const osmium::Node& node) {

View File

@ -78,7 +78,7 @@ namespace osmium {
{ {
m_location_handler.ignore_errors(); m_location_handler.ignore_errors();
if (m_with_areas) { if (m_with_areas) {
osmium::io::Reader reader(file, osmium::osm_entity_bits::relation); osmium::io::Reader reader{file, osmium::osm_entity_bits::relation};
m_collector.read_relations(reader); m_collector.read_relations(reader);
reader.close(); reader.close();
} }

View File

@ -165,6 +165,11 @@ namespace osmium {
public: public:
GeometryFactory<TGeomImpl, TProjection>() :
m_projection(),
m_impl(m_projection.epsg()) {
}
/** /**
* Constructor for default initialized projection. * Constructor for default initialized projection.
*/ */
@ -192,7 +197,7 @@ namespace osmium {
using multipolygon_type = typename TGeomImpl::multipolygon_type; using multipolygon_type = typename TGeomImpl::multipolygon_type;
using ring_type = typename TGeomImpl::ring_type; using ring_type = typename TGeomImpl::ring_type;
int epsg() const { int epsg() const noexcept {
return m_projection.epsg(); return m_projection.epsg();
} }
@ -380,9 +385,9 @@ namespace osmium {
size_t num_rings = 0; size_t num_rings = 0;
m_impl.multipolygon_start(); m_impl.multipolygon_start();
for (auto it = area.cbegin(); it != area.cend(); ++it) { for (const auto& item : area) {
if (it->type() == osmium::item_type::outer_ring) { if (item.type() == osmium::item_type::outer_ring) {
auto& ring = static_cast<const osmium::OuterRing&>(*it); auto& ring = static_cast<const osmium::OuterRing&>(item);
if (num_polygons > 0) { if (num_polygons > 0) {
m_impl.multipolygon_polygon_finish(); m_impl.multipolygon_polygon_finish();
} }
@ -392,8 +397,8 @@ namespace osmium {
m_impl.multipolygon_outer_ring_finish(); m_impl.multipolygon_outer_ring_finish();
++num_rings; ++num_rings;
++num_polygons; ++num_polygons;
} else if (it->type() == osmium::item_type::inner_ring) { } else if (item.type() == osmium::item_type::inner_ring) {
auto& ring = static_cast<const osmium::InnerRing&>(*it); auto& ring = static_cast<const osmium::InnerRing&>(item);
m_impl.multipolygon_inner_ring_start(); m_impl.multipolygon_inner_ring_start();
add_points(ring); add_points(ring);
m_impl.multipolygon_inner_ring_finish(); m_impl.multipolygon_inner_ring_finish();

View File

@ -129,13 +129,13 @@ namespace osmium {
*/ */
OSMIUM_DEPRECATED explicit GEOSFactoryImpl(int /* srid */, int srid) : OSMIUM_DEPRECATED explicit GEOSFactoryImpl(int /* srid */, int srid) :
m_precision_model(new geos::geom::PrecisionModel), m_precision_model(new geos::geom::PrecisionModel),
m_our_geos_factory(new geos::geom::GeometryFactory(m_precision_model.get(), srid)), m_our_geos_factory(new geos::geom::GeometryFactory{m_precision_model.get(), srid}),
m_geos_factory(m_our_geos_factory.get()) { m_geos_factory(m_our_geos_factory.get()) {
} }
explicit GEOSFactoryImpl(int srid) : explicit GEOSFactoryImpl(int srid) :
m_precision_model(new geos::geom::PrecisionModel), m_precision_model(new geos::geom::PrecisionModel),
m_our_geos_factory(new geos::geom::GeometryFactory(m_precision_model.get(), srid)), m_our_geos_factory(new geos::geom::GeometryFactory{m_precision_model.get(), srid}),
m_geos_factory(m_our_geos_factory.get()) { m_geos_factory(m_our_geos_factory.get()) {
} }
@ -143,7 +143,7 @@ namespace osmium {
point_type make_point(const osmium::geom::Coordinates& xy) const { point_type make_point(const osmium::geom::Coordinates& xy) const {
try { try {
return point_type(m_geos_factory->createPoint(geos::geom::Coordinate(xy.x, xy.y))); return point_type{m_geos_factory->createPoint(geos::geom::Coordinate{xy.x, xy.y})};
} catch (const geos::util::GEOSException& e) { } catch (const geos::util::GEOSException& e) {
THROW(osmium::geos_geometry_error(e.what())); THROW(osmium::geos_geometry_error(e.what()));
} }
@ -153,7 +153,7 @@ namespace osmium {
void linestring_start() { void linestring_start() {
try { try {
m_coordinate_sequence.reset(m_geos_factory->getCoordinateSequenceFactory()->create(static_cast<size_t>(0), 2)); m_coordinate_sequence.reset(m_geos_factory->getCoordinateSequenceFactory()->create(static_cast<std::size_t>(0), 2));
} catch (const geos::util::GEOSException& e) { } catch (const geos::util::GEOSException& e) {
THROW(osmium::geos_geometry_error(e.what())); THROW(osmium::geos_geometry_error(e.what()));
} }
@ -161,15 +161,15 @@ namespace osmium {
void linestring_add_location(const osmium::geom::Coordinates& xy) { void linestring_add_location(const osmium::geom::Coordinates& xy) {
try { try {
m_coordinate_sequence->add(geos::geom::Coordinate(xy.x, xy.y)); m_coordinate_sequence->add(geos::geom::Coordinate{xy.x, xy.y});
} catch (const geos::util::GEOSException& e) { } catch (const geos::util::GEOSException& e) {
THROW(osmium::geos_geometry_error(e.what())); THROW(osmium::geos_geometry_error(e.what()));
} }
} }
linestring_type linestring_finish(size_t /* num_points */) { linestring_type linestring_finish(std::size_t /* num_points */) {
try { try {
return linestring_type(m_geos_factory->createLineString(m_coordinate_sequence.release())); return linestring_type{m_geos_factory->createLineString(m_coordinate_sequence.release())};
} catch (const geos::util::GEOSException& e) { } catch (const geos::util::GEOSException& e) {
THROW(osmium::geos_geometry_error(e.what())); THROW(osmium::geos_geometry_error(e.what()));
} }
@ -201,7 +201,7 @@ namespace osmium {
void multipolygon_outer_ring_start() { void multipolygon_outer_ring_start() {
try { try {
m_coordinate_sequence.reset(m_geos_factory->getCoordinateSequenceFactory()->create(static_cast<size_t>(0), 2)); m_coordinate_sequence.reset(m_geos_factory->getCoordinateSequenceFactory()->create(static_cast<std::size_t>(0), 2));
} catch (const geos::util::GEOSException& e) { } catch (const geos::util::GEOSException& e) {
THROW(osmium::geos_geometry_error(e.what())); THROW(osmium::geos_geometry_error(e.what()));
} }
@ -217,7 +217,7 @@ namespace osmium {
void multipolygon_inner_ring_start() { void multipolygon_inner_ring_start() {
try { try {
m_coordinate_sequence.reset(m_geos_factory->getCoordinateSequenceFactory()->create(static_cast<size_t>(0), 2)); m_coordinate_sequence.reset(m_geos_factory->getCoordinateSequenceFactory()->create(static_cast<std::size_t>(0), 2));
} catch (const geos::util::GEOSException& e) { } catch (const geos::util::GEOSException& e) {
THROW(osmium::geos_geometry_error(e.what())); THROW(osmium::geos_geometry_error(e.what()));
} }
@ -233,7 +233,7 @@ namespace osmium {
void multipolygon_add_location(const osmium::geom::Coordinates& xy) { void multipolygon_add_location(const osmium::geom::Coordinates& xy) {
try { try {
m_coordinate_sequence->add(geos::geom::Coordinate(xy.x, xy.y)); m_coordinate_sequence->add(geos::geom::Coordinate{xy.x, xy.y});
} catch (const geos::util::GEOSException& e) { } catch (const geos::util::GEOSException& e) {
THROW(osmium::geos_geometry_error(e.what())); THROW(osmium::geos_geometry_error(e.what()));
} }
@ -246,7 +246,7 @@ namespace osmium {
return p.release(); return p.release();
}); });
m_polygons.clear(); m_polygons.clear();
return multipolygon_type(m_geos_factory->createMultiPolygon(polygons)); return multipolygon_type{m_geos_factory->createMultiPolygon(polygons)};
} catch (const geos::util::GEOSException& e) { } catch (const geos::util::GEOSException& e) {
THROW(osmium::geos_geometry_error(e.what())); THROW(osmium::geos_geometry_error(e.what()));
} }

View File

@ -118,7 +118,7 @@ namespace osmium {
* @pre @code c.valid() @endcode * @pre @code c.valid() @endcode
*/ */
inline Coordinates lonlat_to_mercator(const Coordinates& c) { inline Coordinates lonlat_to_mercator(const Coordinates& c) {
return Coordinates(detail::lon_to_x(c.x), detail::lat_to_y(c.y)); return Coordinates{detail::lon_to_x(c.x), detail::lat_to_y(c.y)};
} }
/** /**
@ -127,7 +127,7 @@ namespace osmium {
* @pre @code c.valid() @endcode * @pre @code c.valid() @endcode
*/ */
inline Coordinates mercator_to_lonlat(const Coordinates& c) { inline Coordinates mercator_to_lonlat(const Coordinates& c) {
return Coordinates(detail::x_to_lon(c.x), detail::y_to_lat(c.y)); return Coordinates{detail::x_to_lon(c.x), detail::y_to_lat(c.y)};
} }
/** /**
@ -138,8 +138,11 @@ namespace osmium {
public: public:
MercatorProjection() {
}
Coordinates operator()(osmium::Location location) const { Coordinates operator()(osmium::Location location) const {
return Coordinates {detail::lon_to_x(location.lon()), detail::lat_to_y(location.lat())}; return Coordinates{detail::lon_to_x(location.lon()), detail::lat_to_y(location.lat())};
} }
int epsg() const noexcept { int epsg() const noexcept {

View File

@ -48,6 +48,7 @@ DEALINGS IN THE SOFTWARE.
#include <proj_api.h> #include <proj_api.h>
#include <osmium/geom/coordinates.hpp> #include <osmium/geom/coordinates.hpp>
#include <osmium/geom/mercator_projection.hpp>
#include <osmium/geom/util.hpp> #include <osmium/geom/util.hpp>
#include <osmium/osm/location.hpp> #include <osmium/osm/location.hpp>
@ -70,15 +71,15 @@ namespace osmium {
public: public:
explicit CRS(const std::string& crs) : explicit CRS(const char* crs) :
m_crs(pj_init_plus(crs.c_str()), ProjCRSDeleter()) { m_crs(pj_init_plus(crs), ProjCRSDeleter()) {
if (!m_crs) { if (!m_crs) {
throw osmium::projection_error(std::string{"creation of CRS failed: "} + pj_strerrno(*pj_get_errno_ref())); throw osmium::projection_error{std::string{"creation of CRS failed: "} + pj_strerrno(*pj_get_errno_ref())};
} }
} }
explicit CRS(const char* crs) : explicit CRS(const std::string& crs) :
CRS(std::string{crs}) { CRS(crs.c_str()) {
} }
explicit CRS(int epsg) : explicit CRS(int epsg) :
@ -88,15 +89,15 @@ namespace osmium {
/** /**
* Get underlying projPJ handle from proj library. * Get underlying projPJ handle from proj library.
*/ */
projPJ get() const { projPJ get() const noexcept {
return m_crs.get(); return m_crs.get();
} }
bool is_latlong() const { bool is_latlong() const noexcept {
return pj_is_latlong(m_crs.get()) != 0; return pj_is_latlong(m_crs.get()) != 0;
} }
bool is_geocent() const { bool is_geocent() const noexcept {
return pj_is_geocent(m_crs.get()) != 0; return pj_is_geocent(m_crs.get()) != 0;
} }
@ -108,12 +109,13 @@ namespace osmium {
* *
* Coordinates have to be in radians and are produced in radians. * Coordinates have to be in radians and are produced in radians.
* *
* @throws osmmium::projection_error if the projection fails * @throws osmium::projection_error if the projection fails
*/ */
// cppcheck-suppress passedByValue (because c is small and we want to change it)
inline Coordinates transform(const CRS& src, const CRS& dest, Coordinates c) { inline Coordinates transform(const CRS& src, const CRS& dest, Coordinates c) {
int result = pj_transform(src.get(), dest.get(), 1, 1, &c.x, &c.y, nullptr); const int result = pj_transform(src.get(), dest.get(), 1, 1, &c.x, &c.y, nullptr);
if (result != 0) { if (result != 0) {
throw osmium::projection_error(std::string("projection failed: ") + pj_strerrno(result)); throw osmium::projection_error{std::string{"projection failed: "} + pj_strerrno(result)};
} }
return c; return c;
} }
@ -121,12 +123,19 @@ namespace osmium {
/** /**
* Functor that does projection from WGS84 (EPSG:4326) to the given * Functor that does projection from WGS84 (EPSG:4326) to the given
* CRS. * CRS.
*
* If this Projection is initialized with the constructor taking
* an integer with the epsg code 4326, no projection is done. If it
* is initialized with epsg code 3857 the Osmium-internal
* implementation of the Mercator projection is used, otherwise this
* falls back to using the proj.4 library. Note that this "magic" does
* not work if you use any of the constructors taking a string.
*/ */
class Projection { class Projection {
int m_epsg; int m_epsg;
std::string m_proj_string; std::string m_proj_string;
CRS m_crs_wgs84 {4326}; CRS m_crs_wgs84{4326};
CRS m_crs_user; CRS m_crs_user;
public: public:
@ -145,20 +154,24 @@ namespace osmium {
explicit Projection(int epsg) : explicit Projection(int epsg) :
m_epsg(epsg), m_epsg(epsg),
m_proj_string(std::string("+init=epsg:") + std::to_string(epsg)), m_proj_string(std::string{"+init=epsg:"} + std::to_string(epsg)),
m_crs_user(epsg) { m_crs_user(epsg) {
} }
Coordinates operator()(osmium::Location location) const { Coordinates operator()(osmium::Location location) const {
Coordinates c {location.lon(), location.lat()}; if (m_epsg == 4326) {
return Coordinates{location.lon(), location.lat()};
} else if (m_epsg == 3857) {
return Coordinates{detail::lon_to_x(location.lon()),
detail::lat_to_y(location.lat())};
}
if (m_epsg != 4326) { Coordinates c{transform(m_crs_wgs84, m_crs_user, Coordinates{deg_to_rad(location.lon()),
c = transform(m_crs_wgs84, m_crs_user, Coordinates(deg_to_rad(location.lon()), deg_to_rad(location.lat()))); deg_to_rad(location.lat())})};
if (m_crs_user.is_latlong()) { if (m_crs_user.is_latlong()) {
c.x = rad_to_deg(c.x); c.x = rad_to_deg(c.x);
c.y = rad_to_deg(c.y); c.y = rad_to_deg(c.y);
} }
}
return c; return c;
} }

View File

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

View File

@ -62,7 +62,7 @@ namespace osmium {
} }
/** /**
* Returns the width or hight of a tile in web mercator coordinates for * Returns the width or height of a tile in web mercator coordinates for
* the given zoom level. * the given zoom level.
*/ */
inline constexpr double tile_extent_in_zoom(uint32_t zoom) noexcept { inline constexpr double tile_extent_in_zoom(uint32_t zoom) noexcept {
@ -108,7 +108,7 @@ namespace osmium {
uint32_t z; uint32_t z;
/** /**
* Create a tile with the given zoom level and x any y tile * Create a tile with the given zoom level and x and y tile
* coordinates. * coordinates.
* *
* The values are not checked for validity. * The values are not checked for validity.
@ -172,22 +172,30 @@ 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& lhs, const Tile& rhs) { inline bool operator==(const Tile& lhs, const Tile& rhs) noexcept {
return lhs.z == rhs.z && lhs.x == rhs.x && lhs.y == rhs.y; return lhs.z == rhs.z && lhs.x == rhs.x && lhs.y == rhs.y;
} }
inline bool operator!=(const Tile& lhs, const Tile& rhs) { inline bool operator!=(const Tile& lhs, const Tile& rhs) noexcept {
return ! (lhs == rhs); 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& lhs, const Tile& rhs) { inline bool operator<(const Tile& lhs, const Tile& rhs) noexcept {
if (lhs.z < rhs.z) return true; if (lhs.z < rhs.z) {
if (lhs.z > rhs.z) return false; return true;
if (lhs.x < rhs.x) return true; }
if (lhs.x > rhs.x) return false; if (lhs.z > rhs.z) {
return false;
}
if (lhs.x < rhs.x) {
return true;
}
if (lhs.x > rhs.x) {
return false;
}
return lhs.y < rhs.y; return lhs.y < rhs.y;
} }

View File

@ -108,19 +108,19 @@ namespace osmium {
}; // enum class wkb_byte_order_type }; // enum class wkb_byte_order_type
std::string m_data; std::string m_data;
uint32_t m_points {0}; uint32_t m_points = 0;
int m_srid; int m_srid;
wkb_type m_wkb_type; wkb_type m_wkb_type;
out_type m_out_type; out_type m_out_type;
size_t m_linestring_size_offset = 0; std::size_t m_linestring_size_offset = 0;
size_t m_polygons = 0; std::size_t m_polygons = 0;
size_t m_rings = 0; std::size_t m_rings = 0;
size_t m_multipolygon_size_offset = 0; std::size_t m_multipolygon_size_offset = 0;
size_t m_polygon_size_offset = 0; std::size_t m_polygon_size_offset = 0;
size_t m_ring_size_offset = 0; std::size_t m_ring_size_offset = 0;
size_t header(std::string& str, wkbGeometryType type, bool add_length) const { std::size_t header(std::string& str, wkbGeometryType type, bool add_length) const {
#if __BYTE_ORDER == __LITTLE_ENDIAN #if __BYTE_ORDER == __LITTLE_ENDIAN
str_push(str, wkb_byte_order_type::NDR); str_push(str, wkb_byte_order_type::NDR);
#else #else
@ -132,14 +132,14 @@ namespace osmium {
} else { } else {
str_push(str, type); str_push(str, type);
} }
const size_t offset = str.size(); const std::size_t offset = str.size();
if (add_length) { if (add_length) {
str_push(str, static_cast<uint32_t>(0)); str_push(str, static_cast<uint32_t>(0));
} }
return offset; return offset;
} }
void set_size(const size_t offset, const size_t size) { void set_size(const std::size_t offset, const std::size_t size) {
uint32_t s = static_cast_with_assert<uint32_t>(size); uint32_t s = static_cast_with_assert<uint32_t>(size);
std::copy_n(reinterpret_cast<char*>(&s), sizeof(uint32_t), &m_data[offset]); std::copy_n(reinterpret_cast<char*>(&s), sizeof(uint32_t), &m_data[offset]);
} }
@ -185,7 +185,7 @@ namespace osmium {
str_push(m_data, xy.y); str_push(m_data, xy.y);
} }
linestring_type linestring_finish(size_t num_points) { linestring_type linestring_finish(std::size_t num_points) {
set_size(m_linestring_size_offset, num_points); set_size(m_linestring_size_offset, num_points);
std::string data; std::string data;

View File

@ -39,6 +39,7 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/handler.hpp> #include <osmium/handler.hpp>
#include <osmium/osm/node.hpp> #include <osmium/osm/node.hpp>
#include <osmium/osm/object_comparisons.hpp>
#include <osmium/osm/relation.hpp> #include <osmium/osm/relation.hpp>
#include <osmium/osm/types.hpp> #include <osmium/osm/types.hpp>
#include <osmium/osm/way.hpp> #include <osmium/osm/way.hpp>
@ -51,12 +52,16 @@ namespace osmium {
*/ */
struct out_of_order_error : public std::runtime_error { struct out_of_order_error : public std::runtime_error {
explicit out_of_order_error(const std::string& what) : osmium::object_id_type object_id;
std::runtime_error(what) {
explicit out_of_order_error(const std::string& what, osmium::object_id_type id) :
std::runtime_error(what),
object_id(id) {
} }
explicit out_of_order_error(const char* what) : explicit out_of_order_error(const char* what, osmium::object_id_type id) :
std::runtime_error(what) { std::runtime_error(what),
object_id(id) {
} }
}; // struct out_of_order_error }; // struct out_of_order_error
@ -67,12 +72,14 @@ namespace osmium {
* Handler that can be used to check that an OSM file is ordered * Handler that can be used to check that an OSM file is ordered
* correctly. Ordered in this case refers to the usual order in OSM * correctly. Ordered in this case refers to the usual order in OSM
* files: First nodes in the order of their IDs, then ways in the order * files: First nodes in the order of their IDs, then ways in the order
* of their IDs, then relations in the order or their IDs. * of their IDs, then relations in the order or their IDs. Negative
* IDs are ordered first then positive IDs, both ordered by absolute
* value.
* *
* IDs have to be unique for each type. This check will fail for * IDs have to be unique for each type. This check will fail for
* history files. * history files.
* *
* To use this add a CheckOrder member variable to your handler and * To use this, add a CheckOrder member variable to your handler and
* call the node(), way(), and relation() methods from your node(), * call the node(), way(), and relation() methods from your node(),
* way(), and relations() handlers, respectively. An out_of_order_error * way(), and relations() handlers, respectively. An out_of_order_error
* exception will be thrown when the input is not in order. * exception will be thrown when the input is not in order.
@ -86,33 +93,42 @@ namespace osmium {
public: public:
void node(const osmium::Node& node) { void node(const osmium::Node& node) {
if (m_max_way_id > 0) { if (m_max_way_id > std::numeric_limits<osmium::object_id_type>::min()) {
throw out_of_order_error("Found a node after a way."); throw out_of_order_error{"Found a node after a way.", node.id()};
} }
if (m_max_relation_id > 0) { if (m_max_relation_id > std::numeric_limits<osmium::object_id_type>::min()) {
throw out_of_order_error("Found a node after a relation."); throw out_of_order_error{"Found a node after a relation.", node.id()};
} }
if (m_max_node_id >= node.id()) { if (m_max_node_id == node.id()) {
throw out_of_order_error("Node IDs out of order."); throw out_of_order_error{"Node ID twice in input. Maybe you are using a history or change file?", node.id()};
}
if (id_order{}(node.id(), m_max_node_id)) {
throw out_of_order_error{"Node IDs out of order.", node.id()};
} }
m_max_node_id = node.id(); m_max_node_id = node.id();
} }
void way(const osmium::Way& way) { void way(const osmium::Way& way) {
if (m_max_relation_id > 0) { if (m_max_relation_id > std::numeric_limits<osmium::object_id_type>::min()) {
throw out_of_order_error("Found a way after a relation."); throw out_of_order_error{"Found a way after a relation.", way.id()};
} }
if (m_max_way_id >= way.id()) { if (m_max_way_id == way.id()) {
throw out_of_order_error("Way IDs out of order."); throw out_of_order_error{"Way ID twice in input. Maybe you are using a history or change file?", way.id()};
}
if (id_order{}(way.id(), m_max_way_id)) {
throw out_of_order_error{"Way IDs out of order.", way.id()};
} }
m_max_way_id = way.id(); m_max_way_id = way.id();
} }
void relation(const osmium::Relation& relation) { void relation(const osmium::Relation& relation) {
if (m_max_relation_id >= relation.id()) { if (m_max_relation_id == relation.id()) {
throw out_of_order_error("Relation IDs out of order."); throw out_of_order_error{"Relation ID twice in input. Maybe you are using a history or change file?", relation.id()};
}
if (id_order{}(relation.id(), m_max_relation_id)) {
throw out_of_order_error{"Relation IDs out of order.", relation.id()};
} }
m_max_relation_id = relation.id(); m_max_relation_id = relation.id();
} }

View File

@ -60,9 +60,9 @@ namespace osmium {
*/ */
class DiskStore : public osmium::handler::Handler { class DiskStore : public osmium::handler::Handler {
using offset_index_type = osmium::index::map::Map<unsigned_object_id_type, size_t>; using offset_index_type = osmium::index::map::Map<unsigned_object_id_type, std::size_t>;
size_t m_offset = 0; std::size_t m_offset = 0;
int m_data_fd; int m_data_fd;
offset_index_type& m_node_index; offset_index_type& m_node_index;

View File

@ -108,7 +108,7 @@ namespace osmium {
<< (object.visible() ? "yes" : "no") << (object.visible() ? "yes" : "no")
<< "\n"; << "\n";
Dump dump(*m_out, m_with_size, m_prefix + " "); Dump dump{*m_out, m_with_size, m_prefix + " "};
osmium::apply(object.cbegin(), object.cend(), dump); osmium::apply(object.cbegin(), object.cend(), dump);
} }
@ -281,7 +281,7 @@ namespace osmium {
*m_out << "\n"; *m_out << "\n";
Dump dump(*m_out, m_with_size, m_prefix + " "); Dump dump{*m_out, m_with_size, m_prefix + " "};
osmium::apply(changeset.cbegin(), changeset.cend(), dump); osmium::apply(changeset.cbegin(), changeset.cend(), dump);
} }

View File

@ -64,9 +64,11 @@ namespace osmium {
template <typename TStoragePosIDs, typename TStorageNegIDs = dummy_type> template <typename TStoragePosIDs, typename TStorageNegIDs = dummy_type>
class NodeLocationsForWays : public osmium::handler::Handler { class NodeLocationsForWays : public osmium::handler::Handler {
static_assert(std::is_base_of<osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>, TStoragePosIDs>::value, "Index class must be derived from osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>"); template <typename T>
using based_on_map = std::is_base_of<osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>, T>;
static_assert(std::is_base_of<osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>, TStorageNegIDs>::value, "Index class must be derived from osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>"); static_assert(based_on_map<TStoragePosIDs>::value, "Index class must be derived from osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>");
static_assert(based_on_map<TStorageNegIDs>::value, "Index class must be derived from osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>");
public: public:
@ -81,11 +83,11 @@ namespace osmium {
/// Object that handles the actual storage of the node locations (with negative IDs). /// Object that handles the actual storage of the node locations (with negative IDs).
TStorageNegIDs& m_storage_neg; TStorageNegIDs& m_storage_neg;
osmium::unsigned_object_id_type m_last_id{0}; osmium::unsigned_object_id_type m_last_id = 0;
bool m_ignore_errors{false}; bool m_ignore_errors = false;
bool m_must_sort{false}; bool m_must_sort = false;
// It is okay to have this static dummy instance, even when using several threads, // It is okay to have this static dummy instance, even when using several threads,
// because it is read-only. // because it is read-only.
@ -123,7 +125,7 @@ namespace osmium {
} }
m_last_id = node.positive_id(); m_last_id = node.positive_id();
const osmium::object_id_type id = node.id(); const auto id = node.id();
if (id >= 0) { if (id >= 0) {
m_storage_pos.set(static_cast<osmium::unsigned_object_id_type>( id), node.location()); m_storage_pos.set(static_cast<osmium::unsigned_object_id_type>( id), node.location());
} else { } else {
@ -136,9 +138,9 @@ namespace osmium {
*/ */
osmium::Location get_node_location(const osmium::object_id_type id) const { osmium::Location get_node_location(const osmium::object_id_type id) const {
if (id >= 0) { if (id >= 0) {
return m_storage_pos.get(static_cast<osmium::unsigned_object_id_type>( id)); return m_storage_pos.get_noexcept(static_cast<osmium::unsigned_object_id_type>( id));
} else { } else {
return m_storage_neg.get(static_cast<osmium::unsigned_object_id_type>(-id)); return m_storage_neg.get_noexcept(static_cast<osmium::unsigned_object_id_type>(-id));
} }
} }
@ -155,16 +157,12 @@ namespace osmium {
} }
bool error = false; bool error = false;
for (auto& node_ref : way.nodes()) { for (auto& node_ref : way.nodes()) {
try {
node_ref.set_location(get_node_location(node_ref.ref())); node_ref.set_location(get_node_location(node_ref.ref()));
if (!node_ref.location()) { if (!node_ref.location()) {
error = true; error = true;
} }
} catch (const osmium::not_found&) {
error = true;
} }
} if (!m_ignore_errors && error) {
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

@ -50,15 +50,15 @@ namespace osmium {
template <typename T> template <typename T>
inline T* create_map_with_fd(const std::vector<std::string>& config) { inline T* create_map_with_fd(const std::vector<std::string>& config) {
if (config.size() == 1) { if (config.size() == 1) {
return new T(); return new T{};
} }
assert(config.size() > 1); assert(config.size() > 1);
const std::string& filename = config[1]; const std::string& filename = config[1];
const int fd = ::open(filename.c_str(), O_CREAT | O_RDWR, 0644); const int fd = ::open(filename.c_str(), O_CREAT | O_RDWR, 0644);
if (fd == -1) { if (fd == -1) {
throw std::runtime_error(std::string("can't open file '") + filename + "': " + std::strerror(errno)); throw std::runtime_error{std::string{"can't open file '"} + filename + "': " + std::strerror(errno)};
} }
return new T(fd); return new T{fd};
} }
} // namespace detail } // namespace detail

View File

@ -53,11 +53,11 @@ namespace osmium {
template <typename T> template <typename T>
class mmap_vector_file : public mmap_vector_base<T> { class mmap_vector_file : public mmap_vector_base<T> {
size_t filesize(int fd) const { static std::size_t filesize(int fd) {
const size_t size = osmium::util::file_size(fd); const auto size = osmium::util::file_size(fd);
if (size % sizeof(T) != 0) { if (size % sizeof(T) != 0) {
throw std::runtime_error("Index file has wrong size (must be multiple of " + std::to_string(sizeof(T)) + ")."); throw std::runtime_error{"Index file has wrong size (must be multiple of " + std::to_string(sizeof(T)) + ")."};
} }
return size / sizeof(T); return size / sizeof(T);

View File

@ -50,7 +50,7 @@ namespace osmium {
inline int create_tmp_file() { inline int create_tmp_file() {
FILE* file = ::tmpfile(); FILE* file = ::tmpfile();
if (!file) { if (!file) {
throw std::system_error(errno, std::system_category(), "tempfile failed"); throw std::system_error{errno, std::system_category(), "tempfile failed"};
} }
return fileno(file); return fileno(file);
} }

View File

@ -35,7 +35,6 @@ DEALINGS IN THE SOFTWARE.
#include <algorithm> #include <algorithm>
#include <cstddef> #include <cstddef>
#include <stdexcept>
#include <utility> #include <utility>
#include <osmium/index/index.hpp> #include <osmium/index/index.hpp>
@ -70,7 +69,7 @@ namespace osmium {
~VectorBasedDenseMap() noexcept final = default; ~VectorBasedDenseMap() noexcept final = default;
void reserve(const size_t size) final { void reserve(const std::size_t size) final {
m_vector.reserve(size); m_vector.reserve(size);
} }
@ -99,15 +98,15 @@ namespace osmium {
return m_vector[id]; return m_vector[id];
} }
size_t size() const final { std::size_t size() const final {
return m_vector.size(); return m_vector.size();
} }
size_t byte_size() const { std::size_t byte_size() const {
return m_vector.size() * sizeof(element_type); return m_vector.size() * sizeof(element_type);
} }
size_t used_memory() const final { std::size_t used_memory() const final {
return sizeof(TValue) * size(); return sizeof(TValue) * size();
} }
@ -205,15 +204,15 @@ namespace osmium {
return result->second; return result->second;
} }
size_t size() const final { std::size_t size() const final {
return m_vector.size(); return m_vector.size();
} }
size_t byte_size() const { std::size_t byte_size() const {
return m_vector.size() * sizeof(element_type); return m_vector.size() * sizeof(element_type);
} }
size_t used_memory() const final { std::size_t used_memory() const final {
return sizeof(element_type) * size(); return sizeof(element_type) * size();
} }

View File

@ -35,10 +35,11 @@ DEALINGS IN THE SOFTWARE.
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
#include <cstddef>
#include <cstring> #include <cstring>
#include <iterator>
#include <memory> #include <memory>
#include <type_traits> #include <type_traits>
#include <unordered_set>
#include <vector> #include <vector>
#include <osmium/osm/item_type.hpp> #include <osmium/osm/item_type.hpp>
@ -57,8 +58,7 @@ namespace osmium {
public: public:
virtual ~IdSet() { virtual ~IdSet() = default;
}
/** /**
* Add the given Id to the set. * Add the given Id to the set.
@ -80,6 +80,11 @@ namespace osmium {
*/ */
virtual void clear() = 0; virtual void clear() = 0;
/**
* Get an estimate of the amount of memory used for the set.
*/
virtual std::size_t used_memory() const noexcept = 0;
}; // class IdSet }; // class IdSet
template <typename T> template <typename T>
@ -139,7 +144,7 @@ namespace osmium {
} }
IdSetDenseIterator<T> operator++(int) noexcept { IdSetDenseIterator<T> operator++(int) noexcept {
IdSetDenseIterator<T> tmp(*this); IdSetDenseIterator<T> tmp{*this};
operator++(); operator++();
return tmp; return tmp;
} }
@ -178,17 +183,17 @@ namespace osmium {
// which would mean less (but larger) memory allocations. For // which would mean less (but larger) memory allocations. For
// relations Ids it could be smaller, because they would all fit // relations Ids it could be smaller, because they would all fit
// into a smaller allocation. // into a smaller allocation.
constexpr static const size_t chunk_bits = 22; constexpr static const std::size_t chunk_bits = 22;
constexpr static const size_t chunk_size = 1 << chunk_bits; constexpr static const std::size_t chunk_size = 1 << chunk_bits;
std::vector<std::unique_ptr<unsigned char[]>> m_data; std::vector<std::unique_ptr<unsigned char[]>> m_data;
T m_size = 0; T m_size = 0;
static size_t chunk_id(T id) noexcept { static std::size_t chunk_id(T id) noexcept {
return id >> (chunk_bits + 3); return id >> (chunk_bits + 3);
} }
static size_t offset(T id) noexcept { static std::size_t offset(T id) noexcept {
return (id >> 3) & ((1 << chunk_bits) - 1); return (id >> 3) & ((1 << chunk_bits) - 1);
} }
@ -244,7 +249,7 @@ namespace osmium {
* *
* @param id The Id to set. * @param id The Id to set.
*/ */
void set(T id) override final { void set(T id) final {
(void)check_and_set(id); (void)check_and_set(id);
} }
@ -267,7 +272,7 @@ namespace osmium {
* *
* @param id The Id to check. * @param id The Id to check.
*/ */
bool get(T id) const noexcept override final { bool get(T id) const noexcept final {
if (chunk_id(id) >= m_data.size()) { if (chunk_id(id) >= m_data.size()) {
return false; return false;
} }
@ -281,7 +286,7 @@ namespace osmium {
/** /**
* Is the set empty? * Is the set empty?
*/ */
bool empty() const noexcept override final { bool empty() const noexcept final {
return m_size == 0; return m_size == 0;
} }
@ -295,17 +300,21 @@ namespace osmium {
/** /**
* Clear the set. * Clear the set.
*/ */
void clear() override final { void clear() final {
m_data.clear(); m_data.clear();
m_size = 0; m_size = 0;
} }
std::size_t used_memory() const noexcept final {
return m_data.size() * chunk_size;
}
IdSetDenseIterator<T> begin() const { IdSetDenseIterator<T> begin() const {
return IdSetDenseIterator<T>{this, 0, last()}; return {this, 0, last()};
} }
IdSetDenseIterator<T> end() const { IdSetDenseIterator<T> end() const {
return IdSetDenseIterator<T>{this, last(), last()}; return {this, last(), last()};
} }
}; // class IdSetDense }; // class IdSetDense
@ -324,7 +333,7 @@ namespace osmium {
/** /**
* Add the given Id to the set. * Add the given Id to the set.
*/ */
void set(T id) override final { void set(T id) final {
m_data.push_back(id); m_data.push_back(id);
} }
@ -333,7 +342,7 @@ namespace osmium {
* *
* @param id The Id to check. * @param id The Id to check.
*/ */
bool get(T id) const noexcept override final { bool get(T id) const noexcept final {
const auto it = std::find(m_data.cbegin(), m_data.cend(), id); const auto it = std::find(m_data.cbegin(), m_data.cend(), id);
return it != m_data.cend(); return it != m_data.cend();
} }
@ -355,14 +364,14 @@ namespace osmium {
/** /**
* Is the set empty? * Is the set empty?
*/ */
bool empty() const noexcept override final { bool empty() const noexcept final {
return m_data.empty(); return m_data.empty();
} }
/** /**
* Clear the set. * Clear the set.
*/ */
void clear() override final { void clear() final {
m_data.clear(); m_data.clear();
} }
@ -383,10 +392,14 @@ namespace osmium {
* @pre You must have called sort_unique() before calling this * @pre You must have called sort_unique() before calling this
* or be sure there are no duplicates. * or be sure there are no duplicates.
*/ */
size_t size() const noexcept { std::size_t size() const noexcept {
return m_data.size(); return m_data.size();
} }
std::size_t used_memory() const noexcept final {
return m_data.capacity() * sizeof(T);
}
/// Iterator type. There is no non-const iterator. /// Iterator type. There is no non-const iterator.
using const_iterator = typename std::vector<T>::const_iterator; using const_iterator = typename std::vector<T>::const_iterator;
@ -408,6 +421,7 @@ namespace osmium {
}; // class IdSetSmall }; // class IdSetSmall
/// @deprecated Use nwr_array helper class instead.
template <template<typename> class IdSetType> template <template<typename> class IdSetType>
class NWRIdSet { class NWRIdSet {

View File

@ -34,12 +34,11 @@ DEALINGS IN THE SOFTWARE.
*/ */
#include <cstddef> #include <cstddef>
#include <cstdint>
#include <limits> #include <limits>
#include <stdexcept> #include <stdexcept>
#include <string> #include <string>
#include <osmium/util/compatibility.hpp>
namespace osmium { namespace osmium {
/** /**

View File

@ -43,7 +43,6 @@ DEALINGS IN THE SOFTWARE.
#include <type_traits> #include <type_traits>
#include <vector> #include <vector>
#include <osmium/util/compatibility.hpp>
#include <osmium/util/string.hpp> #include <osmium/util/string.hpp>
namespace osmium { namespace osmium {
@ -181,14 +180,14 @@ namespace osmium {
// 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 can 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*/) {
throw std::runtime_error("can't dump as array"); throw std::runtime_error{"can't dump as array"};
} }
}; // class Map }; // class Map
@ -245,13 +244,13 @@ namespace osmium {
} }
std::unique_ptr<map_type> create_map(const std::string& config_string) const { std::unique_ptr<map_type> create_map(const std::string& config_string) const {
std::vector<std::string> config = osmium::split_string(config_string, ','); std::vector<std::string> config{osmium::split_string(config_string, ',')};
if (config.empty()) { if (config.empty()) {
throw map_factory_error{"Need non-empty map type name"}; throw map_factory_error{"Need non-empty map type name"};
} }
auto it = m_callbacks.find(config[0]); const auto it = m_callbacks.find(config[0]);
if (it != m_callbacks.end()) { if (it != m_callbacks.end()) {
return std::unique_ptr<map_type>((it->second)(config)); return std::unique_ptr<map_type>((it->second)(config));
} }

View File

@ -37,6 +37,7 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/index/map/dense_mem_array.hpp> // IWYU pragma: keep #include <osmium/index/map/dense_mem_array.hpp> // IWYU pragma: keep
#include <osmium/index/map/dense_mmap_array.hpp> // IWYU pragma: keep #include <osmium/index/map/dense_mmap_array.hpp> // IWYU pragma: keep
#include <osmium/index/map/dummy.hpp> // IWYU pragma: keep #include <osmium/index/map/dummy.hpp> // IWYU pragma: keep
#include <osmium/index/map/flex_mem.hpp> // IWYU pragma: keep
#include <osmium/index/map/sparse_file_array.hpp> // IWYU pragma: keep #include <osmium/index/map/sparse_file_array.hpp> // IWYU pragma: keep
#include <osmium/index/map/sparse_mem_array.hpp> // IWYU pragma: keep #include <osmium/index/map/sparse_mem_array.hpp> // IWYU pragma: keep
#include <osmium/index/map/sparse_mem_map.hpp> // IWYU pragma: keep #include <osmium/index/map/sparse_mem_map.hpp> // IWYU pragma: keep

View File

@ -64,4 +64,8 @@ namespace osmium {
} // namespace osmium } // namespace osmium
#ifdef OSMIUM_WANT_NODE_LOCATION_MAPS
REGISTER_MAP(osmium::unsigned_object_id_type, osmium::Location, osmium::index::map::DenseFileArray, dense_file_array)
#endif
#endif // OSMIUM_INDEX_MAP_DENSE_FILE_ARRAY_HPP #endif // OSMIUM_INDEX_MAP_DENSE_FILE_ARRAY_HPP

View File

@ -54,4 +54,8 @@ namespace osmium {
} // namespace osmium } // namespace osmium
#ifdef OSMIUM_WANT_NODE_LOCATION_MAPS
REGISTER_MAP(osmium::unsigned_object_id_type, osmium::Location, osmium::index::map::DenseMemArray, dense_mem_array)
#endif
#endif // OSMIUM_INDEX_MAP_DENSE_MEM_ARRAY_HPP #endif // OSMIUM_INDEX_MAP_DENSE_MEM_ARRAY_HPP

View File

@ -55,6 +55,10 @@ namespace osmium {
} // namespace osmium } // namespace osmium
#ifdef OSMIUM_WANT_NODE_LOCATION_MAPS
REGISTER_MAP(osmium::unsigned_object_id_type, osmium::Location, osmium::index::map::DenseMmapArray, dense_mmap_array)
#endif
#endif // __linux__ #endif // __linux__
#endif // OSMIUM_INDEX_MAP_DENSE_MMAP_ARRAY_HPP #endif // OSMIUM_INDEX_MAP_DENSE_MMAP_ARRAY_HPP

View File

@ -0,0 +1,285 @@
#ifndef OSMIUM_INDEX_MAP_FLEX_MEM_HPP
#define OSMIUM_INDEX_MAP_FLEX_MEM_HPP
/*
This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2013-2017 Jochen Topf <jochen@topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <utility>
#include <vector>
#include <osmium/index/map.hpp>
#include <osmium/index/index.hpp>
#define OSMIUM_HAS_INDEX_MAP_FLEX_MEM
namespace osmium {
namespace index {
namespace map {
/**
* This is an autoscaling index that works well with small and
* large input data. All data will be held in memory. For small
* input data a sparse array will be used, if this becomes
* inefficient, the class will switch automatically to a dense
* index.
*/
template <typename TId, typename TValue>
class FlexMem : public osmium::index::map::Map<TId, TValue> {
// This value is based on benchmarks with a planet file and
// some smaller files.
enum constant_bits {
bits = 16
};
enum constant_block_size : uint64_t {
block_size = 1ll << bits
};
// Minimum number of entries in the sparse index before we
// are considering switching to a dense index.
enum constant_min_dense_entries : int64_t {
min_dense_entries = 0xffffff
};
// When more than a third of all Ids are in the index, we
// switch to the dense index. This is a compromise between
// the best memory efficiency (which we would get at a factor
// of 2) and the performance (dense index is much faster then
// the sparse index).
enum constant_density_factor {
density_factor = 3
};
// An entry in the sparse index
struct entry {
uint64_t id;
TValue value;
entry(uint64_t i, TValue v) :
id(i),
value(v) {
}
bool operator<(const entry other) const noexcept {
return id < other.id;
}
};
std::vector<entry> m_sparse_entries;
std::vector<std::vector<TValue>> m_dense_blocks;
// The maximum Id that was seen yet. Only set in sparse mode.
uint64_t m_max_id = 0;
// Set to false in sparse mode and to true in dense mode.
bool m_dense;
static uint64_t block(const uint64_t id) noexcept {
return id >> bits;
}
static uint64_t offset(const uint64_t id) noexcept {
return id & (block_size - 1);
}
// Assure that the block with the given number exists. Create
// it if needed.
void assure_block(const uint64_t num) {
if (num >= m_dense_blocks.size()) {
m_dense_blocks.resize(num + 1);
}
if (m_dense_blocks[num].empty()) {
m_dense_blocks[num].assign(block_size, osmium::index::empty_value<TValue>());
}
}
void set_sparse(const uint64_t id, const TValue value) {
m_sparse_entries.emplace_back(id, value);
if (id > m_max_id) {
m_max_id = id;
if (m_sparse_entries.size() >= min_dense_entries) {
if (m_max_id < m_sparse_entries.size() * density_factor) {
switch_to_dense();
}
}
}
}
TValue get_sparse(const uint64_t id) const noexcept {
const auto it = std::lower_bound(m_sparse_entries.begin(),
m_sparse_entries.end(),
entry{id, osmium::index::empty_value<TValue>()});
if (it == m_sparse_entries.end() || it->id != id) {
return osmium::index::empty_value<TValue>();
}
return it->value;
}
void set_dense(const uint64_t id, const TValue value) {
assure_block(block(id));
m_dense_blocks[block(id)][offset(id)] = value;
}
TValue get_dense(const uint64_t id) const noexcept {
if (m_dense_blocks.size() <= block(id) || m_dense_blocks[block(id)].empty()) {
return osmium::index::empty_value<TValue>();
}
return m_dense_blocks[block(id)][offset(id)];
}
public:
/**
* Create FlexMem index.
*
* @param use_dense Usually FlexMem indexes start out as sparse
* indexes and will switch to dense when they
* think it is better. Set this to force dense
* indexing from the start. This is usually
* only useful for testing.
*/
explicit FlexMem(bool use_dense = false) :
m_dense(use_dense) {
}
~FlexMem() noexcept final = default;
bool is_dense() const noexcept {
return m_dense;
}
std::size_t size() const noexcept final {
if (m_dense) {
return m_dense_blocks.size() * block_size;
}
return m_sparse_entries.size();
}
std::size_t used_memory() const noexcept final {
return sizeof(FlexMem) +
m_sparse_entries.size() * sizeof(entry) +
m_dense_blocks.size() * (block_size * sizeof(TValue) + sizeof(std::vector<TValue>));
}
void set(const TId id, const TValue value) final {
if (m_dense) {
set_dense(id, value);
} else {
set_sparse(id, value);
}
}
TValue get_noexcept(const TId id) const noexcept final {
if (m_dense) {
return get_dense(id);
}
return get_sparse(id);
}
TValue get(const TId id) const final {
const auto value = get_noexcept(id);
if (value == osmium::index::empty_value<TValue>()) {
throw osmium::not_found{id};
}
return value;
}
void clear() final {
m_sparse_entries.clear();
m_sparse_entries.shrink_to_fit();
m_dense_blocks.clear();
m_dense_blocks.shrink_to_fit();
m_max_id = 0;
m_dense = false;
}
void sort() final {
std::sort(m_sparse_entries.begin(), m_sparse_entries.end());
}
/**
* Switch from using a sparse to a dense index. Usually you
* do not need to call this, because the FlexMem class will
* do this automatically if it thinks the dense index is more
* efficient.
*
* Does nothing if the index is already in dense mode.
*/
void switch_to_dense() {
if (m_dense) {
return;
}
for (const auto entry : m_sparse_entries) {
set_dense(entry.id, entry.value);
}
m_sparse_entries.clear();
m_sparse_entries.shrink_to_fit();
m_max_id = 0;
m_dense = true;
}
std::pair<std::size_t, std::size_t> stats() const noexcept {
std::size_t used_blocks = 0;
std::size_t empty_blocks = 0;
for (const auto& block : m_dense_blocks) {
if (block.empty()) {
++empty_blocks;
} else {
++used_blocks;
}
}
return std::make_pair(used_blocks, empty_blocks);
}
}; // class FlexMem
} // namespace map
} // namespace index
} // namespace osmium
#ifdef OSMIUM_WANT_NODE_LOCATION_MAPS
REGISTER_MAP(osmium::unsigned_object_id_type, osmium::Location, osmium::index::map::FlexMem, flex_mem)
#endif
#endif // OSMIUM_INDEX_MAP_FLEX_MEM_HPP

View File

@ -64,4 +64,8 @@ namespace osmium {
} // namespace osmium } // namespace osmium
#ifdef OSMIUM_WANT_NODE_LOCATION_MAPS
REGISTER_MAP(osmium::unsigned_object_id_type, osmium::Location, osmium::index::map::SparseFileArray, sparse_file_array)
#endif
#endif // OSMIUM_INDEX_MAP_SPARSE_FILE_ARRAY_HPP #endif // OSMIUM_INDEX_MAP_SPARSE_FILE_ARRAY_HPP

View File

@ -57,4 +57,8 @@ namespace osmium {
} // namespace osmium } // namespace osmium
#ifdef OSMIUM_WANT_NODE_LOCATION_MAPS
REGISTER_MAP(osmium::unsigned_object_id_type, osmium::Location, osmium::index::map::SparseMemArray, sparse_mem_array)
#endif
#endif // OSMIUM_INDEX_MAP_SPARSE_MEM_ARRAY_HPP #endif // OSMIUM_INDEX_MAP_SPARSE_MEM_ARRAY_HPP

View File

@ -120,4 +120,8 @@ namespace osmium {
} // namespace osmium } // namespace osmium
#ifdef OSMIUM_WANT_NODE_LOCATION_MAPS
REGISTER_MAP(osmium::unsigned_object_id_type, osmium::Location, osmium::index::map::SparseMemMap, sparse_mem_map)
#endif
#endif // OSMIUM_INDEX_MAP_SPARSE_MEM_MAP_HPP #endif // OSMIUM_INDEX_MAP_SPARSE_MEM_MAP_HPP

View File

@ -150,6 +150,10 @@ namespace osmium {
} // namespace osmium } // namespace osmium
#ifdef OSMIUM_WANT_NODE_LOCATION_MAPS
REGISTER_MAP(osmium::unsigned_object_id_type, osmium::Location, osmium::index::map::SparseMemTable, sparse_mem_table)
#endif
#endif // OSMIUM_WITH_SPARSEHASH #endif // OSMIUM_WITH_SPARSEHASH
#endif // OSMIUM_INDEX_BYID_SPARSE_MEM_TABLE_HPP #endif // OSMIUM_INDEX_MAP_SPARSE_MEM_TABLE_HPP

View File

@ -55,6 +55,10 @@ namespace osmium {
} // namespace osmium } // namespace osmium
#ifdef OSMIUM_WANT_NODE_LOCATION_MAPS
REGISTER_MAP(osmium::unsigned_object_id_type, osmium::Location, osmium::index::map::SparseMmapArray, sparse_mmap_array)
#endif
#endif // __linux__ #endif // __linux__
#endif // OSMIUM_INDEX_MAP_SPARSE_MMAP_ARRAY_HPP #endif // OSMIUM_INDEX_MAP_SPARSE_MMAP_ARRAY_HPP

View File

@ -35,6 +35,8 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/index/map.hpp> // IWYU pragma: keep #include <osmium/index/map.hpp> // IWYU pragma: keep
#define OSMIUM_WANT_NODE_LOCATION_MAPS
#ifdef OSMIUM_HAS_INDEX_MAP_DENSE_FILE_ARRAY #ifdef OSMIUM_HAS_INDEX_MAP_DENSE_FILE_ARRAY
REGISTER_MAP(osmium::unsigned_object_id_type, osmium::Location, osmium::index::map::DenseFileArray, dense_file_array) REGISTER_MAP(osmium::unsigned_object_id_type, osmium::Location, osmium::index::map::DenseFileArray, dense_file_array)
#endif #endif
@ -67,4 +69,8 @@ DEALINGS IN THE SOFTWARE.
REGISTER_MAP(osmium::unsigned_object_id_type, osmium::Location, osmium::index::map::SparseMmapArray, sparse_mmap_array) REGISTER_MAP(osmium::unsigned_object_id_type, osmium::Location, osmium::index::map::SparseMmapArray, sparse_mmap_array)
#endif #endif
#ifdef OSMIUM_HAS_INDEX_MAP_FLEX_MEM
REGISTER_MAP(osmium::unsigned_object_id_type, osmium::Location, osmium::index::map::FlexMem, flex_mem)
#endif
#endif // OSMIUM_INDEX_NODE_LOCATIONS_MAP_HPP #endif // OSMIUM_INDEX_NODE_LOCATIONS_MAP_HPP

View File

@ -0,0 +1,59 @@
#ifndef OSMIUM_INDEX_NWR_ARRAY_HPP
#define OSMIUM_INDEX_NWR_ARRAY_HPP
/*
This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2013-2017 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 <osmium/osm/item_type.hpp>
namespace osmium {
template <typename T>
class nwr_array {
T m_sets[3];
public:
T& operator()(osmium::item_type type) noexcept {
return m_sets[osmium::item_type_to_nwr_index(type)];
}
const T& operator()(osmium::item_type type) const noexcept {
return m_sets[osmium::item_type_to_nwr_index(type)];
}
}; // class nwr_array
} // namespace osmium
#endif // OSMIUM_INDEX_NWR_ARRAY_HPP

View File

@ -35,10 +35,14 @@ DEALINGS IN THE SOFTWARE.
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
#include <cstddef>
#include <cstdint> #include <cstdint>
#include <tuple> #include <tuple>
#include <type_traits>
#include <utility>
#include <vector> #include <vector>
#include <osmium/osm/item_type.hpp>
#include <osmium/osm/relation.hpp> #include <osmium/osm/relation.hpp>
#include <osmium/osm/types.hpp> #include <osmium/osm/types.hpp>
@ -91,6 +95,24 @@ namespace osmium {
m_map.emplace_back(key, value); m_map.emplace_back(key, value);
} }
typename std::enable_if<std::is_same<TKey, TValue>::value>::type flip_in_place() {
for (auto& p : m_map) {
using std::swap;
swap(p.key, p.value);
}
}
flat_map<TValue, TValueInternal, TKey, TKeyInternal> flip_copy() {
flat_map<TValue, TValueInternal, TKey, TKeyInternal> map;
map.reserve(m_map.size());
for (const auto& p : m_map) {
map.set(p.value, p.key);
}
return map;
}
void sort_unique() { void sort_unique() {
std::sort(m_map.begin(), m_map.end()); std::sort(m_map.begin(), m_map.end());
const auto last = std::unique(m_map.begin(), m_map.end()); const auto last = std::unique(m_map.begin(), m_map.end());
@ -107,19 +129,25 @@ namespace osmium {
return m_map.empty(); return m_map.empty();
} }
size_t size() const noexcept { std::size_t size() const noexcept {
return m_map.size(); return m_map.size();
} }
void reserve(std::size_t size) {
m_map.reserve(size);
}
}; // class flat_map }; // class flat_map
} // namespace detail } // namespace detail
/** /**
* Index for looking up parent relation IDs given a member relation ID. * Index for looking up parent relation IDs given a member relation ID
* or the other way around.
*
* You can not instantiate such an index yourself, instead you need to * You can not instantiate such an index yourself, instead you need to
* instantiate a RelationsMapStash, fill it and then create an index from * instantiate a RelationsMapStash, fill it and then create an index
* it: * from it:
* *
* @code * @code
* RelationsMapStash stash; * RelationsMapStash stash;
@ -128,10 +156,10 @@ namespace osmium {
* stash.add_members(relation); * stash.add_members(relation);
* } * }
* ... * ...
* const auto index = stash.build_index(); * const auto index = stash.build_member_to_parent_index();
* ... * ...
* osmium::unsigned_object_id_type member_id = ...; * osmium::unsigned_object_id_type member_id = ...;
* index.for_each_parent(member_id, [](osmium::unsigned_object_id_type id) { * index.for_each(member_id, [](osmium::unsigned_object_id_type parent_id) {
* ... * ...
* }); * });
* ... * ...
@ -141,13 +169,14 @@ namespace osmium {
class RelationsMapIndex { class RelationsMapIndex {
friend class RelationsMapStash; friend class RelationsMapStash;
friend class RelationsMapIndexes;
using map_type = detail::flat_map<osmium::unsigned_object_id_type, uint32_t, using map_type = detail::flat_map<osmium::unsigned_object_id_type, uint32_t,
osmium::unsigned_object_id_type, uint32_t>; osmium::unsigned_object_id_type, uint32_t>;
map_type m_map; map_type m_map;
RelationsMapIndex(map_type&& map) : explicit RelationsMapIndex(map_type&& map) :
m_map(std::move(map)) { m_map(std::move(map)) {
} }
@ -162,8 +191,8 @@ namespace osmium {
RelationsMapIndex& operator=(RelationsMapIndex&&) = default; RelationsMapIndex& operator=(RelationsMapIndex&&) = default;
/** /**
* Find the given relation id in the index and call the given function * Find the given relation id in the index and call the given
* with all parent relation ids. * function with all parent relation ids.
* *
* @code * @code
* osmium::unsigned_object_id_type member_id = 17; * osmium::unsigned_object_id_type member_id = 17;
@ -172,14 +201,38 @@ namespace osmium {
* }); * });
* @endcode * @endcode
* *
* @deprecated Use for_each() instead.
*
* Complexity: Logarithmic in the number of elements in the index. * Complexity: Logarithmic in the number of elements in the index.
* (Lookup uses binary search.) * (Lookup uses binary search.)
*/ */
template <typename Func> template <typename TFunc>
void for_each_parent(osmium::unsigned_object_id_type member_id, Func&& func) const { void for_each_parent(osmium::unsigned_object_id_type member_id, TFunc&& func) const {
const auto parents = m_map.get(member_id); const auto parents = m_map.get(member_id);
for (auto it = parents.first; it != parents.second; ++it) { for (auto it = parents.first; it != parents.second; ++it) {
std::forward<Func>(func)(it->value); std::forward<TFunc>(func)(it->value);
}
}
/**
* Find the given relation id in the index and call the given
* function with all related relation ids.
*
* @code
* osmium::unsigned_object_id_type id = 17;
* index.for_each(id, [](osmium::unsigned_object_id_type rid) {
* ...
* });
* @endcode
*
* Complexity: Logarithmic in the number of elements in the index.
* (Lookup uses binary search.)
*/
template <typename TFunc>
void for_each(osmium::unsigned_object_id_type id, TFunc&& func) const {
const auto parents = m_map.get(id);
for (auto it = parents.first; it != parents.second; ++it) {
std::forward<TFunc>(func)(it->value);
} }
} }
@ -197,16 +250,58 @@ namespace osmium {
* *
* Complexity: Constant. * Complexity: Constant.
*/ */
size_t size() const noexcept { std::size_t size() const noexcept {
return m_map.size(); return m_map.size();
} }
}; // RelationsMapIndex }; // class RelationsMapIndex
class RelationsMapIndexes {
friend class RelationsMapStash;
RelationsMapIndex m_member_to_parent;
RelationsMapIndex m_parent_to_member;
RelationsMapIndexes(RelationsMapIndex::map_type&& map1, RelationsMapIndex::map_type&& map2) :
m_member_to_parent(std::move(map1)),
m_parent_to_member(std::move(map2)) {
}
public:
const RelationsMapIndex& member_to_parent() const noexcept {
return m_member_to_parent;
}
const RelationsMapIndex& parent_to_member() const noexcept {
return m_parent_to_member;
}
/**
* Is this index empty?
*
* Complexity: Constant.
*/
bool empty() const noexcept {
return m_member_to_parent.empty();
}
/**
* How many entries are in this index?
*
* Complexity: Constant.
*/
std::size_t size() const noexcept {
return m_member_to_parent.size();
}
}; // class RelationsMapIndexes
/** /**
* The RelationsMapStash is used to build up the data needed to create * The RelationsMapStash is used to build up the data needed to create
* an index of member relation ID to parent relation ID. See the * an index of member relation ID to parent relation ID or the other
* RelationsMapIndex class for more. * way around. See the RelationsMapIndex class for more.
*/ */
class RelationsMapStash { class RelationsMapStash {
@ -264,15 +359,18 @@ namespace osmium {
* *
* Complexity: Constant. * Complexity: Constant.
*/ */
size_t size() const noexcept { std::size_t size() const noexcept {
assert(m_valid && "You can't use the RelationsMap any more after calling build_index()"); assert(m_valid && "You can't use the RelationsMap any more after calling build_index()");
return m_map.size(); return m_map.size();
} }
/** /**
* Build an index with the contents of this stash and return it. * Build an index for member to parent lookups from the contents
* of this stash and return it.
* *
* After you get the index you can not use the stash any more! * After you get the index you can not use the stash any more!
*
* @deprecated Use build_member_to_parent_index() instead.
*/ */
RelationsMapIndex build_index() { RelationsMapIndex build_index() {
assert(m_valid && "You can't use the RelationsMap any more after calling build_index()"); assert(m_valid && "You can't use the RelationsMap any more after calling build_index()");
@ -283,6 +381,54 @@ namespace osmium {
return RelationsMapIndex{std::move(m_map)}; return RelationsMapIndex{std::move(m_map)};
} }
/**
* Build an index for member to parent lookups from the contents
* of this stash and return it.
*
* After you get the index you can not use the stash any more!
*/
RelationsMapIndex build_member_to_parent_index() {
assert(m_valid && "You can't use the RelationsMap any more after calling build_member_to_parent_index()");
m_map.sort_unique();
#ifndef NDEBUG
m_valid = false;
#endif
return RelationsMapIndex{std::move(m_map)};
}
/**
* Build an index for parent to member lookups from the contents
* of this stash and return it.
*
* After you get the index you can not use the stash any more!
*/
RelationsMapIndex build_parent_to_member_index() {
assert(m_valid && "You can't use the RelationsMap any more after calling build_parent_to_member_index()");
m_map.flip_in_place();
m_map.sort_unique();
#ifndef NDEBUG
m_valid = false;
#endif
return RelationsMapIndex{std::move(m_map)};
}
/**
* Build indexes for member-to-parent and parent-to-member lookups
* from the contents of this stash and return them.
*
* After you get the index you can not use the stash any more!
*/
RelationsMapIndexes build_indexes() {
assert(m_valid && "You can't use the RelationsMap any more after calling build_indexes()");
auto reverse_map = m_map.flip_copy();
reverse_map.sort_unique();
m_map.sort_unique();
#ifndef NDEBUG
m_valid = false;
#endif
return RelationsMapIndexes{std::move(m_map), std::move(reverse_map)};
}
}; // class RelationsMapStash }; // class RelationsMapStash
} // namespace index } // namespace index

View File

@ -85,7 +85,7 @@ namespace osmium {
namespace detail { namespace detail {
OSMIUM_NORETURN inline void throw_bzip2_error(BZFILE* bzfile, const char* msg, int bzlib_error = 0) { OSMIUM_NORETURN inline void throw_bzip2_error(BZFILE* bzfile, const char* msg, int bzlib_error = 0) {
std::string error("bzip2 error: "); std::string error{"bzip2 error: "};
error += msg; error += msg;
error += ": "; error += ": ";
int errnum = bzlib_error; int errnum = bzlib_error;
@ -94,7 +94,7 @@ namespace osmium {
} else { } else {
error += ::BZ2_bzerror(bzfile, &errnum); error += ::BZ2_bzerror(bzfile, &errnum);
} }
throw osmium::bzip2_error(error, errnum); throw osmium::bzip2_error{error, errnum};
} }
} // namespace detail } // namespace detail
@ -143,7 +143,7 @@ namespace osmium {
osmium::io::detail::reliable_fsync(::fileno(m_file)); osmium::io::detail::reliable_fsync(::fileno(m_file));
} }
if (fclose(m_file) != 0) { if (fclose(m_file) != 0) {
throw std::system_error(errno, std::system_category(), "Close failed"); throw std::system_error{errno, std::system_category(), "Close failed"};
} }
} }
if (error != BZ_OK) { if (error != BZ_OK) {
@ -187,7 +187,7 @@ namespace osmium {
if (!m_stream_end) { if (!m_stream_end) {
buffer.resize(osmium::io::Decompressor::input_buffer_size); buffer.resize(osmium::io::Decompressor::input_buffer_size);
int error; int error;
int nread = ::BZ2_bzRead(&error, m_bzfile, const_cast<char*>(buffer.data()), static_cast_with_assert<int>(buffer.size())); const int nread = ::BZ2_bzRead(&error, m_bzfile, const_cast<char*>(buffer.data()), static_cast_with_assert<int>(buffer.size()));
if (error != BZ_OK && error != BZ_STREAM_END) { if (error != BZ_OK && error != BZ_STREAM_END) {
detail::throw_bzip2_error(m_bzfile, "read failed", error); detail::throw_bzip2_error(m_bzfile, "read failed", error);
} }
@ -227,7 +227,7 @@ namespace osmium {
m_bzfile = nullptr; m_bzfile = nullptr;
if (m_file) { if (m_file) {
if (fclose(m_file) != 0) { if (fclose(m_file) != 0) {
throw std::system_error(errno, std::system_category(), "Close failed"); throw std::system_error{errno, std::system_category(), "Close failed"};
} }
} }
if (error != BZ_OK) { if (error != BZ_OK) {
@ -252,10 +252,10 @@ namespace osmium {
m_bzstream() { m_bzstream() {
m_bzstream.next_in = const_cast<char*>(buffer); m_bzstream.next_in = const_cast<char*>(buffer);
m_bzstream.avail_in = static_cast_with_assert<unsigned int>(size); m_bzstream.avail_in = static_cast_with_assert<unsigned int>(size);
int result = BZ2_bzDecompressInit(&m_bzstream, 0, 0); const int result = BZ2_bzDecompressInit(&m_bzstream, 0, 0);
if (result != BZ_OK) { if (result != BZ_OK) {
std::string message("bzip2 error: decompression init failed: "); std::string message{"bzip2 error: decompression init failed: "};
throw bzip2_error(message, result); throw bzip2_error{message, result};
} }
} }
@ -275,7 +275,7 @@ namespace osmium {
output.resize(buffer_size); output.resize(buffer_size);
m_bzstream.next_out = const_cast<char*>(output.data()); m_bzstream.next_out = const_cast<char*>(output.data());
m_bzstream.avail_out = buffer_size; m_bzstream.avail_out = buffer_size;
int result = BZ2_bzDecompress(&m_bzstream); const int result = BZ2_bzDecompress(&m_bzstream);
if (result != BZ_OK) { if (result != BZ_OK) {
m_buffer = nullptr; m_buffer = nullptr;
@ -283,8 +283,8 @@ namespace osmium {
} }
if (result != BZ_OK && result != BZ_STREAM_END) { if (result != BZ_OK && result != BZ_STREAM_END) {
std::string message("bzip2 error: decompress failed: "); std::string message{"bzip2 error: decompress failed: "};
throw bzip2_error(message, result); throw bzip2_error{message, result};
} }
output.resize(static_cast<unsigned long>(m_bzstream.next_out - output.data())); output.resize(static_cast<unsigned long>(m_bzstream.next_out - output.data()));
@ -304,9 +304,9 @@ namespace osmium {
// we want the register_compression() function to run, setting // we want the register_compression() function to run, setting
// the variable is only a side-effect, it will never be used // the variable is only a side-effect, it will never be used
const bool registered_bzip2_compression = osmium::io::CompressionFactory::instance().register_compression(osmium::io::file_compression::bzip2, const bool registered_bzip2_compression = osmium::io::CompressionFactory::instance().register_compression(osmium::io::file_compression::bzip2,
[](int fd, fsync sync) { return new osmium::io::Bzip2Compressor(fd, sync); }, [](int fd, fsync sync) { return new osmium::io::Bzip2Compressor{fd, sync}; },
[](int fd) { return new osmium::io::Bzip2Decompressor(fd); }, [](int fd) { return new osmium::io::Bzip2Decompressor{fd}; },
[](const char* buffer, size_t size) { return new osmium::io::Bzip2BufferDecompressor(buffer, size); } [](const char* buffer, size_t size) { return new osmium::io::Bzip2BufferDecompressor{buffer, size}; }
); );
// dummy function to silence the unused variable warning from above // dummy function to silence the unused variable warning from above

View File

@ -54,7 +54,6 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/io/error.hpp> #include <osmium/io/error.hpp>
#include <osmium/io/file_compression.hpp> #include <osmium/io/file_compression.hpp>
#include <osmium/io/writer_options.hpp> #include <osmium/io/writer_options.hpp>
#include <osmium/util/compatibility.hpp>
#include <osmium/util/file.hpp> #include <osmium/util/file.hpp>
namespace osmium { namespace osmium {
@ -77,8 +76,7 @@ namespace osmium {
m_fsync(sync) { m_fsync(sync) {
} }
virtual ~Compressor() noexcept { virtual ~Compressor() noexcept = default;
}
virtual void write(const std::string& data) = 0; virtual void write(const std::string& data) = 0;
@ -88,8 +86,8 @@ namespace osmium {
class Decompressor { class Decompressor {
std::atomic<size_t> m_file_size {0}; std::atomic<std::size_t> m_file_size{0};
std::atomic<size_t> m_offset {0}; std::atomic<std::size_t> m_offset{0};
public: public:
@ -103,26 +101,25 @@ namespace osmium {
Decompressor(Decompressor&&) = delete; Decompressor(Decompressor&&) = delete;
Decompressor& operator=(Decompressor&&) = delete; Decompressor& operator=(Decompressor&&) = delete;
virtual ~Decompressor() noexcept { virtual ~Decompressor() noexcept = default;
}
virtual std::string read() = 0; virtual std::string read() = 0;
virtual void close() = 0; virtual void close() = 0;
size_t file_size() const noexcept { std::size_t file_size() const noexcept {
return m_file_size; return m_file_size;
} }
void set_file_size(size_t size) noexcept { void set_file_size(std::size_t size) noexcept {
m_file_size = size; m_file_size = size;
} }
size_t offset() const noexcept { std::size_t offset() const noexcept {
return m_offset; return m_offset;
} }
void set_offset(size_t offset) noexcept { void set_offset(std::size_t offset) noexcept {
m_offset = offset; m_offset = offset;
} }
@ -141,7 +138,7 @@ namespace osmium {
using create_compressor_type = std::function<osmium::io::Compressor*(int, fsync)>; using create_compressor_type = std::function<osmium::io::Compressor*(int, fsync)>;
using create_decompressor_type_fd = std::function<osmium::io::Decompressor*(int)>; using create_decompressor_type_fd = std::function<osmium::io::Decompressor*(int)>;
using create_decompressor_type_buffer = std::function<osmium::io::Decompressor*(const char*, size_t)>; using create_decompressor_type_buffer = std::function<osmium::io::Decompressor*(const char*, std::size_t)>;
private: private:
@ -187,10 +184,10 @@ namespace osmium {
create_decompressor_type_fd create_decompressor_fd, create_decompressor_type_fd create_decompressor_fd,
create_decompressor_type_buffer create_decompressor_buffer) { create_decompressor_type_buffer create_decompressor_buffer) {
compression_map_type::value_type cc(compression, compression_map_type::value_type cc{compression,
std::make_tuple(create_compressor, std::make_tuple(create_compressor,
create_decompressor_fd, create_decompressor_fd,
create_decompressor_buffer)); create_decompressor_buffer)};
return m_callbacks.insert(cc).second; return m_callbacks.insert(cc).second;
} }
@ -208,7 +205,7 @@ namespace osmium {
return p; return p;
} }
std::unique_ptr<osmium::io::Decompressor> create_decompressor(osmium::io::file_compression compression, const char* buffer, size_t size) const { std::unique_ptr<osmium::io::Decompressor> create_decompressor(osmium::io::file_compression compression, const char* buffer, std::size_t size) const {
const auto callbacks = find_callbacks(compression); const auto callbacks = find_callbacks(compression);
return std::unique_ptr<osmium::io::Decompressor>(std::get<2>(callbacks)(buffer, size)); return std::unique_ptr<osmium::io::Decompressor>(std::get<2>(callbacks)(buffer, size));
} }
@ -240,7 +237,7 @@ namespace osmium {
void close() final { void close() final {
if (m_fd >= 0) { if (m_fd >= 0) {
int fd = m_fd; const int fd = m_fd;
m_fd = -1; m_fd = -1;
if (do_fsync()) { if (do_fsync()) {
osmium::io::detail::reliable_fsync(fd); osmium::io::detail::reliable_fsync(fd);
@ -255,8 +252,8 @@ namespace osmium {
int m_fd; int m_fd;
const char *m_buffer; const char *m_buffer;
size_t m_buffer_size; std::size_t m_buffer_size;
size_t m_offset = 0; std::size_t m_offset = 0;
public: public:
@ -267,7 +264,7 @@ namespace osmium {
m_buffer_size(0) { m_buffer_size(0) {
} }
NoDecompressor(const char* buffer, size_t size) : NoDecompressor(const char* buffer, std::size_t size) :
Decompressor(), Decompressor(),
m_fd(-1), m_fd(-1),
m_buffer(buffer), m_buffer(buffer),
@ -287,15 +284,15 @@ namespace osmium {
if (m_buffer) { if (m_buffer) {
if (m_buffer_size != 0) { if (m_buffer_size != 0) {
size_t size = m_buffer_size; const std::size_t size = m_buffer_size;
m_buffer_size = 0; m_buffer_size = 0;
buffer.append(m_buffer, size); buffer.append(m_buffer, size);
} }
} else { } else {
buffer.resize(osmium::io::Decompressor::input_buffer_size); buffer.resize(osmium::io::Decompressor::input_buffer_size);
auto nread = ::read(m_fd, const_cast<char*>(buffer.data()), osmium::io::Decompressor::input_buffer_size); const auto nread = ::read(m_fd, const_cast<char*>(buffer.data()), osmium::io::Decompressor::input_buffer_size);
if (nread < 0) { if (nread < 0) {
throw std::system_error(errno, std::system_category(), "Read failed"); throw std::system_error{errno, std::system_category(), "Read failed"};
} }
buffer.resize(std::string::size_type(nread)); buffer.resize(std::string::size_type(nread));
} }
@ -308,7 +305,7 @@ namespace osmium {
void close() final { void close() final {
if (m_fd >= 0) { if (m_fd >= 0) {
int fd = m_fd; const int fd = m_fd;
m_fd = -1; m_fd = -1;
osmium::io::detail::reliable_close(fd); osmium::io::detail::reliable_close(fd);
} }
@ -321,9 +318,9 @@ namespace osmium {
// we want the register_compression() function to run, setting // we want the register_compression() function to run, setting
// the variable is only a side-effect, it will never be used // the variable is only a side-effect, it will never be used
const bool registered_no_compression = osmium::io::CompressionFactory::instance().register_compression(osmium::io::file_compression::none, const bool registered_no_compression = osmium::io::CompressionFactory::instance().register_compression(osmium::io::file_compression::none,
[](int fd, fsync sync) { return new osmium::io::NoCompressor(fd, sync); }, [](int fd, fsync sync) { return new osmium::io::NoCompressor{fd, sync}; },
[](int fd) { return new osmium::io::NoDecompressor(fd); }, [](int fd) { return new osmium::io::NoDecompressor{fd}; },
[](const char* buffer, size_t size) { return new osmium::io::NoDecompressor(buffer, size); } [](const char* buffer, std::size_t size) { return new osmium::io::NoDecompressor{buffer, size}; }
); );
// dummy function to silence the unused variable warning from above // dummy function to silence the unused variable warning from above

View File

@ -282,15 +282,16 @@ namespace osmium {
void write_box(const osmium::Box& box) { void write_box(const osmium::Box& box) {
write_fieldname("box l/b/r/t"); write_fieldname("box l/b/r/t");
if (!box) { if (box.bottom_left().is_undefined() &&
box.top_right().is_undefined()) {
write_error("BOX NOT SET!\n"); write_error("BOX NOT SET!\n");
return; return;
} }
const auto& bl = box.bottom_left(); const auto& bl = box.bottom_left();
const auto& tr = box.top_right(); const auto& tr = box.top_right();
bl.as_string(std::back_inserter(*m_out)); bl.as_string_without_check(std::back_inserter(*m_out));
*m_out += ' '; *m_out += ' ';
tr.as_string(std::back_inserter(*m_out)); tr.as_string_without_check(std::back_inserter(*m_out));
if (!box.valid()) { if (!box.valid()) {
write_error(" INVALID BOX!"); write_error(" INVALID BOX!");
} }
@ -520,8 +521,8 @@ namespace osmium {
public: public:
DebugOutputFormat(const osmium::io::File& file, future_string_queue_type& output_queue) : DebugOutputFormat(osmium::thread::Pool& pool, const osmium::io::File& file, future_string_queue_type& output_queue) :
OutputFormat(output_queue), OutputFormat(pool, output_queue),
m_options() { m_options() {
m_options.add_metadata = file.is_not_false("add_metadata"); m_options.add_metadata = file.is_not_false("add_metadata");
m_options.use_color = file.is_true("color"); m_options.use_color = file.is_true("color");
@ -576,7 +577,7 @@ namespace osmium {
} }
void write_buffer(osmium::memory::Buffer&& buffer) final { void write_buffer(osmium::memory::Buffer&& buffer) final {
m_output_queue.push(osmium::thread::Pool::instance().submit(DebugOutputBlock{std::move(buffer), m_options})); m_output_queue.push(m_pool.submit(DebugOutputBlock{std::move(buffer), m_options}));
} }
}; // class DebugOutputFormat }; // class DebugOutputFormat
@ -584,8 +585,8 @@ namespace osmium {
// we want the register_output_format() function to run, setting // we want the register_output_format() function to run, setting
// the variable is only a side-effect, it will never be used // the variable is only a side-effect, it will never be used
const bool registered_debug_output = osmium::io::detail::OutputFormatFactory::instance().register_output_format(osmium::io::file_format::debug, const bool registered_debug_output = osmium::io::detail::OutputFormatFactory::instance().register_output_format(osmium::io::file_format::debug,
[](const osmium::io::File& file, future_string_queue_type& output_queue) { [](osmium::thread::Pool& pool, const osmium::io::File& file, future_string_queue_type& output_queue) {
return new osmium::io::detail::DebugOutputFormat(file, output_queue); return new osmium::io::detail::DebugOutputFormat(pool, file, output_queue);
}); });
// dummy function to silence the unused variable warning from above // dummy function to silence the unused variable warning from above

View File

@ -48,6 +48,7 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/io/header.hpp> #include <osmium/io/header.hpp>
#include <osmium/memory/buffer.hpp> #include <osmium/memory/buffer.hpp>
#include <osmium/osm/entity_bits.hpp> #include <osmium/osm/entity_bits.hpp>
#include <osmium/thread/pool.hpp>
namespace osmium { namespace osmium {
@ -55,35 +56,37 @@ namespace osmium {
namespace detail { namespace detail {
struct reader_options { struct parser_arguments {
osmium::osm_entity_bits::type read_which_entities = osm_entity_bits::all; osmium::thread::Pool& pool;
osmium::io::read_meta read_metadata = read_meta::yes; future_string_queue_type& input_queue;
future_buffer_queue_type& output_queue;
std::promise<osmium::io::Header>& header_promise;
osmium::osm_entity_bits::type read_which_entities;
osmium::io::read_meta read_metadata;
}; };
class Parser { class Parser {
osmium::thread::Pool& m_pool;
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;
reader_options m_options; osmium::osm_entity_bits::type m_read_which_entities;
osmium::io::read_meta m_read_metadata;
bool m_header_is_done; bool m_header_is_done;
protected: protected:
std::string get_input() { osmium::thread::Pool& get_pool() {
return m_input_queue.pop(); return m_pool;
}
bool input_done() const {
return m_input_queue.has_reached_end_of_data();
} }
osmium::osm_entity_bits::type read_types() const noexcept { osmium::osm_entity_bits::type read_types() const noexcept {
return m_options.read_which_entities; return m_read_which_entities;
} }
osmium::io::read_meta read_metadata() const noexcept { osmium::io::read_meta read_metadata() const noexcept {
return m_options.read_metadata; return m_read_metadata;
} }
bool header_is_done() const noexcept { bool header_is_done() const noexcept {
@ -117,14 +120,13 @@ namespace osmium {
public: public:
Parser(future_string_queue_type& input_queue, explicit Parser(parser_arguments& args) :
future_buffer_queue_type& output_queue, m_pool(args.pool),
std::promise<osmium::io::Header>& header_promise, m_output_queue(args.output_queue),
osmium::io::detail::reader_options options) : m_header_promise(args.header_promise),
m_output_queue(output_queue), m_input_queue(args.input_queue),
m_header_promise(header_promise), m_read_which_entities(args.read_which_entities),
m_input_queue(input_queue), m_read_metadata(args.read_metadata),
m_options(options),
m_header_is_done(false) { m_header_is_done(false) {
} }
@ -138,6 +140,14 @@ namespace osmium {
virtual void run() = 0; virtual void run() = 0;
std::string get_input() {
return m_input_queue.pop();
}
bool input_done() const {
return m_input_queue.has_reached_end_of_data();
}
void parse() { void parse() {
try { try {
run(); run();
@ -163,10 +173,7 @@ namespace osmium {
public: public:
using create_parser_type = std::function<std::unique_ptr<Parser>(future_string_queue_type&, using create_parser_type = std::function<std::unique_ptr<Parser>(parser_arguments&)>;
future_buffer_queue_type&,
std::promise<osmium::io::Header>& header_promise,
osmium::io::detail::reader_options options)>;
private: private:
@ -185,22 +192,20 @@ namespace osmium {
return factory; return factory;
} }
bool register_parser(osmium::io::file_format format, create_parser_type create_function) { bool register_parser(osmium::io::file_format format, create_parser_type&& create_function) {
if (! m_callbacks.insert(map_type::value_type(format, create_function)).second) { const auto result = m_callbacks.emplace(format, std::forward<create_parser_type>(create_function));
return false; return result.second;
}
return true;
} }
create_parser_type get_creator_function(const osmium::io::File& file) { create_parser_type get_creator_function(const osmium::io::File& file) const {
auto it = m_callbacks.find(file.format()); const auto it = m_callbacks.find(file.format());
if (it == m_callbacks.end()) { if (it == m_callbacks.end()) {
throw unsupported_file_format_error( throw unsupported_file_format_error{
std::string("Can not open file '") + std::string{"Can not open file '"} +
file.filename() + file.filename() +
"' with type '" + "' with type '" +
as_string(file.format()) + as_string(file.format()) +
"'. No support for reading this format in this program."); "'. No support for reading this format in this program."};
} }
return it->second; return it->second;
} }

View File

@ -121,7 +121,7 @@ namespace osmium {
current_entry = 0; current_entry = 0;
} }
void add(const char* string, size_t size) { void add(const char* string, std::size_t size) {
if (m_table.empty()) { if (m_table.empty()) {
m_table.resize(entry_size * number_of_entries); m_table.resize(entry_size * number_of_entries);
} }
@ -162,7 +162,7 @@ namespace osmium {
return protozero::decode_zigzag64(protozero::decode_varint(data, end)); return protozero::decode_zigzag64(protozero::decode_varint(data, end));
} }
bool ensure_bytes_available(size_t need_bytes) { bool ensure_bytes_available(std::size_t need_bytes) {
if ((m_end - m_data) >= long(need_bytes)) { if ((m_end - m_data) >= long(need_bytes)) {
return true; return true;
} }
@ -174,7 +174,7 @@ namespace osmium {
m_input.erase(0, m_data - m_input.data()); m_input.erase(0, m_data - m_input.data());
while (m_input.size() < need_bytes) { while (m_input.size() < need_bytes) {
std::string data = get_input(); const std::string data{get_input()};
if (input_done()) { if (input_done()) {
return false; return false;
} }
@ -589,11 +589,8 @@ namespace osmium {
public: public:
O5mParser(future_string_queue_type& input_queue, explicit O5mParser(parser_arguments& args) :
future_buffer_queue_type& output_queue, Parser(args),
std::promise<osmium::io::Header>& header_promise,
osmium::io::detail::reader_options options) :
Parser(input_queue, output_queue, header_promise, options),
m_header(), m_header(),
m_buffer(buffer_size), m_buffer(buffer_size),
m_input(), m_input(),
@ -616,11 +613,8 @@ namespace osmium {
// the variable is only a side-effect, it will never be used // the variable is only a side-effect, it will never be used
const bool registered_o5m_parser = ParserFactory::instance().register_parser( const bool registered_o5m_parser = ParserFactory::instance().register_parser(
file_format::o5m, file_format::o5m,
[](future_string_queue_type& input_queue, [](parser_arguments& args) {
future_buffer_queue_type& output_queue, return std::unique_ptr<Parser>(new O5mParser{args});
std::promise<osmium::io::Header>& header_promise,
osmium::io::detail::reader_options options) {
return std::unique_ptr<Parser>(new O5mParser(input_queue, output_queue, header_promise, options));
}); });
// dummy function to silence the unused variable warning from above // dummy function to silence the unused variable warning from above

View File

@ -33,19 +33,16 @@ DEALINGS IN THE SOFTWARE.
*/ */
#include <cstdlib> #include <cstdint>
#include <future>
#include <memory> #include <memory>
#include <string> #include <string>
#include <utility> #include <utility>
#include <osmium/io/detail/input_format.hpp> #include <osmium/io/detail/input_format.hpp>
#include <osmium/io/detail/opl_parser_functions.hpp> #include <osmium/io/detail/opl_parser_functions.hpp>
#include <osmium/io/detail/queue_util.hpp>
#include <osmium/io/file_format.hpp> #include <osmium/io/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/entity_bits.hpp>
#include <osmium/thread/util.hpp> #include <osmium/thread/util.hpp>
namespace osmium { namespace osmium {
@ -54,10 +51,56 @@ namespace osmium {
namespace detail { namespace detail {
// Feed data coming in blocks line by line to the OPL parser
// function. This has been broken out of the OPLParser class
// where it belongs into a standalone template function to be
// better testable.
template <typename T>
void line_by_line(T& worker) {
std::string rest;
while (!worker.input_done()) {
std::string input{worker.get_input()};
std::string::size_type ppos = 0;
if (!rest.empty()) {
ppos = input.find_first_of("\n\r");
if (ppos == std::string::npos) {
rest.append(input);
continue;
}
rest.append(input, 0, ppos);
if (!rest.empty()) {
worker.parse_line(rest.data());
rest.clear();
}
++ppos;
}
for (auto pos = input.find_first_of("\n\r", ppos);
pos != std::string::npos;
pos = input.find_first_of("\n\r", ppos)) {
const char* data = &input[ppos];
input[pos] = '\0';
if (data[0] != '\0') {
worker.parse_line(data);
}
ppos = pos + 1;
if (ppos >= input.size()) {
break;
}
}
rest.assign(input, ppos, std::string::npos);
}
if (!rest.empty()) {
worker.parse_line(rest.data());
}
}
class OPLParser : public Parser { class OPLParser : public Parser {
osmium::memory::Buffer m_buffer{1024*1024}; osmium::memory::Buffer m_buffer{1024*1024};
const char* m_data = nullptr;
uint64_t m_line_count = 0; uint64_t m_line_count = 0;
void maybe_flush() { void maybe_flush() {
@ -70,63 +113,26 @@ namespace osmium {
} }
} }
void parse_line() {
if (opl_parse_line(m_line_count, m_data, m_buffer, read_types())) {
maybe_flush();
}
++m_line_count;
}
public: public:
OPLParser(future_string_queue_type& input_queue, explicit OPLParser(parser_arguments& args) :
future_buffer_queue_type& output_queue, Parser(args) {
std::promise<osmium::io::Header>& header_promise,
osmium::io::detail::reader_options options) :
Parser(input_queue, output_queue, header_promise, options) {
set_header_value(osmium::io::Header{}); set_header_value(osmium::io::Header{});
} }
~OPLParser() noexcept final = default; ~OPLParser() noexcept final = default;
void parse_line(const char* data) {
if (opl_parse_line(m_line_count, data, m_buffer, read_types())) {
maybe_flush();
}
++m_line_count;
}
void run() final { void run() final {
osmium::thread::set_thread_name("_osmium_opl_in"); osmium::thread::set_thread_name("_osmium_opl_in");
std::string rest; line_by_line(*this);
while (!input_done()) {
std::string input = get_input();
std::string::size_type ppos = 0;
if (!rest.empty()) {
ppos = input.find('\n');
if (ppos == std::string::npos) {
rest.append(input);
continue;
}
rest.append(input.substr(0, ppos));
m_data = rest.data();
parse_line();
rest.clear();
}
std::string::size_type pos = input.find('\n', ppos);
while (pos != std::string::npos) {
m_data = &input[ppos];
input[pos] = '\0';
parse_line();
ppos = pos + 1;
if (ppos >= input.size()) {
break;
}
pos = input.find('\n', ppos);
}
rest = input.substr(ppos);
}
if (!rest.empty()) {
m_data = rest.data();
parse_line();
}
if (m_buffer.committed() > 0) { if (m_buffer.committed() > 0) {
send_to_output_queue(std::move(m_buffer)); send_to_output_queue(std::move(m_buffer));
@ -139,11 +145,8 @@ namespace osmium {
// the variable is only a side-effect, it will never be used // the variable is only a side-effect, it will never be used
const bool registered_opl_parser = ParserFactory::instance().register_parser( const bool registered_opl_parser = ParserFactory::instance().register_parser(
file_format::opl, file_format::opl,
[](future_string_queue_type& input_queue, [](parser_arguments& args) {
future_buffer_queue_type& output_queue, return std::unique_ptr<Parser>(new OPLParser{args});
std::promise<osmium::io::Header>& header_promise,
osmium::io::detail::reader_options options) {
return std::unique_ptr<Parser>(new OPLParser(input_queue, output_queue, header_promise, options));
}); });
// dummy function to silence the unused variable warning from above // dummy function to silence the unused variable warning from above

View File

@ -141,14 +141,15 @@ namespace osmium {
} }
void write_location(const osmium::Location& location, const char x, const char y) { void write_location(const osmium::Location& location, const char x, const char y) {
const bool not_undefined = !location.is_undefined();
*m_out += ' '; *m_out += ' ';
*m_out += x; *m_out += x;
if (location) { if (not_undefined) {
osmium::detail::append_location_coordinate_to_string(std::back_inserter(*m_out), location.x()); osmium::detail::append_location_coordinate_to_string(std::back_inserter(*m_out), location.x());
} }
*m_out += ' '; *m_out += ' ';
*m_out += y; *m_out += y;
if (location) { if (not_undefined) {
osmium::detail::append_location_coordinate_to_string(std::back_inserter(*m_out), location.y()); osmium::detail::append_location_coordinate_to_string(std::back_inserter(*m_out), location.y());
} }
} }
@ -283,8 +284,8 @@ namespace osmium {
public: public:
OPLOutputFormat(const osmium::io::File& file, future_string_queue_type& output_queue) : OPLOutputFormat(osmium::thread::Pool& pool, const osmium::io::File& file, future_string_queue_type& output_queue) :
OutputFormat(output_queue), OutputFormat(pool, output_queue),
m_options() { m_options() {
m_options.add_metadata = file.is_not_false("add_metadata"); m_options.add_metadata = file.is_not_false("add_metadata");
m_options.locations_on_ways = file.is_true("locations_on_ways"); m_options.locations_on_ways = file.is_true("locations_on_ways");
@ -297,7 +298,7 @@ namespace osmium {
~OPLOutputFormat() noexcept final = default; ~OPLOutputFormat() noexcept final = default;
void write_buffer(osmium::memory::Buffer&& buffer) final { void write_buffer(osmium::memory::Buffer&& buffer) final {
m_output_queue.push(osmium::thread::Pool::instance().submit(OPLOutputBlock{std::move(buffer), m_options})); m_output_queue.push(m_pool.submit(OPLOutputBlock{std::move(buffer), m_options}));
} }
}; // class OPLOutputFormat }; // class OPLOutputFormat
@ -305,8 +306,8 @@ namespace osmium {
// we want the register_output_format() function to run, setting // we want the register_output_format() function to run, setting
// the variable is only a side-effect, it will never be used // the variable is only a side-effect, it will never be used
const bool registered_opl_output = osmium::io::detail::OutputFormatFactory::instance().register_output_format(osmium::io::file_format::opl, const bool registered_opl_output = osmium::io::detail::OutputFormatFactory::instance().register_output_format(osmium::io::file_format::opl,
[](const osmium::io::File& file, future_string_queue_type& output_queue) { [](osmium::thread::Pool& pool, const osmium::io::File& file, future_string_queue_type& output_queue) {
return new osmium::io::detail::OPLOutputFormat(file, output_queue); return new osmium::io::detail::OPLOutputFormat(pool, file, output_queue);
}); });
// dummy function to silence the unused variable warning from above // dummy function to silence the unused variable warning from above

View File

@ -81,7 +81,7 @@ namespace osmium {
} }
explicit opl_error(const char* what, const char* d = nullptr) : explicit opl_error(const char* what, const char* d = nullptr) :
io_error(std::string("OPL error: ") + what), io_error(std::string{"OPL error: "} + what),
data(d), data(d),
msg("OPL error: ") { msg("OPL error: ") {
msg.append(what); msg.append(what);
@ -291,7 +291,7 @@ namespace osmium {
++*data; ++*data;
return; return;
} }
std::string msg = "expected '"; std::string msg{"expected '"};
msg += c; msg += c;
msg += "'"; msg += "'";
throw opl_error{msg, *data}; throw opl_error{msg, *data};
@ -599,8 +599,7 @@ namespace osmium {
const char* tags_begin = nullptr; const char* tags_begin = nullptr;
osmium::Location location1; osmium::Box box;
osmium::Location location2;
std::string user; std::string user;
while (**data) { while (**data) {
opl_parse_space(data); opl_parse_space(data);
@ -630,22 +629,22 @@ namespace osmium {
break; break;
case 'x': case 'x':
if (opl_non_empty(*data)) { if (opl_non_empty(*data)) {
location1.set_lon_partial(data); box.bottom_left().set_lon_partial(data);
} }
break; break;
case 'y': case 'y':
if (opl_non_empty(*data)) { if (opl_non_empty(*data)) {
location1.set_lat_partial(data); box.bottom_left().set_lat_partial(data);
} }
break; break;
case 'X': case 'X':
if (opl_non_empty(*data)) { if (opl_non_empty(*data)) {
location2.set_lon_partial(data); box.top_right().set_lon_partial(data);
} }
break; break;
case 'Y': case 'Y':
if (opl_non_empty(*data)) { if (opl_non_empty(*data)) {
location2.set_lat_partial(data); box.top_right().set_lat_partial(data);
} }
break; break;
case 'T': case 'T':
@ -661,13 +660,7 @@ namespace osmium {
} }
if (location1.valid() && location2.valid()) {
osmium::Box box;
box.extend(location1);
box.extend(location2);
builder.set_bounds(box); builder.set_bounds(box);
}
builder.set_user(user); builder.set_user(user);
if (tags_begin) { if (tags_begin) {

View File

@ -46,6 +46,7 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/io/file.hpp> #include <osmium/io/file.hpp>
#include <osmium/io/file_format.hpp> #include <osmium/io/file_format.hpp>
#include <osmium/memory/buffer.hpp> #include <osmium/memory/buffer.hpp>
#include <osmium/thread/pool.hpp>
namespace osmium { namespace osmium {
@ -107,6 +108,7 @@ namespace osmium {
protected: protected:
osmium::thread::Pool& m_pool;
future_string_queue_type& m_output_queue; future_string_queue_type& m_output_queue;
/** /**
@ -119,7 +121,8 @@ namespace osmium {
public: public:
explicit OutputFormat(future_string_queue_type& output_queue) : OutputFormat(osmium::thread::Pool& pool, future_string_queue_type& output_queue) :
m_pool(pool),
m_output_queue(output_queue) { m_output_queue(output_queue) {
} }
@ -152,7 +155,7 @@ namespace osmium {
public: public:
using create_output_type = std::function<osmium::io::detail::OutputFormat*(const osmium::io::File&, future_string_queue_type&)>; using create_output_type = std::function<osmium::io::detail::OutputFormat*(osmium::thread::Pool&, const osmium::io::File&, future_string_queue_type&)>;
private: private:
@ -178,22 +181,52 @@ namespace osmium {
return true; return true;
} }
std::unique_ptr<osmium::io::detail::OutputFormat> create_output(const osmium::io::File& file, future_string_queue_type& output_queue) { std::unique_ptr<osmium::io::detail::OutputFormat> create_output(osmium::thread::Pool& pool, const osmium::io::File& file, future_string_queue_type& output_queue) {
auto it = m_callbacks.find(file.format()); const auto it = m_callbacks.find(file.format());
if (it != m_callbacks.end()) { if (it != m_callbacks.end()) {
return std::unique_ptr<osmium::io::detail::OutputFormat>((it->second)(file, output_queue)); return std::unique_ptr<osmium::io::detail::OutputFormat>((it->second)(pool, file, output_queue));
} }
throw unsupported_file_format_error( throw unsupported_file_format_error{
std::string("Can not open file '") + std::string{"Can not open file '"} +
file.filename() + file.filename() +
"' with type '" + "' with type '" +
as_string(file.format()) + as_string(file.format()) +
"'. No support for writing this format in this program."); "'. No support for writing this format in this program."};
} }
}; // class OutputFormatFactory }; // class OutputFormatFactory
class BlackholeOutputFormat : public osmium::io::detail::OutputFormat {
public:
BlackholeOutputFormat(osmium::thread::Pool& pool, const osmium::io::File& /*file*/, future_string_queue_type& output_queue) :
OutputFormat(pool, output_queue) {
}
BlackholeOutputFormat(const BlackholeOutputFormat&) = delete;
BlackholeOutputFormat& operator=(const BlackholeOutputFormat&) = delete;
~BlackholeOutputFormat() noexcept final = default;
void write_buffer(osmium::memory::Buffer&& /*buffer*/) final {
}
}; // class BlackholeOutputFormat
// we want the register_output_format() function to run, setting
// the variable is only a side-effect, it will never be used
const bool registered_blackhole_output = osmium::io::detail::OutputFormatFactory::instance().register_output_format(osmium::io::file_format::blackhole,
[](osmium::thread::Pool& pool, const osmium::io::File& file, future_string_queue_type& output_queue) {
return new osmium::io::detail::BlackholeOutputFormat(pool, file, output_queue);
});
// dummy function to silence the unused variable warning from above
inline bool get_registered_blackhole_output() noexcept {
return registered_blackhole_output;
}
} // namespace detail } // namespace detail
} // namespace io } // namespace io

View File

@ -99,21 +99,21 @@ namespace osmium {
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"};
} }
protozero::pbf_message<OSMFormat::StringTable> pbf_string_table(data); protozero::pbf_message<OSMFormat::StringTable> pbf_string_table{data};
while (pbf_string_table.next(OSMFormat::StringTable::repeated_bytes_s)) { while (pbf_string_table.next(OSMFormat::StringTable::repeated_bytes_s)) {
const auto str_view = pbf_string_table.get_view(); const auto str_view = pbf_string_table.get_view();
if (str_view.size() > osmium::max_osm_string_length) { if (str_view.size() > osmium::max_osm_string_length) {
throw osmium::pbf_error("overlong string in string table"); throw osmium::pbf_error{"overlong string in string table"};
} }
m_stringtable.emplace_back(str_view.data(), osmium::string_size_type(str_view.size())); m_stringtable.emplace_back(str_view.data(), osmium::string_size_type(str_view.size()));
} }
} }
void decode_primitive_block_metadata() { void decode_primitive_block_metadata() {
protozero::pbf_message<OSMFormat::PrimitiveBlock> pbf_primitive_block(m_data); protozero::pbf_message<OSMFormat::PrimitiveBlock> pbf_primitive_block{m_data};
while (pbf_primitive_block.next()) { while (pbf_primitive_block.next()) {
switch (pbf_primitive_block.tag()) { switch (pbf_primitive_block.tag()) {
case OSMFormat::PrimitiveBlock::required_StringTable_stringtable: case OSMFormat::PrimitiveBlock::required_StringTable_stringtable:
@ -138,7 +138,7 @@ namespace osmium {
} }
void decode_primitive_block_data() { void decode_primitive_block_data() {
protozero::pbf_message<OSMFormat::PrimitiveBlock> pbf_primitive_block(m_data); protozero::pbf_message<OSMFormat::PrimitiveBlock> pbf_primitive_block{m_data};
while (pbf_primitive_block.next(OSMFormat::PrimitiveBlock::repeated_PrimitiveGroup_primitivegroup)) { while (pbf_primitive_block.next(OSMFormat::PrimitiveBlock::repeated_PrimitiveGroup_primitivegroup)) {
protozero::pbf_message<OSMFormat::PrimitiveGroup> pbf_primitive_group = pbf_primitive_block.get_message(); protozero::pbf_message<OSMFormat::PrimitiveGroup> pbf_primitive_group = pbf_primitive_block.get_message();
while (pbf_primitive_group.next()) { while (pbf_primitive_group.next()) {
@ -187,16 +187,16 @@ namespace osmium {
} }
osm_string_len_type decode_info(const data_view& data, osmium::OSMObject& object) { osm_string_len_type decode_info(const data_view& data, osmium::OSMObject& object) {
osm_string_len_type user = std::make_pair("", 0); osm_string_len_type user{"", 0};
protozero::pbf_message<OSMFormat::Info> pbf_info(data); protozero::pbf_message<OSMFormat::Info> pbf_info{data};
while (pbf_info.next()) { while (pbf_info.next()) {
switch (pbf_info.tag()) { switch (pbf_info.tag()) {
case OSMFormat::Info::optional_int32_version: case OSMFormat::Info::optional_int32_version:
{ {
const auto version = pbf_info.get_int32(); const auto version = pbf_info.get_int32();
if (version < 0) { if (version < 0) {
throw osmium::pbf_error("object version must not be negative"); throw osmium::pbf_error{"object version must not be negative"};
} }
object.set_version(static_cast_with_assert<object_version_type>(version)); object.set_version(static_cast_with_assert<object_version_type>(version));
} }
@ -208,7 +208,7 @@ namespace osmium {
{ {
const auto changeset_id = pbf_info.get_int64(); const auto changeset_id = pbf_info.get_int64();
if (changeset_id < 0) { if (changeset_id < 0) {
throw osmium::pbf_error("object changeset_id must not be negative"); throw osmium::pbf_error{"object changeset_id must not be negative"};
} }
object.set_changeset(static_cast_with_assert<changeset_id_type>(changeset_id)); object.set_changeset(static_cast_with_assert<changeset_id_type>(changeset_id));
} }
@ -240,7 +240,7 @@ namespace osmium {
while (kit != keys.end()) { while (kit != keys.end()) {
if (vit == vals.end()) { if (vit == vals.end()) {
// this is against the spec, must have same number of elements // this is against the spec, must have same number of elements
throw osmium::pbf_error("PBF format error"); throw osmium::pbf_error{"PBF format error"};
} }
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++);
@ -262,9 +262,9 @@ namespace osmium {
int64_t lon = std::numeric_limits<int64_t>::max(); int64_t lon = std::numeric_limits<int64_t>::max();
int64_t lat = std::numeric_limits<int64_t>::max(); int64_t lat = std::numeric_limits<int64_t>::max();
osm_string_len_type user = { "", 0 }; osm_string_len_type user{"", 0};
protozero::pbf_message<OSMFormat::Node> pbf_node(data); protozero::pbf_message<OSMFormat::Node> pbf_node{data};
while (pbf_node.next()) { while (pbf_node.next()) {
switch (pbf_node.tag()) { switch (pbf_node.tag()) {
case OSMFormat::Node::required_sint64_id: case OSMFormat::Node::required_sint64_id:
@ -297,12 +297,12 @@ namespace osmium {
if (node.visible()) { if (node.visible()) {
if (lon == std::numeric_limits<int64_t>::max() || if (lon == std::numeric_limits<int64_t>::max() ||
lat == std::numeric_limits<int64_t>::max()) { lat == std::numeric_limits<int64_t>::max()) {
throw osmium::pbf_error("illegal coordinate format"); throw osmium::pbf_error{"illegal coordinate format"};
} }
node.set_location(osmium::Location( node.set_location(osmium::Location{
convert_pbf_coordinate(lon), convert_pbf_coordinate(lon),
convert_pbf_coordinate(lat) convert_pbf_coordinate(lat)
)); });
} }
builder.set_user(user.first, user.second); builder.set_user(user.first, user.second);
@ -319,9 +319,9 @@ namespace osmium {
protozero::iterator_range<protozero::pbf_reader::const_sint64_iterator> lats; protozero::iterator_range<protozero::pbf_reader::const_sint64_iterator> lats;
protozero::iterator_range<protozero::pbf_reader::const_sint64_iterator> lons; protozero::iterator_range<protozero::pbf_reader::const_sint64_iterator> lons;
osm_string_len_type user = { "", 0 }; osm_string_len_type user{"", 0};
protozero::pbf_message<OSMFormat::Way> pbf_way(data); protozero::pbf_message<OSMFormat::Way> pbf_way{data};
while (pbf_way.next()) { while (pbf_way.next()) {
switch (pbf_way.tag()) { switch (pbf_way.tag()) {
case OSMFormat::Way::required_int64_id: case OSMFormat::Way::required_int64_id:
@ -391,9 +391,9 @@ namespace osmium {
protozero::iterator_range<protozero::pbf_reader::const_sint64_iterator> refs; protozero::iterator_range<protozero::pbf_reader::const_sint64_iterator> refs;
protozero::iterator_range<protozero::pbf_reader::const_int32_iterator> types; protozero::iterator_range<protozero::pbf_reader::const_int32_iterator> types;
osm_string_len_type user = { "", 0 }; osm_string_len_type user{"", 0};
protozero::pbf_message<OSMFormat::Relation> pbf_relation(data); protozero::pbf_message<OSMFormat::Relation> pbf_relation{data};
while (pbf_relation.next()) { while (pbf_relation.next()) {
switch (pbf_relation.tag()) { switch (pbf_relation.tag()) {
case OSMFormat::Relation::required_int64_id: case OSMFormat::Relation::required_int64_id:
@ -435,7 +435,7 @@ namespace osmium {
const auto& r = m_stringtable.at(roles.front()); const auto& r = m_stringtable.at(roles.front());
const int type = types.front(); const int type = types.front();
if (type < 0 || type > 2) { if (type < 0 || type > 2) {
throw osmium::pbf_error("unknown relation member type"); throw osmium::pbf_error{"unknown relation member type"};
} }
rml_builder.add_member( rml_builder.add_member(
osmium::item_type(type + 1), osmium::item_type(type + 1),
@ -457,7 +457,7 @@ namespace osmium {
while (it != last && *it != 0) { while (it != last && *it != 0) {
const auto& k = m_stringtable.at(*it++); const auto& k = m_stringtable.at(*it++);
if (it == last) { if (it == last) {
throw osmium::pbf_error("PBF format error"); // this is against the spec, keys/vals must come in pairs throw osmium::pbf_error{"PBF format error"}; // this is against the spec, keys/vals must come in pairs
} }
const auto& v = m_stringtable.at(*it++); const auto& v = m_stringtable.at(*it++);
tl_builder.add_tag(k.first, k.second, v.first, v.second); tl_builder.add_tag(k.first, k.second, v.first, v.second);
@ -475,7 +475,7 @@ namespace osmium {
protozero::iterator_range<protozero::pbf_reader::const_int32_iterator> tags; protozero::iterator_range<protozero::pbf_reader::const_int32_iterator> tags;
protozero::pbf_message<OSMFormat::DenseNodes> pbf_dense_nodes(data); protozero::pbf_message<OSMFormat::DenseNodes> pbf_dense_nodes{data};
while (pbf_dense_nodes.next()) { while (pbf_dense_nodes.next()) {
switch (pbf_dense_nodes.tag()) { switch (pbf_dense_nodes.tag()) {
case OSMFormat::DenseNodes::packed_sint64_id: case OSMFormat::DenseNodes::packed_sint64_id:
@ -505,7 +505,7 @@ namespace osmium {
if (lons.empty() || if (lons.empty() ||
lats.empty()) { lats.empty()) {
// this is against the spec, must have same number of elements // this is against the spec, must have same number of elements
throw osmium::pbf_error("PBF format error"); throw osmium::pbf_error{"PBF format error"};
} }
osmium::builder::NodeBuilder builder{m_buffer}; osmium::builder::NodeBuilder builder{m_buffer};
@ -547,7 +547,7 @@ namespace osmium {
protozero::iterator_range<protozero::pbf_reader::const_sint32_iterator> user_sids; protozero::iterator_range<protozero::pbf_reader::const_sint32_iterator> user_sids;
protozero::iterator_range<protozero::pbf_reader::const_int32_iterator> visibles; protozero::iterator_range<protozero::pbf_reader::const_int32_iterator> visibles;
protozero::pbf_message<OSMFormat::DenseNodes> pbf_dense_nodes(data); protozero::pbf_message<OSMFormat::DenseNodes> pbf_dense_nodes{data};
while (pbf_dense_nodes.next()) { while (pbf_dense_nodes.next()) {
switch (pbf_dense_nodes.tag()) { switch (pbf_dense_nodes.tag()) {
case OSMFormat::DenseNodes::packed_sint64_id: case OSMFormat::DenseNodes::packed_sint64_id:
@ -556,7 +556,7 @@ namespace osmium {
case OSMFormat::DenseNodes::optional_DenseInfo_denseinfo: case OSMFormat::DenseNodes::optional_DenseInfo_denseinfo:
{ {
has_info = true; has_info = true;
protozero::pbf_message<OSMFormat::DenseInfo> pbf_dense_info = pbf_dense_nodes.get_message(); protozero::pbf_message<OSMFormat::DenseInfo> pbf_dense_info{pbf_dense_nodes.get_message()};
while (pbf_dense_info.next()) { while (pbf_dense_info.next()) {
switch (pbf_dense_info.tag()) { switch (pbf_dense_info.tag()) {
case OSMFormat::DenseInfo::packed_int32_version: case OSMFormat::DenseInfo::packed_int32_version:
@ -612,7 +612,7 @@ namespace osmium {
if (lons.empty() || if (lons.empty() ||
lats.empty()) { lats.empty()) {
// this is against the spec, must have same number of elements // this is against the spec, must have same number of elements
throw osmium::pbf_error("PBF format error"); throw osmium::pbf_error{"PBF format error"};
} }
bool visible = true; bool visible = true;
@ -630,20 +630,20 @@ namespace osmium {
uids.empty() || uids.empty() ||
user_sids.empty()) { user_sids.empty()) {
// this is against the spec, must have same number of elements // this is against the spec, must have same number of elements
throw osmium::pbf_error("PBF format error"); throw osmium::pbf_error{"PBF format error"};
} }
const auto version = versions.front(); const auto version = versions.front();
versions.drop_front(); versions.drop_front();
if (version < 0) { if (version < 0) {
throw osmium::pbf_error("object version must not be negative"); throw osmium::pbf_error{"object version must not be negative"};
} }
node.set_version(static_cast<osmium::object_version_type>(version)); node.set_version(static_cast<osmium::object_version_type>(version));
const auto changeset_id = dense_changeset.update(changesets.front()); const auto changeset_id = dense_changeset.update(changesets.front());
changesets.drop_front(); changesets.drop_front();
if (changeset_id < 0) { if (changeset_id < 0) {
throw osmium::pbf_error("object changeset_id must not be negative"); throw osmium::pbf_error{"object changeset_id must not be negative"};
} }
node.set_changeset(static_cast<osmium::changeset_id_type>(changeset_id)); node.set_changeset(static_cast<osmium::changeset_id_type>(changeset_id));
@ -655,7 +655,7 @@ namespace osmium {
if (has_visibles) { if (has_visibles) {
if (visibles.empty()) { if (visibles.empty()) {
// this is against the spec, must have same number of elements // this is against the spec, must have same number of elements
throw osmium::pbf_error("PBF format error"); throw osmium::pbf_error{"PBF format error"};
} }
visible = (visibles.front() != 0); visible = (visibles.front() != 0);
visibles.drop_front(); visibles.drop_front();
@ -674,10 +674,10 @@ namespace osmium {
const auto lat = dense_latitude.update(lats.front()); const auto lat = dense_latitude.update(lats.front());
lats.drop_front(); lats.drop_front();
if (visible) { if (visible) {
builder.object().set_location(osmium::Location( builder.object().set_location(osmium::Location{
convert_pbf_coordinate(lon), convert_pbf_coordinate(lon),
convert_pbf_coordinate(lat) convert_pbf_coordinate(lat)
)); });
} }
if (tag_it != tags.end()) { if (tag_it != tags.end()) {
@ -708,7 +708,7 @@ namespace osmium {
decode_primitive_block_metadata(); decode_primitive_block_metadata();
decode_primitive_block_data(); decode_primitive_block_data();
} catch (const std::out_of_range&) { } catch (const std::out_of_range&) {
throw osmium::pbf_error("string id out of range"); throw osmium::pbf_error{"string id out of range"};
} }
return std::move(m_buffer); return std::move(m_buffer);
@ -720,30 +720,30 @@ namespace osmium {
int32_t raw_size = 0; int32_t raw_size = 0;
protozero::data_view zlib_data; protozero::data_view zlib_data;
protozero::pbf_message<FileFormat::Blob> pbf_blob(blob_data); protozero::pbf_message<FileFormat::Blob> pbf_blob{blob_data};
while (pbf_blob.next()) { while (pbf_blob.next()) {
switch (pbf_blob.tag()) { switch (pbf_blob.tag()) {
case FileFormat::Blob::optional_bytes_raw: case FileFormat::Blob::optional_bytes_raw:
{ {
auto data_len = pbf_blob.get_view(); const auto data_len = pbf_blob.get_view();
if (data_len.size() > max_uncompressed_blob_size) { if (data_len.size() > max_uncompressed_blob_size) {
throw osmium::pbf_error("illegal blob size"); throw osmium::pbf_error{"illegal blob size"};
} }
return data_len; return data_len;
} }
case FileFormat::Blob::optional_int32_raw_size: case FileFormat::Blob::optional_int32_raw_size:
raw_size = pbf_blob.get_int32(); raw_size = pbf_blob.get_int32();
if (raw_size <= 0 || uint32_t(raw_size) > max_uncompressed_blob_size) { if (raw_size <= 0 || uint32_t(raw_size) > max_uncompressed_blob_size) {
throw osmium::pbf_error("illegal blob size"); throw osmium::pbf_error{"illegal blob size"};
} }
break; break;
case FileFormat::Blob::optional_bytes_zlib_data: case FileFormat::Blob::optional_bytes_zlib_data:
zlib_data = pbf_blob.get_view(); zlib_data = pbf_blob.get_view();
break; break;
case FileFormat::Blob::optional_bytes_lzma_data: case FileFormat::Blob::optional_bytes_lzma_data:
throw osmium::pbf_error("lzma blobs not implemented"); throw osmium::pbf_error{"lzma blobs not implemented"};
default: default:
throw osmium::pbf_error("unknown compression"); throw osmium::pbf_error{"unknown compression"};
} }
} }
@ -756,7 +756,7 @@ namespace osmium {
); );
} }
throw osmium::pbf_error("blob contains no data"); throw osmium::pbf_error{"blob contains no data"};
} }
inline osmium::Box decode_header_bbox(const data_view& data) { inline osmium::Box decode_header_bbox(const data_view& data) {
@ -765,7 +765,7 @@ namespace osmium {
int64_t top = std::numeric_limits<int64_t>::max(); int64_t top = std::numeric_limits<int64_t>::max();
int64_t bottom = std::numeric_limits<int64_t>::max(); int64_t bottom = std::numeric_limits<int64_t>::max();
protozero::pbf_message<OSMFormat::HeaderBBox> pbf_header_bbox(data); protozero::pbf_message<OSMFormat::HeaderBBox> pbf_header_bbox{data};
while (pbf_header_bbox.next()) { while (pbf_header_bbox.next()) {
switch (pbf_header_bbox.tag()) { switch (pbf_header_bbox.tag()) {
case OSMFormat::HeaderBBox::required_sint64_left: case OSMFormat::HeaderBBox::required_sint64_left:
@ -789,7 +789,7 @@ namespace osmium {
right == std::numeric_limits<int64_t>::max() || right == std::numeric_limits<int64_t>::max() ||
top == std::numeric_limits<int64_t>::max() || top == std::numeric_limits<int64_t>::max() ||
bottom == std::numeric_limits<int64_t>::max()) { bottom == std::numeric_limits<int64_t>::max()) {
throw osmium::pbf_error("invalid bbox"); throw osmium::pbf_error{"invalid bbox"};
} }
osmium::Box box; osmium::Box box;
@ -803,7 +803,7 @@ namespace osmium {
osmium::io::Header header; osmium::io::Header header;
int i = 0; int i = 0;
protozero::pbf_message<OSMFormat::HeaderBlock> pbf_header_block(data); protozero::pbf_message<OSMFormat::HeaderBlock> pbf_header_block{data};
while (pbf_header_block.next()) { while (pbf_header_block.next()) {
switch (pbf_header_block.tag()) { switch (pbf_header_block.tag()) {
case OSMFormat::HeaderBlock::optional_HeaderBBox_bbox: case OSMFormat::HeaderBlock::optional_HeaderBBox_bbox:
@ -819,9 +819,9 @@ namespace osmium {
} else if (!std::strncmp("HistoricalInformation", feature.data(), feature.size())) { } else if (!std::strncmp("HistoricalInformation", feature.data(), feature.size())) {
header.set_has_multiple_object_versions(true); header.set_has_multiple_object_versions(true);
} else { } else {
std::string msg("required feature not supported: "); std::string msg{"required feature not supported: "};
msg.append(feature.data(), feature.size()); msg.append(feature.data(), feature.size());
throw osmium::pbf_error(msg); throw osmium::pbf_error{msg};
} }
} }
break; break;
@ -833,7 +833,7 @@ namespace osmium {
break; break;
case OSMFormat::HeaderBlock::optional_int64_osmosis_replication_timestamp: case OSMFormat::HeaderBlock::optional_int64_osmosis_replication_timestamp:
{ {
const auto timestamp = osmium::Timestamp(pbf_header_block.get_int64()).to_iso(); const auto timestamp = osmium::Timestamp{pbf_header_block.get_int64()}.to_iso();
header.set("osmosis_replication_timestamp", timestamp); header.set("osmosis_replication_timestamp", timestamp);
header.set("timestamp", timestamp); header.set("timestamp", timestamp);
} }
@ -889,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, m_read_metadata); PBFPrimitiveBlockDecoder decoder{decode_blob(*m_input_buffer, output), m_read_types, m_read_metadata};
return decoder(); return decoder();
} }

View File

@ -33,15 +33,14 @@ DEALINGS IN THE SOFTWARE.
*/ */
#include <algorithm>
#include <cassert> #include <cassert>
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
#include <cstring> #include <cstring>
#include <future>
#include <memory> #include <memory>
#include <string> #include <string>
#include <type_traits> #include <type_traits>
#include <utility>
#include <protozero/pbf_message.hpp> #include <protozero/pbf_message.hpp>
#include <protozero/types.hpp> #include <protozero/types.hpp>
@ -50,7 +49,6 @@ 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/pbf_decoder.hpp> #include <osmium/io/detail/pbf_decoder.hpp>
#include <osmium/io/detail/protobuf_tags.hpp> #include <osmium/io/detail/protobuf_tags.hpp>
#include <osmium/io/detail/queue_util.hpp>
#include <osmium/io/file_format.hpp> #include <osmium/io/file_format.hpp>
#include <osmium/io/header.hpp> #include <osmium/io/header.hpp>
#include <osmium/osm/entity_bits.hpp> #include <osmium/osm/entity_bits.hpp>
@ -77,14 +75,14 @@ namespace osmium {
*/ */
std::string read_from_input_queue(size_t size) { std::string read_from_input_queue(size_t size) {
while (m_input_buffer.size() < size) { while (m_input_buffer.size() < size) {
const std::string new_data = get_input(); const std::string new_data{get_input()};
if (input_done()) { if (input_done()) {
throw osmium::pbf_error("truncated data (EOF encountered)"); throw osmium::pbf_error{"truncated data (EOF encountered)"};
} }
m_input_buffer += new_data; m_input_buffer += new_data;
} }
std::string output { m_input_buffer.substr(size) }; std::string output{m_input_buffer.substr(size)};
m_input_buffer.resize(size); m_input_buffer.resize(size);
using std::swap; using std::swap;
@ -101,7 +99,7 @@ namespace osmium {
uint32_t size_in_network_byte_order; uint32_t size_in_network_byte_order;
try { try {
const std::string input_data = read_from_input_queue(sizeof(size_in_network_byte_order)); const std::string input_data{read_from_input_queue(sizeof(size_in_network_byte_order))};
size_in_network_byte_order = *reinterpret_cast<const uint32_t*>(input_data.data()); size_in_network_byte_order = *reinterpret_cast<const uint32_t*>(input_data.data());
} catch (const osmium::pbf_error&) { } catch (const osmium::pbf_error&) {
return 0; // EOF return 0; // EOF
@ -109,7 +107,7 @@ namespace osmium {
const uint32_t size = ntohl(size_in_network_byte_order); const uint32_t size = ntohl(size_in_network_byte_order);
if (size > static_cast<uint32_t>(max_blob_header_size)) { if (size > static_cast<uint32_t>(max_blob_header_size)) {
throw osmium::pbf_error("invalid BlobHeader size (> max_blob_header_size)"); throw osmium::pbf_error{"invalid BlobHeader size (> max_blob_header_size)"};
} }
return size; return size;
@ -137,11 +135,11 @@ namespace osmium {
} }
if (blob_header_datasize == 0) { if (blob_header_datasize == 0) {
throw osmium::pbf_error("PBF format error: BlobHeader.datasize missing or zero."); throw osmium::pbf_error{"PBF format error: BlobHeader.datasize missing or zero."};
} }
if (std::strncmp(expected_type, blob_header_type.data(), blob_header_type.size())) { if (std::strncmp(expected_type, blob_header_type.data(), blob_header_type.size())) {
throw osmium::pbf_error("blob does not have expected type (OSMHeader in first blob, OSMData in following blobs)"); throw osmium::pbf_error{"blob does not have expected type (OSMHeader in first blob, OSMData in following blobs)"};
} }
return blob_header_datasize; return blob_header_datasize;
@ -155,35 +153,34 @@ namespace osmium {
return 0; return 0;
} }
const std::string blob_header = read_from_input_queue(size); const std::string blob_header{read_from_input_queue(size)};
return decode_blob_header(protozero::pbf_message<FileFormat::BlobHeader>(blob_header), expected_type); return decode_blob_header(protozero::pbf_message<FileFormat::BlobHeader>(blob_header), expected_type);
} }
std::string read_from_input_queue_with_check(size_t size) { std::string read_from_input_queue_with_check(size_t size) {
if (size > max_uncompressed_blob_size) { if (size > max_uncompressed_blob_size) {
throw osmium::pbf_error(std::string("invalid blob size: " + throw osmium::pbf_error{std::string{"invalid blob size: "} +
std::to_string(size))); std::to_string(size)};
} }
return read_from_input_queue(size); return read_from_input_queue(size);
} }
// Parse the header in the PBF OSMHeader blob. // Parse the header in the PBF OSMHeader blob.
void parse_header_blob() { void parse_header_blob() {
osmium::io::Header header;
const auto size = check_type_and_get_blob_size("OSMHeader"); const auto size = check_type_and_get_blob_size("OSMHeader");
header = decode_header(read_from_input_queue_with_check(size)); osmium::io::Header header{decode_header(read_from_input_queue_with_check(size))};
set_header_value(header); set_header_value(header);
} }
void parse_data_blobs() { void parse_data_blobs() {
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(), read_metadata()}; 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(get_pool().submit(std::move(data_blob_parser)));
} else { } else {
send_to_output_queue(data_blob_parser()); send_to_output_queue(data_blob_parser());
} }
@ -192,11 +189,8 @@ namespace osmium {
public: public:
PBFParser(future_string_queue_type& input_queue, explicit PBFParser(parser_arguments& args) :
future_buffer_queue_type& output_queue, Parser(args),
std::promise<osmium::io::Header>& header_promise,
osmium::io::detail::reader_options options) :
Parser(input_queue, output_queue, header_promise, options),
m_input_buffer() { m_input_buffer() {
} }
@ -218,11 +212,8 @@ namespace osmium {
// the variable is only a side-effect, it will never be used // the variable is only a side-effect, it will never be used
const bool registered_pbf_parser = ParserFactory::instance().register_parser( const bool registered_pbf_parser = ParserFactory::instance().register_parser(
file_format::pbf, file_format::pbf,
[](future_string_queue_type& input_queue, [](parser_arguments& args) {
future_buffer_queue_type& output_queue, return std::unique_ptr<Parser>(new PBFParser{args});
std::promise<osmium::io::Header>& header_promise,
osmium::io::detail::reader_options options) {
return std::unique_ptr<Parser>(new PBFParser(input_queue, output_queue, header_promise, options));
}); });
// dummy function to silence the unused variable warning from above // dummy function to silence the unused variable warning from above

View File

@ -33,15 +33,14 @@ DEALINGS IN THE SOFTWARE.
*/ */
#include <algorithm>
#include <cassert> #include <cassert>
#include <cmath> #include <cmath>
#include <cstdint> #include <cstdint>
#include <cstdlib> #include <cstdlib>
#include <iterator>
#include <memory> #include <memory>
#include <string> #include <string>
#include <utility> #include <utility>
#include <vector>
#include <protozero/pbf_builder.hpp> #include <protozero/pbf_builder.hpp>
#include <protozero/pbf_writer.hpp> #include <protozero/pbf_writer.hpp>
@ -171,7 +170,7 @@ namespace osmium {
assert(m_msg.size() <= max_uncompressed_blob_size); assert(m_msg.size() <= max_uncompressed_blob_size);
std::string blob_data; std::string blob_data;
protozero::pbf_builder<FileFormat::Blob> pbf_blob(blob_data); protozero::pbf_builder<FileFormat::Blob> pbf_blob{blob_data};
if (m_use_compression) { if (m_use_compression) {
pbf_blob.add_int32(FileFormat::Blob::optional_int32_raw_size, int32_t(m_msg.size())); pbf_blob.add_int32(FileFormat::Blob::optional_int32_raw_size, int32_t(m_msg.size()));
@ -181,12 +180,12 @@ namespace osmium {
} }
std::string blob_header_data; std::string blob_header_data;
protozero::pbf_builder<FileFormat::BlobHeader> pbf_blob_header(blob_header_data); protozero::pbf_builder<FileFormat::BlobHeader> pbf_blob_header{blob_header_data};
pbf_blob_header.add_string(FileFormat::BlobHeader::required_string_type, m_blob_type == pbf_blob_type::data ? "OSMData" : "OSMHeader"); pbf_blob_header.add_string(FileFormat::BlobHeader::required_string_type, m_blob_type == pbf_blob_type::data ? "OSMData" : "OSMHeader");
pbf_blob_header.add_int32(FileFormat::BlobHeader::required_int32_datasize, static_cast_with_assert<int32_t>(blob_data.size())); pbf_blob_header.add_int32(FileFormat::BlobHeader::required_int32_datasize, static_cast_with_assert<int32_t>(blob_data.size()));
uint32_t sz = htonl(static_cast_with_assert<uint32_t>(blob_header_data.size())); const uint32_t sz = htonl(static_cast_with_assert<uint32_t>(blob_header_data.size()));
// write to output: the 4-byte BlobHeader-Size followed by the BlobHeader followed by the Blob // write to output: the 4-byte BlobHeader-Size followed by the BlobHeader followed by the Blob
std::string output; std::string output;
@ -270,7 +269,7 @@ namespace osmium {
m_delta_lon.clear(); m_delta_lon.clear();
} }
size_t size() const { std::size_t size() const {
return m_ids.size() * 3 * sizeof(int64_t); return m_ids.size() * 3 * sizeof(int64_t);
} }
@ -300,12 +299,12 @@ namespace osmium {
std::string serialize() const { std::string serialize() const {
std::string data; std::string data;
protozero::pbf_builder<OSMFormat::DenseNodes> pbf_dense_nodes(data); protozero::pbf_builder<OSMFormat::DenseNodes> pbf_dense_nodes{data};
pbf_dense_nodes.add_packed_sint64(OSMFormat::DenseNodes::packed_sint64_id, m_ids.cbegin(), m_ids.cend()); pbf_dense_nodes.add_packed_sint64(OSMFormat::DenseNodes::packed_sint64_id, m_ids.cbegin(), m_ids.cend());
if (m_options.add_metadata) { if (m_options.add_metadata) {
protozero::pbf_builder<OSMFormat::DenseInfo> pbf_dense_info(pbf_dense_nodes, OSMFormat::DenseNodes::optional_DenseInfo_denseinfo); protozero::pbf_builder<OSMFormat::DenseInfo> pbf_dense_info{pbf_dense_nodes, OSMFormat::DenseNodes::optional_DenseInfo_denseinfo};
pbf_dense_info.add_packed_int32(OSMFormat::DenseInfo::packed_int32_version, m_versions.cbegin(), m_versions.cend()); pbf_dense_info.add_packed_int32(OSMFormat::DenseInfo::packed_int32_version, m_versions.cbegin(), m_versions.cend());
pbf_dense_info.add_packed_sint64(OSMFormat::DenseInfo::packed_sint64_timestamp, m_timestamps.cbegin(), m_timestamps.cend()); pbf_dense_info.add_packed_sint64(OSMFormat::DenseInfo::packed_sint64_timestamp, m_timestamps.cbegin(), m_timestamps.cend());
pbf_dense_info.add_packed_sint64(OSMFormat::DenseInfo::packed_sint64_changeset, m_changesets.cbegin(), m_changesets.cend()); pbf_dense_info.add_packed_sint64(OSMFormat::DenseInfo::packed_sint64_changeset, m_changesets.cbegin(), m_changesets.cend());
@ -390,7 +389,7 @@ namespace osmium {
return m_type; return m_type;
} }
size_t size() const { std::size_t size() const {
return m_pbf_primitive_group_data.size() + m_stringtable.size() + m_dense_nodes.size(); return m_pbf_primitive_group_data.size() + m_stringtable.size() + m_dense_nodes.size();
} }
@ -400,7 +399,7 @@ namespace osmium {
* enough space for the string table (which typically * enough space for the string table (which typically
* needs about 0.1 to 0.3% of the block size). * needs about 0.1 to 0.3% of the block size).
*/ */
constexpr static size_t max_used_blob_size = max_uncompressed_blob_size * 95 / 100; constexpr static std::size_t max_used_blob_size = max_uncompressed_blob_size * 95 / 100;
bool can_add(OSMFormat::PrimitiveGroup type) const { bool can_add(OSMFormat::PrimitiveGroup type) const {
if (type != m_type) { if (type != m_type) {
@ -426,16 +425,16 @@ namespace osmium {
} }
std::string primitive_block_data; std::string primitive_block_data;
protozero::pbf_builder<OSMFormat::PrimitiveBlock> primitive_block(primitive_block_data); protozero::pbf_builder<OSMFormat::PrimitiveBlock> primitive_block{primitive_block_data};
{ {
protozero::pbf_builder<OSMFormat::StringTable> pbf_string_table(primitive_block, OSMFormat::PrimitiveBlock::required_StringTable_stringtable); protozero::pbf_builder<OSMFormat::StringTable> pbf_string_table{primitive_block, OSMFormat::PrimitiveBlock::required_StringTable_stringtable};
m_primitive_block.write_stringtable(pbf_string_table); m_primitive_block.write_stringtable(pbf_string_table);
} }
primitive_block.add_message(OSMFormat::PrimitiveBlock::repeated_PrimitiveGroup_primitivegroup, m_primitive_block.group_data()); primitive_block.add_message(OSMFormat::PrimitiveBlock::repeated_PrimitiveGroup_primitivegroup, m_primitive_block.group_data());
m_output_queue.push(osmium::thread::Pool::instance().submit( m_output_queue.push(m_pool.submit(
SerializeBlob{std::move(primitive_block_data), SerializeBlob{std::move(primitive_block_data),
pbf_blob_type::data, pbf_blob_type::data,
m_options.use_compression} m_options.use_compression}
@ -459,7 +458,7 @@ namespace osmium {
} }
if (m_options.add_metadata) { if (m_options.add_metadata) {
protozero::pbf_builder<OSMFormat::Info> pbf_info(pbf_object, T::enum_type::optional_Info_info); protozero::pbf_builder<OSMFormat::Info> pbf_info{pbf_object, T::enum_type::optional_Info_info};
pbf_info.add_int32(OSMFormat::Info::optional_int32_version, static_cast_with_assert<int32_t>(object.version())); pbf_info.add_int32(OSMFormat::Info::optional_int32_version, static_cast_with_assert<int32_t>(object.version()));
pbf_info.add_int64(OSMFormat::Info::optional_int64_timestamp, uint32_t(object.timestamp())); pbf_info.add_int64(OSMFormat::Info::optional_int64_timestamp, uint32_t(object.timestamp()));
@ -481,8 +480,8 @@ namespace osmium {
public: public:
PBFOutputFormat(const osmium::io::File& file, future_string_queue_type& output_queue) : PBFOutputFormat(osmium::thread::Pool& pool, const osmium::io::File& file, future_string_queue_type& output_queue) :
OutputFormat(output_queue), OutputFormat(pool, output_queue),
m_options(), m_options(),
m_primitive_block(m_options) { m_primitive_block(m_options) {
m_options.use_dense_nodes = file.is_not_false("pbf_dense_nodes"); m_options.use_dense_nodes = file.is_not_false("pbf_dense_nodes");
@ -500,10 +499,10 @@ namespace osmium {
void write_header(const osmium::io::Header& header) final { void write_header(const osmium::io::Header& header) final {
std::string data; std::string data;
protozero::pbf_builder<OSMFormat::HeaderBlock> pbf_header_block(data); protozero::pbf_builder<OSMFormat::HeaderBlock> pbf_header_block{data};
if (!header.boxes().empty()) { if (!header.boxes().empty()) {
protozero::pbf_builder<OSMFormat::HeaderBBox> pbf_header_bbox(pbf_header_block, OSMFormat::HeaderBlock::optional_HeaderBBox_bbox); protozero::pbf_builder<OSMFormat::HeaderBBox> pbf_header_bbox{pbf_header_block, OSMFormat::HeaderBlock::optional_HeaderBBox_bbox};
osmium::Box box = header.joined_boxes(); osmium::Box box = header.joined_boxes();
pbf_header_bbox.add_sint64(OSMFormat::HeaderBBox::required_sint64_left, int64_t(box.bottom_left().lon() * lonlat_resolution)); pbf_header_bbox.add_sint64(OSMFormat::HeaderBBox::required_sint64_left, int64_t(box.bottom_left().lon() * lonlat_resolution));
@ -528,23 +527,23 @@ namespace osmium {
pbf_header_block.add_string(OSMFormat::HeaderBlock::optional_string_writingprogram, header.get("generator")); pbf_header_block.add_string(OSMFormat::HeaderBlock::optional_string_writingprogram, header.get("generator"));
const std::string osmosis_replication_timestamp = header.get("osmosis_replication_timestamp"); const std::string osmosis_replication_timestamp{header.get("osmosis_replication_timestamp")};
if (!osmosis_replication_timestamp.empty()) { if (!osmosis_replication_timestamp.empty()) {
osmium::Timestamp ts(osmosis_replication_timestamp.c_str()); osmium::Timestamp ts{osmosis_replication_timestamp.c_str()};
pbf_header_block.add_int64(OSMFormat::HeaderBlock::optional_int64_osmosis_replication_timestamp, uint32_t(ts)); pbf_header_block.add_int64(OSMFormat::HeaderBlock::optional_int64_osmosis_replication_timestamp, uint32_t(ts));
} }
const std::string osmosis_replication_sequence_number = header.get("osmosis_replication_sequence_number"); const std::string osmosis_replication_sequence_number{header.get("osmosis_replication_sequence_number")};
if (!osmosis_replication_sequence_number.empty()) { if (!osmosis_replication_sequence_number.empty()) {
pbf_header_block.add_int64(OSMFormat::HeaderBlock::optional_int64_osmosis_replication_sequence_number, std::atoll(osmosis_replication_sequence_number.c_str())); pbf_header_block.add_int64(OSMFormat::HeaderBlock::optional_int64_osmosis_replication_sequence_number, std::atoll(osmosis_replication_sequence_number.c_str()));
} }
const std::string osmosis_replication_base_url = header.get("osmosis_replication_base_url"); const std::string osmosis_replication_base_url{header.get("osmosis_replication_base_url")};
if (!osmosis_replication_base_url.empty()) { if (!osmosis_replication_base_url.empty()) {
pbf_header_block.add_string(OSMFormat::HeaderBlock::optional_string_osmosis_replication_base_url, osmosis_replication_base_url); pbf_header_block.add_string(OSMFormat::HeaderBlock::optional_string_osmosis_replication_base_url, osmosis_replication_base_url);
} }
m_output_queue.push(osmium::thread::Pool::instance().submit( m_output_queue.push(m_pool.submit(
SerializeBlob{std::move(data), SerializeBlob{std::move(data),
pbf_blob_type::header, pbf_blob_type::header,
m_options.use_compression} m_options.use_compression}
@ -567,7 +566,7 @@ namespace osmium {
} }
switch_primitive_block_type(OSMFormat::PrimitiveGroup::repeated_Node_nodes); switch_primitive_block_type(OSMFormat::PrimitiveGroup::repeated_Node_nodes);
protozero::pbf_builder<OSMFormat::Node> pbf_node{ m_primitive_block.group(), OSMFormat::PrimitiveGroup::repeated_Node_nodes }; protozero::pbf_builder<OSMFormat::Node> pbf_node{m_primitive_block.group(), OSMFormat::PrimitiveGroup::repeated_Node_nodes};
pbf_node.add_sint64(OSMFormat::Node::required_sint64_id, node.id()); pbf_node.add_sint64(OSMFormat::Node::required_sint64_id, node.id());
add_meta(node, pbf_node); add_meta(node, pbf_node);
@ -578,7 +577,7 @@ namespace osmium {
void way(const osmium::Way& way) { void way(const osmium::Way& way) {
switch_primitive_block_type(OSMFormat::PrimitiveGroup::repeated_Way_ways); switch_primitive_block_type(OSMFormat::PrimitiveGroup::repeated_Way_ways);
protozero::pbf_builder<OSMFormat::Way> pbf_way{ m_primitive_block.group(), OSMFormat::PrimitiveGroup::repeated_Way_ways }; protozero::pbf_builder<OSMFormat::Way> pbf_way{m_primitive_block.group(), OSMFormat::PrimitiveGroup::repeated_Way_ways};
pbf_way.add_int64(OSMFormat::Way::required_int64_id, way.id()); pbf_way.add_int64(OSMFormat::Way::required_int64_id, way.id());
add_meta(way, pbf_way); add_meta(way, pbf_way);
@ -611,7 +610,7 @@ namespace osmium {
void relation(const osmium::Relation& relation) { void relation(const osmium::Relation& relation) {
switch_primitive_block_type(OSMFormat::PrimitiveGroup::repeated_Relation_relations); switch_primitive_block_type(OSMFormat::PrimitiveGroup::repeated_Relation_relations);
protozero::pbf_builder<OSMFormat::Relation> pbf_relation { m_primitive_block.group(), OSMFormat::PrimitiveGroup::repeated_Relation_relations }; protozero::pbf_builder<OSMFormat::Relation> pbf_relation{m_primitive_block.group(), OSMFormat::PrimitiveGroup::repeated_Relation_relations};
pbf_relation.add_int64(OSMFormat::Relation::required_int64_id, relation.id()); pbf_relation.add_int64(OSMFormat::Relation::required_int64_id, relation.id());
add_meta(relation, pbf_relation); add_meta(relation, pbf_relation);
@ -644,8 +643,8 @@ namespace osmium {
// we want the register_output_format() function to run, setting // we want the register_output_format() function to run, setting
// the variable is only a side-effect, it will never be used // the variable is only a side-effect, it will never be used
const bool registered_pbf_output = osmium::io::detail::OutputFormatFactory::instance().register_output_format(osmium::io::file_format::pbf, const bool registered_pbf_output = osmium::io::detail::OutputFormatFactory::instance().register_output_format(osmium::io::file_format::pbf,
[](const osmium::io::File& file, future_string_queue_type& output_queue) { [](osmium::thread::Pool& pool, const osmium::io::File& file, future_string_queue_type& output_queue) {
return new osmium::io::detail::PBFOutputFormat(file, output_queue); return new osmium::io::detail::PBFOutputFormat{pool, file, output_queue};
}); });
// dummy function to silence the unused variable warning from above // dummy function to silence the unused variable warning from above

View File

@ -85,7 +85,7 @@ namespace osmium {
#endif #endif
const int fd = ::open(filename.c_str(), flags, 0666); const int fd = ::open(filename.c_str(), flags, 0666);
if (fd < 0) { if (fd < 0) {
throw std::system_error(errno, std::system_category(), std::string("Open failed for '") + filename + "'"); throw std::system_error{errno, std::system_category(), std::string("Open failed for '") + filename + "'"};
} }
return fd; return fd;
} }
@ -109,7 +109,7 @@ namespace osmium {
#endif #endif
const int fd = ::open(filename.c_str(), flags); const int fd = ::open(filename.c_str(), flags);
if (fd < 0) { if (fd < 0) {
throw std::system_error(errno, std::system_category(), std::string("Open failed for '") + filename + "'"); throw std::system_error{errno, std::system_category(), std::string("Open failed for '") + filename + "'"};
} }
return fd; return fd;
} }
@ -134,7 +134,7 @@ namespace osmium {
} }
const auto length = ::write(fd, output_buffer + offset, static_cast<unsigned int>(write_count)); const auto length = ::write(fd, output_buffer + offset, static_cast<unsigned int>(write_count));
if (length < 0) { if (length < 0) {
throw std::system_error(errno, std::system_category(), "Write failed"); throw std::system_error{errno, std::system_category(), "Write failed"};
} }
offset += static_cast<size_t>(length); offset += static_cast<size_t>(length);
} while (offset < size); } while (offset < size);
@ -160,13 +160,13 @@ namespace osmium {
#else #else
if (::fsync(fd) != 0) { if (::fsync(fd) != 0) {
#endif #endif
throw std::system_error(errno, std::system_category(), "Fsync failed"); throw std::system_error{errno, std::system_category(), "Fsync failed"};
} }
} }
inline void reliable_close(const int fd) { inline void reliable_close(const int fd) {
if (::close(fd) != 0) { if (::close(fd) != 0) {
throw std::system_error(errno, std::system_category(), "Close failed"); throw std::system_error{errno, std::system_category(), "Close failed"};
} }
} }

View File

@ -136,8 +136,12 @@ namespace osmium {
const_iterator& operator++() { const_iterator& operator++() {
assert(m_it != m_last); assert(m_it != m_last);
const auto last_pos = m_it->c_str() + m_it->size(); const auto last_pos = m_it->c_str() + m_it->size();
while (m_pos != last_pos && *m_pos) ++m_pos; while (m_pos != last_pos && *m_pos) {
if (m_pos != last_pos) ++m_pos; ++m_pos;
}
if (m_pos != last_pos) {
++m_pos;
}
if (m_pos == last_pos) { if (m_pos == last_pos) {
++m_it; ++m_it;
if (m_it != m_last) { if (m_it != m_last) {
@ -150,7 +154,7 @@ namespace osmium {
} }
const_iterator operator++(int) { const_iterator operator++(int) {
const_iterator tmp(*this); const_iterator tmp{*this};
operator++(); operator++();
return tmp; return tmp;
} }
@ -175,11 +179,11 @@ namespace osmium {
if (m_chunks.front().empty()) { if (m_chunks.front().empty()) {
return end(); return end();
} }
return const_iterator(m_chunks.begin(), m_chunks.end()); return {m_chunks.begin(), m_chunks.end()};
} }
const_iterator end() const { const_iterator end() const {
return const_iterator(m_chunks.end(), m_chunks.end()); return {m_chunks.end(), m_chunks.end()};
} }
// These functions get you some idea how much memory was // These functions get you some idea how much memory was
@ -273,7 +277,7 @@ namespace osmium {
m_index[cs] = ++m_size; m_index[cs] = ++m_size;
if (m_size > max_entries) { if (m_size > max_entries) {
throw osmium::pbf_error("string table has too many entries"); throw osmium::pbf_error{"string table has too many entries"};
} }
return m_size; return m_size;

View File

@ -134,10 +134,10 @@ namespace osmium {
// Write out the value with four or more hex digits. // Write out the value with four or more hex digits.
inline void append_min_4_hex_digits(std::string& out, uint32_t value, const char* const hex_digits) { inline void append_min_4_hex_digits(std::string& out, uint32_t value, const char* const hex_digits) {
auto auto
v = value & 0xf0000000; if (v) out += hex_digits[v >> 28]; v = value & 0xf0000000; if (v) { out += hex_digits[v >> 28]; }
v = value & 0x0f000000; if (v) out += hex_digits[v >> 24]; v = value & 0x0f000000; if (v) { out += hex_digits[v >> 24]; }
v = value & 0x00f00000; if (v) out += hex_digits[v >> 20]; v = value & 0x00f00000; if (v) { out += hex_digits[v >> 20]; }
v = value & 0x000f0000; if (v) out += hex_digits[v >> 16]; v = value & 0x000f0000; if (v) { out += hex_digits[v >> 16]; }
out += hex_digits[(value >> 12) & 0xf]; out += hex_digits[(value >> 12) & 0xf];
out += hex_digits[(value >> 8) & 0xf]; out += hex_digits[(value >> 8) & 0xf];
@ -181,7 +181,7 @@ namespace osmium {
inline void append_xml_encoded_string(std::string& out, const char* data) { inline void append_xml_encoded_string(std::string& out, const char* data) {
for (; *data != '\0'; ++data) { for (; *data != '\0'; ++data) {
switch(*data) { switch (*data) {
case '&': out += "&amp;"; break; case '&': out += "&amp;"; break;
case '\"': out += "&quot;"; break; case '\"': out += "&quot;"; break;
case '\'': out += "&apos;"; break; case '\'': out += "&apos;"; break;

View File

@ -33,11 +33,11 @@ DEALINGS IN THE SOFTWARE.
*/ */
#include <algorithm>
#include <exception> #include <exception>
#include <future> #include <future>
#include <memory> #include <memory>
#include <string> #include <string>
#include <utility>
#include <osmium/io/compression.hpp> #include <osmium/io/compression.hpp>
#include <osmium/io/detail/queue_util.hpp> #include <osmium/io/detail/queue_util.hpp>
@ -83,7 +83,7 @@ namespace osmium {
try { try {
while (true) { while (true) {
std::string data = m_queue.pop(); const std::string data{m_queue.pop()};
if (at_end_of_data(data)) { if (at_end_of_data(data)) {
break; break;
} }

View File

@ -444,12 +444,14 @@ namespace osmium {
item_type type = item_type::undefined; item_type type = item_type::undefined;
object_id_type ref = 0; object_id_type ref = 0;
bool ref_is_set = false;
const char* role = ""; const char* role = "";
check_attributes(attrs, [&type, &ref, &role](const XML_Char* name, const XML_Char* value) { check_attributes(attrs, [&](const XML_Char* name, const XML_Char* value) {
if (!std::strcmp(name, "type")) { if (!std::strcmp(name, "type")) {
type = char_to_item_type(value[0]); type = char_to_item_type(value[0]);
} else if (!std::strcmp(name, "ref")) { } else if (!std::strcmp(name, "ref")) {
ref = osmium::string_to_object_id(value); ref = osmium::string_to_object_id(value);
ref_is_set = true;
} else if (!std::strcmp(name, "role")) { } else if (!std::strcmp(name, "role")) {
role = static_cast<const char*>(value); role = static_cast<const char*>(value);
} }
@ -457,7 +459,7 @@ 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_is_set) {
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);
@ -625,11 +627,8 @@ namespace osmium {
public: public:
XMLParser(future_string_queue_type& input_queue, explicit XMLParser(parser_arguments& args) :
future_buffer_queue_type& output_queue, Parser(args),
std::promise<osmium::io::Header>& header_promise,
osmium::io::detail::reader_options options) :
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),
@ -673,11 +672,8 @@ namespace osmium {
// the variable is only a side-effect, it will never be used // the variable is only a side-effect, it will never be used
const bool registered_xml_parser = ParserFactory::instance().register_parser( const bool registered_xml_parser = ParserFactory::instance().register_parser(
file_format::xml, file_format::xml,
[](future_string_queue_type& input_queue, [](parser_arguments& args) {
future_buffer_queue_type& output_queue, return std::unique_ptr<Parser>(new XMLParser{args});
std::promise<osmium::io::Header>& header_promise,
osmium::io::detail::reader_options options) {
return std::unique_ptr<Parser>(new XMLParser{input_queue, output_queue, header_promise, options});
}); });
// dummy function to silence the unused variable warning from above // dummy function to silence the unused variable warning from above

View File

@ -33,7 +33,6 @@ DEALINGS IN THE SOFTWARE.
*/ */
#include <algorithm>
#include <iterator> #include <iterator>
#include <memory> #include <memory>
#include <string> #include <string>
@ -397,7 +396,8 @@ namespace osmium {
write_attribute("uid", changeset.uid()); write_attribute("uid", changeset.uid());
} }
if (changeset.bounds()) { if (!changeset.bounds().bottom_left().is_undefined() ||
!changeset.bounds().top_right().is_undefined()) {
detail::append_lat_lon_attributes(*m_out, "min_lat", "min_lon", changeset.bounds().bottom_left()); detail::append_lat_lon_attributes(*m_out, "min_lat", "min_lon", changeset.bounds().bottom_left());
detail::append_lat_lon_attributes(*m_out, "max_lat", "max_lon", changeset.bounds().top_right()); detail::append_lat_lon_attributes(*m_out, "max_lat", "max_lon", changeset.bounds().top_right());
} }
@ -431,8 +431,8 @@ namespace osmium {
public: public:
XMLOutputFormat(const osmium::io::File& file, future_string_queue_type& output_queue) : XMLOutputFormat(osmium::thread::Pool& pool, const osmium::io::File& file, future_string_queue_type& output_queue) :
OutputFormat(output_queue), OutputFormat(pool, output_queue),
m_options() { m_options() {
m_options.add_metadata = file.is_not_false("add_metadata"); m_options.add_metadata = file.is_not_false("add_metadata");
m_options.use_change_ops = file.is_true("xml_change_format"); m_options.use_change_ops = file.is_true("xml_change_format");
@ -446,14 +446,14 @@ namespace osmium {
~XMLOutputFormat() noexcept final = default; ~XMLOutputFormat() noexcept final = default;
void write_header(const osmium::io::Header& header) final { void write_header(const osmium::io::Header& header) final {
std::string out = "<?xml version='1.0' encoding='UTF-8'?>\n"; std::string out{"<?xml version='1.0' encoding='UTF-8'?>\n"};
if (m_options.use_change_ops) { if (m_options.use_change_ops) {
out += "<osmChange version=\"0.6\" generator=\""; out += "<osmChange version=\"0.6\" generator=\"";
} else { } else {
out += "<osm version=\"0.6\""; out += "<osm version=\"0.6\"";
std::string xml_josm_upload = header.get("xml_josm_upload"); const std::string xml_josm_upload{header.get("xml_josm_upload")};
if (xml_josm_upload == "true" || xml_josm_upload == "false") { if (xml_josm_upload == "true" || xml_josm_upload == "false") {
out += " upload=\""; out += " upload=\"";
out += xml_josm_upload; out += xml_josm_upload;
@ -475,7 +475,7 @@ namespace osmium {
} }
void write_buffer(osmium::memory::Buffer&& buffer) final { void write_buffer(osmium::memory::Buffer&& buffer) final {
m_output_queue.push(osmium::thread::Pool::instance().submit(XMLOutputBlock{std::move(buffer), m_options})); m_output_queue.push(m_pool.submit(XMLOutputBlock{std::move(buffer), m_options}));
} }
void write_end() final { void write_end() final {
@ -495,8 +495,8 @@ namespace osmium {
// we want the register_output_format() function to run, setting // we want the register_output_format() function to run, setting
// the variable is only a side-effect, it will never be used // the variable is only a side-effect, it will never be used
const bool registered_xml_output = osmium::io::detail::OutputFormatFactory::instance().register_output_format(osmium::io::file_format::xml, const bool registered_xml_output = osmium::io::detail::OutputFormatFactory::instance().register_output_format(osmium::io::file_format::xml,
[](const osmium::io::File& file, future_string_queue_type& output_queue) { [](osmium::thread::Pool& pool, const osmium::io::File& file, future_string_queue_type& output_queue) {
return new osmium::io::detail::XMLOutputFormat(file, output_queue); return new osmium::io::detail::XMLOutputFormat(pool, file, output_queue);
}); });
// dummy function to silence the unused variable warning from above // dummy function to silence the unused variable warning from above

View File

@ -70,7 +70,7 @@ namespace osmium {
); );
if (result != Z_OK) { if (result != Z_OK) {
throw io_error(std::string("failed to compress data: ") + zError(result)); throw io_error{std::string{"failed to compress data: "} + zError(result)};
} }
output.resize(output_size); output.resize(output_size);
@ -100,7 +100,7 @@ namespace osmium {
); );
if (result != Z_OK) { if (result != Z_OK) {
throw io_error(std::string("failed to uncompress data: ") + zError(result)); throw io_error{std::string{"failed to uncompress data: "} + zError(result)};
} }
return protozero::data_view{output.data(), output.size()}; return protozero::data_view{output.data(), output.size()};

View File

@ -113,7 +113,7 @@ namespace osmium {
} }
// if filename is a URL, default to XML format // if filename is a URL, default to XML format
const std::string protocol = m_filename.substr(0, m_filename.find_first_of(':')); const std::string protocol{m_filename.substr(0, m_filename.find_first_of(':'))};
if (protocol == "http" || protocol == "https") { if (protocol == "http" || protocol == "https") {
m_file_format = file_format::xml; m_file_format = file_format::xml;
} }
@ -176,7 +176,7 @@ namespace osmium {
if (pos == std::string::npos) { if (pos == std::string::npos) {
set(option, true); set(option, true);
} else { } else {
std::string value = option.substr(pos+1); std::string value{option.substr(pos+1)};
option.erase(pos); option.erase(pos);
set(option, value); set(option, value);
} }
@ -192,7 +192,9 @@ namespace osmium {
void detect_format_from_suffix(const std::string& name) { void detect_format_from_suffix(const std::string& name) {
std::vector<std::string> suffixes = detail::split(name, '.'); std::vector<std::string> suffixes = detail::split(name, '.');
if (suffixes.empty()) return; if (suffixes.empty()) {
return;
}
// if the last suffix is one of a known set of compressions, // if the last suffix is one of a known set of compressions,
// set that compression // set that compression
@ -204,7 +206,9 @@ namespace osmium {
suffixes.pop_back(); suffixes.pop_back();
} }
if (suffixes.empty()) return; if (suffixes.empty()) {
return;
}
// if the last suffix is one of a known set of formats, // if the last suffix is one of a known set of formats,
// set that format // set that format
@ -231,19 +235,30 @@ namespace osmium {
} else if (suffixes.back() == "debug") { } else if (suffixes.back() == "debug") {
m_file_format = file_format::debug; m_file_format = file_format::debug;
suffixes.pop_back(); suffixes.pop_back();
} else if (suffixes.back() == "blackhole") {
m_file_format = file_format::blackhole;
suffixes.pop_back();
} }
if (suffixes.empty()) return; if (suffixes.empty()) {
return;
}
if (suffixes.back() == "osm") { if (suffixes.back() == "osm") {
if (m_file_format == file_format::unknown) m_file_format = file_format::xml; if (m_file_format == file_format::unknown) {
m_file_format = file_format::xml;
}
suffixes.pop_back(); suffixes.pop_back();
} else if (suffixes.back() == "osh") { } else if (suffixes.back() == "osh") {
if (m_file_format == file_format::unknown) m_file_format = file_format::xml; if (m_file_format == file_format::unknown) {
m_file_format = file_format::xml;
}
m_has_multiple_object_versions = true; m_has_multiple_object_versions = true;
suffixes.pop_back(); suffixes.pop_back();
} else if (suffixes.back() == "osc") { } else if (suffixes.back() == "osc") {
if (m_file_format == file_format::unknown) m_file_format = file_format::xml; if (m_file_format == file_format::unknown) {
m_file_format = file_format::xml;
}
m_has_multiple_object_versions = true; m_has_multiple_object_versions = true;
set("xml_change_format", true); set("xml_change_format", true);
suffixes.pop_back(); suffixes.pop_back();
@ -258,7 +273,7 @@ namespace osmium {
*/ */
const File& check() const { const File& check() const {
if (m_file_format == file_format::unknown) { if (m_file_format == file_format::unknown) {
std::string msg = "Could not detect file format"; std::string msg{"Could not detect file format"};
if (!m_format_string.empty()) { if (!m_format_string.empty()) {
msg += " from format string '"; msg += " from format string '";
msg += m_format_string; msg += m_format_string;
@ -272,7 +287,7 @@ namespace osmium {
msg += "'"; msg += "'";
} }
msg += "."; msg += ".";
throw io_error(msg); throw io_error{msg};
} }
return *this; return *this;
} }

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