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

View File

@ -6,9 +6,130 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## [unreleased] -
### Added
### Changed
### 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
@ -16,25 +137,94 @@ This project adheres to [Semantic Versioning](http://semver.org/).
multipolygons with overlapping or nearly overlapping lines.
- Invalid use of iterators leading to undefined behaviour in area assembler
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.
- 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
- Use minimum size of 64 bytes for buffers. This fixes an infinite loop
when buffer size is zero.
- Infinite loop in `Buffer::reserve_space()`. (Issue #202.)
- `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
- Terminate called on full non-auto-growing buffer. (Issue #189.)
- When file formats were used that were not compiled into the binary, it
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.
- XML reader doesn't fail on relation member ref=0 any more.
## [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
this.
[unreleased]: https://github.com/osmcode/libosmium/compare/v2.11.3...HEAD
[2.11.3]: https://github.com/osmcode/libosmium/compare/v2.11.2...v2.11.3
[2.11.2]: https://github.com/osmcode/libosmium/compare/v2.11.1...v2.11.2
[2.11.1]: https://github.com/osmcode/libosmium/compare/v2.11.0...v2.11.1
[unreleased]: https://github.com/osmcode/libosmium/compare/v2.13.1...HEAD
[2.13.1]: https://github.com/osmcode/libosmium/compare/v2.13.0...v2.13.1
[2.13.0]: https://github.com/osmcode/libosmium/compare/v2.12.2...v2.13.0
[2.12.2]: https://github.com/osmcode/libosmium/compare/v2.12.1...v2.12.2
[2.12.1]: https://github.com/osmcode/libosmium/compare/v2.12.0...v2.12.1
[2.12.0]: https://github.com/osmcode/libosmium/compare/v2.11.0...v2.12.0
[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.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)
set(LIBOSMIUM_VERSION_MAJOR 2)
set(LIBOSMIUM_VERSION_MINOR 11)
set(LIBOSMIUM_VERSION_PATCH 3)
set(LIBOSMIUM_VERSION_MINOR 13)
set(LIBOSMIUM_VERSION_PATCH 1)
set(LIBOSMIUM_VERSION
"${LIBOSMIUM_VERSION_MAJOR}.${LIBOSMIUM_VERSION_MINOR}.${LIBOSMIUM_VERSION_PATCH}")
@ -43,8 +43,14 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
if(CMAKE_BUILD_TYPE STREQUAL "Dev")
set(dev_build ON)
set(data_test_build ON)
else()
set(dev_build OFF)
set(data_test_build OFF)
endif()
if(CMAKE_BUILD_TYPE STREQUAL "Coverage")
set(data_test_build ON)
endif()
option(BUILD_EXAMPLES "compile example programs" ON)
@ -52,7 +58,8 @@ option(BUILD_TESTING "compile unit tests, please run them with ctest" ON)
option(BUILD_HEADERS "compile every header file on its own" ${dev_build})
option(BUILD_BENCHMARKS "compile benchmark programs" ${dev_build})
option(BUILD_DATA_TESTS "compile data tests, please run them with ctest" ${dev_build})
option(BUILD_DATA_TESTS "compile data tests, please run them with ctest" ${data_test_build})
option(INSTALL_GDALCPP "also install gdalcpp headers" OFF)
option(INSTALL_PROTOZERO "also install protozero headers" OFF)
@ -88,11 +95,12 @@ endif()
#
#-----------------------------------------------------------------------------
include(CheckCXXCompilerFlag)
check_cxx_compiler_flag("-fkeep-inline-functions" HAS_KEEP_INLINE_FUNCTIONS)
if(HAS_KEEP_INLINE_FUNCTIONS)
set(extra_coverage_flags_ "-fkeep-inline-functions")
endif()
## This leads to all sorts of compile problems, so disable for now
#include(CheckCXXCompilerFlag)
#check_cxx_compiler_flag("-fkeep-inline-functions" HAS_KEEP_INLINE_FUNCTIONS)
#if(HAS_KEEP_INLINE_FUNCTIONS)
# set(extra_coverage_flags_ "-fkeep-inline-functions")
#endif()
set(CMAKE_CXX_FLAGS_COVERAGE
"-g -O0 -fno-inline-functions -fno-inline --coverage ${extra_coverage_flags_}"
@ -103,8 +111,8 @@ set(CMAKE_EXE_LINKER_FLAGS_COVERAGE
CACHE STRING "Flags used by the linker during coverage builds.")
if(CMAKE_BUILD_TYPE STREQUAL "Coverage")
if(BUILD_EXAMPLES OR BUILD_HEADERS OR BUILD_BENCHMARKS OR BUILD_DATA_TESTS)
message(WARNING "Coverage builds don't work for anything but the unit tests")
if(BUILD_EXAMPLES OR BUILD_HEADERS OR BUILD_BENCHMARKS)
message(WARNING "Coverage builds don't work for anything but the tests")
endif()
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
@ -184,8 +192,12 @@ endif()
#-----------------------------------------------------------------------------
if(NOT MSVC)
if(NOT USE_CPP_VERSION)
if(CYGWIN)
set(USE_CPP_VERSION gnu++11)
else()
set(USE_CPP_VERSION c++11)
endif()
endif()
message(STATUS "Use C++ version: ${USE_CPP_VERSION}")
# following only available from cmake 2.8.12:
# add_compile_options(-std=${USE_CPP_VERSION})
@ -201,15 +213,15 @@ endif()
#-----------------------------------------------------------------------------
if(MSVC)
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()
set(USUAL_COMPILE_OPTIONS "-O3 -g")
set(USUAL_LINK_OPTIONS "")
endif()
if(WIN32)
add_definitions(-DWIN32 -D_WIN32 -DMSWIN32 -DBGDWIN32
-DWINVER=0x0500 -D_WIN32_WINNT=0x0500 -D_WIN32_IE=0x0600)
add_definitions(-DWIN32 -D_WIN32 -DMSWIN32 -DBGDWIN32)
endif()
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."
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)
add_definitions(-fno-omit-frame-pointer)
endif()
@ -301,7 +322,13 @@ find_program(CPPCHECK cppcheck)
if(CPPCHECK)
message(STATUS "Looking for cppcheck - found")
set(CPPCHECK_OPTIONS
--enable=warning,style,performance,portability,information,missingInclude --force -Uassert)
--language=c++
--quiet
-j4
--inline-suppr
--enable=warning,style,performance,portability,information,missingInclude
--force
-Uassert -DPROTOZERO_STRICT_API -DPROTOZERO_USE_BUILTIN_BSWAP -UPROTOZERO_USE_VIEW)
# cpp doesn't find system includes for some reason, suppress that report
set(CPPCHECK_OPTIONS ${CPPCHECK_OPTIONS} --suppress=missingIncludeSystem)
@ -460,10 +487,12 @@ if(CLANG_TIDY)
list(APPEND CT_CHECKS "misc-*"
"-misc-argument-comment")
list(APPEND CT_CHECKS "modernize-*")
list(APPEND CT_CHECKS "modernize-*"
"-modernize-make-unique") # not available in C++11
list(APPEND CT_CHECKS "readability-*"
"-readability-identifier-naming"
"-readability-implicit-bool-cast"
"-readability-named-parameter")
string(REPLACE ";" "," ALL_CHECKS "${CT_CHECKS}")

View File

@ -12,7 +12,7 @@ All Osmium code MUST be in the `osmium` namespace or one of its sub-namespaces.
## Include-Only
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
is no place to put this data.
@ -69,7 +69,7 @@ different.
* Template parameters are single uppercase letters or start with uppercase `T`
and use CamelCase.
* Always use `typename` in templates, not `class`: `template <typename T>`.
* The ellipsis in variadic template never has a space to the left of it and
* 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.
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
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
@ -118,9 +131,20 @@ used to define mappings for iwyu. See the IWYU tool at
## Testing
There are a 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
default cmake config. Run `ctest` to run them. Many more tests are needed.
There are unit tests using the Catch Unit Test Framework in the `test`
directory, some data tests in `test/osm-testdata` and tests of the examples in
`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

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.
[![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)
[![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)
Please see the [Libosmium manual](http://osmcode.org/libosmium/manual.html)
for more details than this README can provide.

View File

@ -7,7 +7,13 @@
environment:
matrix:
- config: Dev
autocrlf: true
- config: Dev
autocrlf: false
- config: RelWithDebInfo
autocrlf: true
- config: RelWithDebInfo
autocrlf: false
shallow_clone: true
@ -16,6 +22,8 @@ os: Visual Studio 2015
# scripts that are called at very beginning, before repo cloning
init:
- git config --global core.autocrlf %autocrlf%
- git config --get core.autocrlf
# clone directory
clone_folder: c:\projects\libosmium
@ -24,3 +32,8 @@ platform: x64
build_script:
- 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}
${OSMIUM_IO_LIBRARIES}
${BENCHMARK_LIBS_${benchmark}})
set_pthread_on_target(osmium_benchmark_${benchmark})
configure_file(run_benchmark_${benchmark}.sh
${CMAKE_CURRENT_BINARY_DIR}/run_benchmark_${benchmark}.sh
@ONLY)

View File

@ -97,11 +97,14 @@ ECHO calling^: %CMAKE_CMD%
%CMAKE_CMD%
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 ^
/p:Configuration=%config% ^
/toolsversion:14.0 ^
/p:Platform=x64 ^
/p:PlatformToolset=v140
/p:PlatformToolset=v140 %avlogger%
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
ctest --output-on-failure ^

View File

@ -296,6 +296,20 @@ find_package_handle_standard_args(Osmium
VERSION_VAR _libosmium_version)
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
@ -319,6 +333,10 @@ if(MSVC)
# old compilers anyway.
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)
endif()

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -33,6 +33,10 @@
#include <sys/types.h> // for open
#include <vector> // for std::vector
#ifdef _WIN32
# include <io.h> // for _setmode
#endif
// Disk-based indexes
#include <osmium/index/map/dense_file_array.hpp>
#include <osmium/index/map/sparse_file_array.hpp>
@ -52,7 +56,7 @@ class IndexAccess {
public:
IndexAccess(int fd) :
explicit IndexAccess(int fd) :
m_fd(fd) {
}
@ -83,7 +87,7 @@ class IndexAccessDense : public IndexAccess<TValue> {
public:
IndexAccessDense(int fd) :
explicit IndexAccessDense(int fd) :
IndexAccess<TValue>(fd) {
}
@ -122,7 +126,7 @@ class IndexAccessSparse : public IndexAccess<TValue> {
public:
IndexAccessSparse(int fd) :
explicit IndexAccessSparse(int fd) :
IndexAccess<TValue>(fd) {
}
@ -192,17 +196,17 @@ public:
}
static struct option long_options[] = {
{"array", required_argument, 0, 'a'},
{"dump", no_argument, 0, 'd'},
{"help", no_argument, 0, 'h'},
{"list", required_argument, 0, 'l'},
{"search", required_argument, 0, 's'},
{"type", required_argument, 0, 't'},
{0, 0, 0, 0}
{"array", required_argument, nullptr, 'a'},
{"dump", no_argument, nullptr, 'd'},
{"help", no_argument, nullptr, 'h'},
{"list", required_argument, nullptr, 'l'},
{"search", required_argument, nullptr, 's'},
{"type", required_argument, nullptr, 't'},
{nullptr, 0, nullptr, 0}
};
while (true) {
const int c = getopt_long(argc, argv, "a:dhl:s:t:", long_options, 0);
const int c = getopt_long(argc, argv, "a:dhl:s:t:", long_options, nullptr);
if (c == -1) {
break;
}
@ -243,7 +247,7 @@ public:
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::exit(2);
}
@ -308,13 +312,18 @@ int main(int argc, char* argv[]) {
Options options{argc, argv};
// Open the index file.
const int fd = open(options.filename(), O_RDWR);
const int fd = ::open(options.filename(), O_RDWR);
if (fd < 0) {
std::cerr << "Can not open file '" << options.filename()
<< "': " << std::strerror(errno) << '\n';
std::exit(2);
}
#ifdef _WIN32
_setmode(fd, _O_BINARY);
#endif
try {
// Depending on the type of index, we have different implementations.
if (options.type_is("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);
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/types.h> // for open
#ifdef _WIN32
# include <io.h> // for _setmode
#endif
// Allow any format of input files (XML, PBF, ...)
#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};
// Initialize location index on disk creating a new file.
const int fd = open(cache_filename.c_str(), O_RDWR | O_CREAT, 0666);
const int fd = ::open(cache_filename.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0666);
if (fd == -1) {
std::cerr << "Can not open location cache file '" << cache_filename << "': " << std::strerror(errno) << "\n";
std::exit(1);
}
#ifdef _WIN32
_setmode(fd, _O_BINARY);
#endif
index_type index{fd};
// The handler that stores all node locations in the index.

View File

@ -33,6 +33,10 @@
#include <sys/stat.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, ...)
#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};
// 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) {
std::cerr << "Can not open location cache file '" << cache_filename << "': " << std::strerror(errno) << "\n";
return 1;
}
#ifdef _WIN32
_setmode(fd, _O_BINARY);
#endif
index_type index{fd};
// The handler that adds node locations from the index to the ways.

View File

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

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

View File

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

View File

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

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

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) {
}
/**
* 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.
*
@ -189,6 +201,23 @@ namespace osmium {
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
* report all ways belonging to areas having problems.

View File

@ -60,58 +60,76 @@ namespace osmium {
~ProblemReporterException() override = default;
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);
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 {
m_sstream.str();
m_sstream.str("");
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,
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);
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 {
m_sstream.str();
m_sstream.str("");
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 {
m_sstream.str();
m_sstream.str("");
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 {
m_sstream.str();
m_sstream.str("");
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 {
m_sstream.str();
m_sstream.str("");
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 {
m_sstream.str();
m_sstream.str("");
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 {
m_sstream.str();
m_sstream.str("");
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

View File

@ -73,14 +73,14 @@ namespace osmium {
gdalcpp::Layer m_layer_ways;
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_id", int32_t(m_object_id));
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) {
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);
feature.set_field("id1", double(id1));
feature.set_field("id2", double(id2));
@ -93,7 +93,7 @@ namespace osmium {
ogr_linestring->addPoint(loc1.lon(), loc1.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);
feature.set_field("id1", static_cast<double>(id1));
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());
}
void report_overlapping_segment(const osmium::NodeRef& nr1, const osmium::NodeRef& nr2) override {
write_line("overlapping_segment", nr1.ref(), nr2.ref(), nr1.location(), nr2.location());
}
void report_ring_not_closed(const osmium::NodeRef& nr, const osmium::Way* way = nullptr) override {
write_point("ring_not_closed", nr.ref(), way ? way->id() : 0, nr.location());
}
@ -175,7 +179,7 @@ namespace osmium {
return;
}
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);
feature.set_field("id1", int32_t(way.id()));
feature.set_field("id2", 0);
@ -191,7 +195,7 @@ namespace osmium {
return;
}
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);
feature.set_field("id1", int32_t(way.id()));
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 {
if (way.nodes().empty()) {
return;
@ -212,7 +232,7 @@ namespace osmium {
return;
}
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);
feature.set_field("way_id", int32_t(way.id()));
feature.add_to_layer();

View File

@ -85,6 +85,12 @@ namespace osmium {
<< " node_id2=" << nr2.ref() << " location2=" << nr2.location() << "\n";
}
void report_overlapping_segment(const osmium::NodeRef& nr1, const osmium::NodeRef& nr2) override {
header("overlapping segment");
*m_out << "node_id1=" << nr1.ref() << " location1=" << nr1.location()
<< " node_id2=" << nr2.ref() << " location2=" << nr2.location() << "\n";
}
void report_ring_not_closed(const osmium::NodeRef& nr, const osmium::Way* way = nullptr) override {
header("ring not closed");
*m_out << "node_id=" << nr.ref() << " location=" << nr.location();
@ -114,6 +120,16 @@ namespace osmium {
*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
} // 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 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_ways = 0; ///< Ways that are in relation more than once
uint64_t from_relations = 0; ///< Area created from multipolygon relation
uint64_t from_ways = 0; ///< Area created from way
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 open_rings = 0; ///< Number of open rings in the area
uint64_t outer_rings = 0; ///< Number of outer rings in the area
uint64_t overlapping_segments = 0; ///< Three or more segments with same end points
uint64_t short_ways = 0; ///< Number of ways with less than two nodes
uint64_t single_way_in_mp_relation = 0; ///< Multipolygon relation containing a single way
uint64_t touching_rings = 0; ///< Rings touching in a node
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 invalid_locations = 0; ///< Invalid location found
area_stats& operator+=(const area_stats& other) noexcept {
area_really_complex_case += other.area_really_complex_case;
@ -75,6 +78,7 @@ namespace osmium {
area_touching_rings_case += other.area_touching_rings_case;
duplicate_nodes += other.duplicate_nodes;
duplicate_segments += other.duplicate_segments;
duplicate_ways += other.duplicate_ways;
from_relations += other.from_relations;
from_ways += other.from_ways;
inner_rings += other.inner_rings;
@ -91,6 +95,7 @@ namespace osmium {
touching_rings += other.touching_rings;
ways_in_multiple_rings += other.ways_in_multiple_rings;
wrong_role += other.wrong_role;
invalid_locations += invalid_locations;
return *this;
}
@ -103,6 +108,7 @@ namespace osmium {
<< " area_touching_rings_case=" << s.area_touching_rings_case
<< " duplicate_nodes=" << s.duplicate_nodes
<< " duplicate_segments=" << s.duplicate_segments
<< " duplicate_ways=" << s.duplicate_ways
<< " from_relations=" << s.from_relations
<< " from_ways=" << s.from_ways
<< " inner_rings=" << s.inner_rings
@ -118,7 +124,8 @@ namespace osmium {
<< " single_way_in_mp_relation=" << s.single_way_in_mp_relation
<< " touching_rings=" << s.touching_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

View File

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

View File

@ -71,7 +71,7 @@ namespace osmium {
* @deprecated
* 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();
{
osmium::builder::TagListBuilder tl_builder(buffer);
@ -87,7 +87,7 @@ namespace osmium {
* @deprecated
* 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();
{
osmium::builder::TagListBuilder tl_builder(buffer);
@ -103,7 +103,7 @@ namespace osmium {
* @deprecated
* 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();
{
osmium::builder::TagListBuilder tl_builder(buffer);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -118,7 +118,7 @@ namespace osmium {
* @pre @code c.valid() @endcode
*/
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
*/
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:
MercatorProjection() {
}
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 {

View File

@ -48,6 +48,7 @@ DEALINGS IN THE SOFTWARE.
#include <proj_api.h>
#include <osmium/geom/coordinates.hpp>
#include <osmium/geom/mercator_projection.hpp>
#include <osmium/geom/util.hpp>
#include <osmium/osm/location.hpp>
@ -70,15 +71,15 @@ namespace osmium {
public:
explicit CRS(const std::string& crs) :
m_crs(pj_init_plus(crs.c_str()), ProjCRSDeleter()) {
explicit CRS(const char* crs) :
m_crs(pj_init_plus(crs), ProjCRSDeleter()) {
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) :
CRS(std::string{crs}) {
explicit CRS(const std::string& crs) :
CRS(crs.c_str()) {
}
explicit CRS(int epsg) :
@ -88,15 +89,15 @@ namespace osmium {
/**
* Get underlying projPJ handle from proj library.
*/
projPJ get() const {
projPJ get() const noexcept {
return m_crs.get();
}
bool is_latlong() const {
bool is_latlong() const noexcept {
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;
}
@ -108,12 +109,13 @@ namespace osmium {
*
* 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) {
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) {
throw osmium::projection_error(std::string("projection failed: ") + pj_strerrno(result));
throw osmium::projection_error{std::string{"projection failed: "} + pj_strerrno(result)};
}
return c;
}
@ -121,12 +123,19 @@ namespace osmium {
/**
* Functor that does projection from WGS84 (EPSG:4326) to the given
* 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 {
int m_epsg;
std::string m_proj_string;
CRS m_crs_wgs84 {4326};
CRS m_crs_wgs84{4326};
CRS m_crs_user;
public:
@ -145,20 +154,24 @@ namespace osmium {
explicit Projection(int 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) {
}
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) {
c = transform(m_crs_wgs84, m_crs_user, Coordinates(deg_to_rad(location.lon()), deg_to_rad(location.lat())));
Coordinates c{transform(m_crs_wgs84, m_crs_user, Coordinates{deg_to_rad(location.lon()),
deg_to_rad(location.lat())})};
if (m_crs_user.is_latlong()) {
c.x = rad_to_deg(c.x);
c.y = rad_to_deg(c.y);
}
}
return c;
}

View File

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

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.
*/
inline constexpr double tile_extent_in_zoom(uint32_t zoom) noexcept {
@ -108,7 +108,7 @@ namespace osmium {
uint32_t z;
/**
* Create a tile with the given zoom level and x any y tile
* Create a tile with the given zoom level and x and y tile
* coordinates.
*
* The values are not checked for validity.
@ -172,22 +172,30 @@ namespace osmium {
}; // struct Tile
/// Tiles are equal if all their attributes are equal.
inline bool operator==(const Tile& lhs, const Tile& rhs) {
inline bool operator==(const Tile& lhs, const Tile& rhs) noexcept {
return lhs.z == rhs.z && lhs.x == rhs.x && lhs.y == rhs.y;
}
inline bool operator!=(const Tile& lhs, const Tile& rhs) {
inline bool operator!=(const Tile& lhs, const Tile& rhs) noexcept {
return ! (lhs == rhs);
}
/**
* This defines an arbitrary order on tiles for use in std::map etc.
*/
inline bool operator<(const Tile& lhs, const Tile& rhs) {
if (lhs.z < rhs.z) return true;
if (lhs.z > rhs.z) return false;
if (lhs.x < rhs.x) return true;
if (lhs.x > rhs.x) return false;
inline bool operator<(const Tile& lhs, const Tile& rhs) noexcept {
if (lhs.z < rhs.z) {
return true;
}
if (lhs.z > rhs.z) {
return false;
}
if (lhs.x < rhs.x) {
return true;
}
if (lhs.x > rhs.x) {
return false;
}
return lhs.y < rhs.y;
}

View File

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

View File

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

View File

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

View File

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

View File

@ -64,9 +64,11 @@ namespace osmium {
template <typename TStoragePosIDs, typename TStorageNegIDs = dummy_type>
class NodeLocationsForWays : public osmium::handler::Handler {
static_assert(std::is_base_of<osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>, TStoragePosIDs>::value, "Index class must be derived from osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>");
template <typename T>
using based_on_map = std::is_base_of<osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>, T>;
static_assert(std::is_base_of<osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>, TStorageNegIDs>::value, "Index class must be derived from osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>");
static_assert(based_on_map<TStoragePosIDs>::value, "Index class must be derived from osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>");
static_assert(based_on_map<TStorageNegIDs>::value, "Index class must be derived from osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>");
public:
@ -81,11 +83,11 @@ namespace osmium {
/// Object that handles the actual storage of the node locations (with negative IDs).
TStorageNegIDs& m_storage_neg;
osmium::unsigned_object_id_type m_last_id{0};
osmium::unsigned_object_id_type m_last_id = 0;
bool m_ignore_errors{false};
bool m_ignore_errors = false;
bool m_must_sort{false};
bool m_must_sort = false;
// It is okay to have this static dummy instance, even when using several threads,
// because it is read-only.
@ -123,7 +125,7 @@ namespace osmium {
}
m_last_id = node.positive_id();
const osmium::object_id_type id = node.id();
const auto id = node.id();
if (id >= 0) {
m_storage_pos.set(static_cast<osmium::unsigned_object_id_type>( id), node.location());
} else {
@ -136,9 +138,9 @@ namespace osmium {
*/
osmium::Location get_node_location(const osmium::object_id_type id) const {
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 {
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;
for (auto& node_ref : way.nodes()) {
try {
node_ref.set_location(get_node_location(node_ref.ref()));
if (!node_ref.location()) {
error = true;
}
} catch (const osmium::not_found&) {
error = true;
}
}
if (error && !m_ignore_errors) {
if (!m_ignore_errors && error) {
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>
inline T* create_map_with_fd(const std::vector<std::string>& config) {
if (config.size() == 1) {
return new T();
return new T{};
}
assert(config.size() > 1);
const std::string& filename = config[1];
const int fd = ::open(filename.c_str(), O_CREAT | O_RDWR, 0644);
if (fd == -1) {
throw std::runtime_error(std::string("can't open file '") + filename + "': " + std::strerror(errno));
throw std::runtime_error{std::string{"can't open file '"} + filename + "': " + std::strerror(errno)};
}
return new T(fd);
return new T{fd};
}
} // namespace detail

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -43,7 +43,6 @@ DEALINGS IN THE SOFTWARE.
#include <type_traits>
#include <vector>
#include <osmium/util/compatibility.hpp>
#include <osmium/util/string.hpp>
namespace osmium {
@ -181,14 +180,14 @@ namespace osmium {
// but not always. It could, for instance, sort internal data.
// This is why it is not declared const here.
virtual void dump_as_list(const int /*fd*/) {
throw std::runtime_error("can't dump as list");
throw std::runtime_error{"can't dump as list"};
}
// This function can usually be const in derived classes,
// but not always. It could, for instance, sort internal data.
// This is why it is not declared const here.
virtual void dump_as_array(const int /*fd*/) {
throw std::runtime_error("can't dump as array");
throw std::runtime_error{"can't dump as array"};
}
}; // class Map
@ -245,13 +244,13 @@ namespace osmium {
}
std::unique_ptr<map_type> create_map(const std::string& config_string) const {
std::vector<std::string> config = osmium::split_string(config_string, ',');
std::vector<std::string> config{osmium::split_string(config_string, ',')};
if (config.empty()) {
throw map_factory_error{"Need non-empty map type name"};
}
auto it = m_callbacks.find(config[0]);
const auto it = m_callbacks.find(config[0]);
if (it != m_callbacks.end()) {
return std::unique_ptr<map_type>((it->second)(config));
}

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_mmap_array.hpp> // IWYU pragma: keep
#include <osmium/index/map/dummy.hpp> // IWYU pragma: keep
#include <osmium/index/map/flex_mem.hpp> // IWYU pragma: keep
#include <osmium/index/map/sparse_file_array.hpp> // IWYU pragma: keep
#include <osmium/index/map/sparse_mem_array.hpp> // IWYU pragma: keep
#include <osmium/index/map/sparse_mem_map.hpp> // IWYU pragma: keep

View File

@ -64,4 +64,8 @@ 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

View File

@ -54,4 +54,8 @@ 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

View File

@ -55,6 +55,10 @@ 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 // 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
#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

View File

@ -57,4 +57,8 @@ 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

View File

@ -120,4 +120,8 @@ 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

View File

@ -150,6 +150,10 @@ 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_INDEX_BYID_SPARSE_MEM_TABLE_HPP
#endif // OSMIUM_INDEX_MAP_SPARSE_MEM_TABLE_HPP

View File

@ -55,6 +55,10 @@ 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 // 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
#define OSMIUM_WANT_NODE_LOCATION_MAPS
#ifdef OSMIUM_HAS_INDEX_MAP_DENSE_FILE_ARRAY
REGISTER_MAP(osmium::unsigned_object_id_type, osmium::Location, osmium::index::map::DenseFileArray, dense_file_array)
#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)
#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

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 <cassert>
#include <cstddef>
#include <cstdint>
#include <tuple>
#include <type_traits>
#include <utility>
#include <vector>
#include <osmium/osm/item_type.hpp>
#include <osmium/osm/relation.hpp>
#include <osmium/osm/types.hpp>
@ -91,6 +95,24 @@ namespace osmium {
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() {
std::sort(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();
}
size_t size() const noexcept {
std::size_t size() const noexcept {
return m_map.size();
}
void reserve(std::size_t size) {
m_map.reserve(size);
}
}; // class flat_map
} // 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
* instantiate a RelationsMapStash, fill it and then create an index from
* it:
* instantiate a RelationsMapStash, fill it and then create an index
* from it:
*
* @code
* RelationsMapStash stash;
@ -128,10 +156,10 @@ namespace osmium {
* 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 = ...;
* 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 {
friend class RelationsMapStash;
friend class RelationsMapIndexes;
using map_type = detail::flat_map<osmium::unsigned_object_id_type, uint32_t,
osmium::unsigned_object_id_type, uint32_t>;
map_type m_map;
RelationsMapIndex(map_type&& map) :
explicit RelationsMapIndex(map_type&& map) :
m_map(std::move(map)) {
}
@ -162,8 +191,8 @@ namespace osmium {
RelationsMapIndex& operator=(RelationsMapIndex&&) = default;
/**
* Find the given relation id in the index and call the given function
* with all parent relation ids.
* Find the given relation id in the index and call the given
* function with all parent relation ids.
*
* @code
* osmium::unsigned_object_id_type member_id = 17;
@ -172,14 +201,38 @@ namespace osmium {
* });
* @endcode
*
* @deprecated Use for_each() instead.
*
* Complexity: Logarithmic in the number of elements in the index.
* (Lookup uses binary search.)
*/
template <typename Func>
void for_each_parent(osmium::unsigned_object_id_type member_id, Func&& func) const {
template <typename TFunc>
void for_each_parent(osmium::unsigned_object_id_type member_id, TFunc&& func) const {
const auto parents = m_map.get(member_id);
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.
*/
size_t size() const noexcept {
std::size_t size() const noexcept {
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
* an index of member relation ID to parent relation ID. See the
* RelationsMapIndex class for more.
* an index of member relation ID to parent relation ID or the other
* way around. See the RelationsMapIndex class for more.
*/
class RelationsMapStash {
@ -264,15 +359,18 @@ namespace osmium {
*
* Complexity: Constant.
*/
size_t size() const noexcept {
std::size_t size() const noexcept {
assert(m_valid && "You can't use the RelationsMap any more after calling build_index()");
return m_map.size();
}
/**
* 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!
*
* @deprecated Use build_member_to_parent_index() instead.
*/
RelationsMapIndex 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)};
}
/**
* 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
} // namespace index

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -33,19 +33,16 @@ DEALINGS IN THE SOFTWARE.
*/
#include <cstdlib>
#include <future>
#include <cstdint>
#include <memory>
#include <string>
#include <utility>
#include <osmium/io/detail/input_format.hpp>
#include <osmium/io/detail/opl_parser_functions.hpp>
#include <osmium/io/detail/queue_util.hpp>
#include <osmium/io/file_format.hpp>
#include <osmium/io/header.hpp>
#include <osmium/memory/buffer.hpp>
#include <osmium/osm/entity_bits.hpp>
#include <osmium/thread/util.hpp>
namespace osmium {
@ -54,10 +51,56 @@ namespace osmium {
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 {
osmium::memory::Buffer m_buffer{1024*1024};
const char* m_data = nullptr;
uint64_t m_line_count = 0;
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:
OPLParser(future_string_queue_type& input_queue,
future_buffer_queue_type& output_queue,
std::promise<osmium::io::Header>& header_promise,
osmium::io::detail::reader_options options) :
Parser(input_queue, output_queue, header_promise, options) {
explicit OPLParser(parser_arguments& args) :
Parser(args) {
set_header_value(osmium::io::Header{});
}
~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 {
osmium::thread::set_thread_name("_osmium_opl_in");
std::string rest;
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();
}
line_by_line(*this);
if (m_buffer.committed() > 0) {
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
const bool registered_opl_parser = ParserFactory::instance().register_parser(
file_format::opl,
[](future_string_queue_type& input_queue,
future_buffer_queue_type& output_queue,
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));
[](parser_arguments& args) {
return std::unique_ptr<Parser>(new OPLParser{args});
});
// 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) {
const bool not_undefined = !location.is_undefined();
*m_out += ' ';
*m_out += x;
if (location) {
if (not_undefined) {
osmium::detail::append_location_coordinate_to_string(std::back_inserter(*m_out), location.x());
}
*m_out += ' ';
*m_out += y;
if (location) {
if (not_undefined) {
osmium::detail::append_location_coordinate_to_string(std::back_inserter(*m_out), location.y());
}
}
@ -283,8 +284,8 @@ namespace osmium {
public:
OPLOutputFormat(const osmium::io::File& file, future_string_queue_type& output_queue) :
OutputFormat(output_queue),
OPLOutputFormat(osmium::thread::Pool& pool, const osmium::io::File& file, future_string_queue_type& output_queue) :
OutputFormat(pool, output_queue),
m_options() {
m_options.add_metadata = file.is_not_false("add_metadata");
m_options.locations_on_ways = file.is_true("locations_on_ways");
@ -297,7 +298,7 @@ namespace osmium {
~OPLOutputFormat() noexcept final = default;
void write_buffer(osmium::memory::Buffer&& buffer) final {
m_output_queue.push(osmium::thread::Pool::instance().submit(OPLOutputBlock{std::move(buffer), m_options}));
m_output_queue.push(m_pool.submit(OPLOutputBlock{std::move(buffer), m_options}));
}
}; // class OPLOutputFormat
@ -305,8 +306,8 @@ namespace osmium {
// we want the register_output_format() function to run, setting
// the variable is only a side-effect, it will never be used
const bool registered_opl_output = osmium::io::detail::OutputFormatFactory::instance().register_output_format(osmium::io::file_format::opl,
[](const osmium::io::File& file, future_string_queue_type& output_queue) {
return new osmium::io::detail::OPLOutputFormat(file, output_queue);
[](osmium::thread::Pool& pool, const osmium::io::File& file, future_string_queue_type& output_queue) {
return new osmium::io::detail::OPLOutputFormat(pool, file, output_queue);
});
// dummy function to silence the unused variable warning from above

View File

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

View File

@ -46,6 +46,7 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/io/file.hpp>
#include <osmium/io/file_format.hpp>
#include <osmium/memory/buffer.hpp>
#include <osmium/thread/pool.hpp>
namespace osmium {
@ -107,6 +108,7 @@ namespace osmium {
protected:
osmium::thread::Pool& m_pool;
future_string_queue_type& m_output_queue;
/**
@ -119,7 +121,8 @@ namespace osmium {
public:
explicit OutputFormat(future_string_queue_type& output_queue) :
OutputFormat(osmium::thread::Pool& pool, future_string_queue_type& output_queue) :
m_pool(pool),
m_output_queue(output_queue) {
}
@ -152,7 +155,7 @@ namespace osmium {
public:
using create_output_type = std::function<osmium::io::detail::OutputFormat*(const osmium::io::File&, future_string_queue_type&)>;
using create_output_type = std::function<osmium::io::detail::OutputFormat*(osmium::thread::Pool&, const osmium::io::File&, future_string_queue_type&)>;
private:
@ -178,22 +181,52 @@ namespace osmium {
return true;
}
std::unique_ptr<osmium::io::detail::OutputFormat> create_output(const osmium::io::File& file, future_string_queue_type& output_queue) {
auto it = m_callbacks.find(file.format());
std::unique_ptr<osmium::io::detail::OutputFormat> create_output(osmium::thread::Pool& pool, const osmium::io::File& file, future_string_queue_type& output_queue) {
const auto it = m_callbacks.find(file.format());
if (it != m_callbacks.end()) {
return std::unique_ptr<osmium::io::detail::OutputFormat>((it->second)(file, output_queue));
return std::unique_ptr<osmium::io::detail::OutputFormat>((it->second)(pool, file, output_queue));
}
throw unsupported_file_format_error(
std::string("Can not open file '") +
throw unsupported_file_format_error{
std::string{"Can not open file '"} +
file.filename() +
"' with type '" +
as_string(file.format()) +
"'. No support for writing this format in this program.");
"'. No support for writing this format in this program."};
}
}; // class OutputFormatFactory
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 io

View File

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

View File

@ -33,15 +33,14 @@ DEALINGS IN THE SOFTWARE.
*/
#include <algorithm>
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <future>
#include <memory>
#include <string>
#include <type_traits>
#include <utility>
#include <protozero/pbf_message.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_decoder.hpp>
#include <osmium/io/detail/protobuf_tags.hpp>
#include <osmium/io/detail/queue_util.hpp>
#include <osmium/io/file_format.hpp>
#include <osmium/io/header.hpp>
#include <osmium/osm/entity_bits.hpp>
@ -77,14 +75,14 @@ namespace osmium {
*/
std::string read_from_input_queue(size_t size) {
while (m_input_buffer.size() < size) {
const std::string new_data = get_input();
const std::string new_data{get_input()};
if (input_done()) {
throw osmium::pbf_error("truncated data (EOF encountered)");
throw osmium::pbf_error{"truncated data (EOF encountered)"};
}
m_input_buffer += new_data;
}
std::string output { m_input_buffer.substr(size) };
std::string output{m_input_buffer.substr(size)};
m_input_buffer.resize(size);
using std::swap;
@ -101,7 +99,7 @@ namespace osmium {
uint32_t size_in_network_byte_order;
try {
const std::string input_data = read_from_input_queue(sizeof(size_in_network_byte_order));
const std::string input_data{read_from_input_queue(sizeof(size_in_network_byte_order))};
size_in_network_byte_order = *reinterpret_cast<const uint32_t*>(input_data.data());
} catch (const osmium::pbf_error&) {
return 0; // EOF
@ -109,7 +107,7 @@ namespace osmium {
const uint32_t size = ntohl(size_in_network_byte_order);
if (size > static_cast<uint32_t>(max_blob_header_size)) {
throw osmium::pbf_error("invalid BlobHeader size (> max_blob_header_size)");
throw osmium::pbf_error{"invalid BlobHeader size (> max_blob_header_size)"};
}
return size;
@ -137,11 +135,11 @@ namespace osmium {
}
if (blob_header_datasize == 0) {
throw osmium::pbf_error("PBF format error: BlobHeader.datasize missing or zero.");
throw osmium::pbf_error{"PBF format error: BlobHeader.datasize missing or zero."};
}
if (std::strncmp(expected_type, blob_header_type.data(), blob_header_type.size())) {
throw osmium::pbf_error("blob does not have expected type (OSMHeader in first blob, OSMData in following blobs)");
throw osmium::pbf_error{"blob does not have expected type (OSMHeader in first blob, OSMData in following blobs)"};
}
return blob_header_datasize;
@ -155,35 +153,34 @@ namespace osmium {
return 0;
}
const std::string blob_header = read_from_input_queue(size);
const std::string blob_header{read_from_input_queue(size)};
return decode_blob_header(protozero::pbf_message<FileFormat::BlobHeader>(blob_header), expected_type);
}
std::string read_from_input_queue_with_check(size_t size) {
if (size > max_uncompressed_blob_size) {
throw osmium::pbf_error(std::string("invalid blob size: " +
std::to_string(size)));
throw osmium::pbf_error{std::string{"invalid blob size: "} +
std::to_string(size)};
}
return read_from_input_queue(size);
}
// Parse the header in the PBF OSMHeader blob.
void parse_header_blob() {
osmium::io::Header header;
const auto size = check_type_and_get_blob_size("OSMHeader");
header = decode_header(read_from_input_queue_with_check(size));
osmium::io::Header header{decode_header(read_from_input_queue_with_check(size))};
set_header_value(header);
}
void parse_data_blobs() {
while (const auto size = check_type_and_get_blob_size("OSMData")) {
std::string input_buffer = read_from_input_queue_with_check(size);
std::string input_buffer{read_from_input_queue_with_check(size)};
PBFDataBlobDecoder data_blob_parser{std::move(input_buffer), read_types(), read_metadata()};
if (osmium::config::use_pool_threads_for_pbf_parsing()) {
send_to_output_queue(osmium::thread::Pool::instance().submit(std::move(data_blob_parser)));
send_to_output_queue(get_pool().submit(std::move(data_blob_parser)));
} else {
send_to_output_queue(data_blob_parser());
}
@ -192,11 +189,8 @@ namespace osmium {
public:
PBFParser(future_string_queue_type& input_queue,
future_buffer_queue_type& output_queue,
std::promise<osmium::io::Header>& header_promise,
osmium::io::detail::reader_options options) :
Parser(input_queue, output_queue, header_promise, options),
explicit PBFParser(parser_arguments& args) :
Parser(args),
m_input_buffer() {
}
@ -218,11 +212,8 @@ namespace osmium {
// the variable is only a side-effect, it will never be used
const bool registered_pbf_parser = ParserFactory::instance().register_parser(
file_format::pbf,
[](future_string_queue_type& input_queue,
future_buffer_queue_type& output_queue,
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));
[](parser_arguments& args) {
return std::unique_ptr<Parser>(new PBFParser{args});
});
// 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 <cmath>
#include <cstdint>
#include <cstdlib>
#include <iterator>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include <protozero/pbf_builder.hpp>
#include <protozero/pbf_writer.hpp>
@ -171,7 +170,7 @@ namespace osmium {
assert(m_msg.size() <= max_uncompressed_blob_size);
std::string blob_data;
protozero::pbf_builder<FileFormat::Blob> pbf_blob(blob_data);
protozero::pbf_builder<FileFormat::Blob> pbf_blob{blob_data};
if (m_use_compression) {
pbf_blob.add_int32(FileFormat::Blob::optional_int32_raw_size, int32_t(m_msg.size()));
@ -181,12 +180,12 @@ namespace osmium {
}
std::string blob_header_data;
protozero::pbf_builder<FileFormat::BlobHeader> pbf_blob_header(blob_header_data);
protozero::pbf_builder<FileFormat::BlobHeader> pbf_blob_header{blob_header_data};
pbf_blob_header.add_string(FileFormat::BlobHeader::required_string_type, m_blob_type == pbf_blob_type::data ? "OSMData" : "OSMHeader");
pbf_blob_header.add_int32(FileFormat::BlobHeader::required_int32_datasize, static_cast_with_assert<int32_t>(blob_data.size()));
uint32_t sz = htonl(static_cast_with_assert<uint32_t>(blob_header_data.size()));
const uint32_t sz = htonl(static_cast_with_assert<uint32_t>(blob_header_data.size()));
// write to output: the 4-byte BlobHeader-Size followed by the BlobHeader followed by the Blob
std::string output;
@ -270,7 +269,7 @@ namespace osmium {
m_delta_lon.clear();
}
size_t size() const {
std::size_t size() const {
return m_ids.size() * 3 * sizeof(int64_t);
}
@ -300,12 +299,12 @@ namespace osmium {
std::string serialize() const {
std::string data;
protozero::pbf_builder<OSMFormat::DenseNodes> pbf_dense_nodes(data);
protozero::pbf_builder<OSMFormat::DenseNodes> pbf_dense_nodes{data};
pbf_dense_nodes.add_packed_sint64(OSMFormat::DenseNodes::packed_sint64_id, m_ids.cbegin(), m_ids.cend());
if (m_options.add_metadata) {
protozero::pbf_builder<OSMFormat::DenseInfo> pbf_dense_info(pbf_dense_nodes, OSMFormat::DenseNodes::optional_DenseInfo_denseinfo);
protozero::pbf_builder<OSMFormat::DenseInfo> pbf_dense_info{pbf_dense_nodes, OSMFormat::DenseNodes::optional_DenseInfo_denseinfo};
pbf_dense_info.add_packed_int32(OSMFormat::DenseInfo::packed_int32_version, m_versions.cbegin(), m_versions.cend());
pbf_dense_info.add_packed_sint64(OSMFormat::DenseInfo::packed_sint64_timestamp, m_timestamps.cbegin(), m_timestamps.cend());
pbf_dense_info.add_packed_sint64(OSMFormat::DenseInfo::packed_sint64_changeset, m_changesets.cbegin(), m_changesets.cend());
@ -390,7 +389,7 @@ namespace osmium {
return m_type;
}
size_t size() const {
std::size_t size() const {
return m_pbf_primitive_group_data.size() + m_stringtable.size() + m_dense_nodes.size();
}
@ -400,7 +399,7 @@ namespace osmium {
* enough space for the string table (which typically
* needs about 0.1 to 0.3% of the block size).
*/
constexpr static size_t max_used_blob_size = max_uncompressed_blob_size * 95 / 100;
constexpr static std::size_t max_used_blob_size = max_uncompressed_blob_size * 95 / 100;
bool can_add(OSMFormat::PrimitiveGroup type) const {
if (type != m_type) {
@ -426,16 +425,16 @@ namespace osmium {
}
std::string primitive_block_data;
protozero::pbf_builder<OSMFormat::PrimitiveBlock> primitive_block(primitive_block_data);
protozero::pbf_builder<OSMFormat::PrimitiveBlock> primitive_block{primitive_block_data};
{
protozero::pbf_builder<OSMFormat::StringTable> pbf_string_table(primitive_block, OSMFormat::PrimitiveBlock::required_StringTable_stringtable);
protozero::pbf_builder<OSMFormat::StringTable> pbf_string_table{primitive_block, OSMFormat::PrimitiveBlock::required_StringTable_stringtable};
m_primitive_block.write_stringtable(pbf_string_table);
}
primitive_block.add_message(OSMFormat::PrimitiveBlock::repeated_PrimitiveGroup_primitivegroup, m_primitive_block.group_data());
m_output_queue.push(osmium::thread::Pool::instance().submit(
m_output_queue.push(m_pool.submit(
SerializeBlob{std::move(primitive_block_data),
pbf_blob_type::data,
m_options.use_compression}
@ -459,7 +458,7 @@ namespace osmium {
}
if (m_options.add_metadata) {
protozero::pbf_builder<OSMFormat::Info> pbf_info(pbf_object, T::enum_type::optional_Info_info);
protozero::pbf_builder<OSMFormat::Info> pbf_info{pbf_object, T::enum_type::optional_Info_info};
pbf_info.add_int32(OSMFormat::Info::optional_int32_version, static_cast_with_assert<int32_t>(object.version()));
pbf_info.add_int64(OSMFormat::Info::optional_int64_timestamp, uint32_t(object.timestamp()));
@ -481,8 +480,8 @@ namespace osmium {
public:
PBFOutputFormat(const osmium::io::File& file, future_string_queue_type& output_queue) :
OutputFormat(output_queue),
PBFOutputFormat(osmium::thread::Pool& pool, const osmium::io::File& file, future_string_queue_type& output_queue) :
OutputFormat(pool, output_queue),
m_options(),
m_primitive_block(m_options) {
m_options.use_dense_nodes = file.is_not_false("pbf_dense_nodes");
@ -500,10 +499,10 @@ namespace osmium {
void write_header(const osmium::io::Header& header) final {
std::string data;
protozero::pbf_builder<OSMFormat::HeaderBlock> pbf_header_block(data);
protozero::pbf_builder<OSMFormat::HeaderBlock> pbf_header_block{data};
if (!header.boxes().empty()) {
protozero::pbf_builder<OSMFormat::HeaderBBox> pbf_header_bbox(pbf_header_block, OSMFormat::HeaderBlock::optional_HeaderBBox_bbox);
protozero::pbf_builder<OSMFormat::HeaderBBox> pbf_header_bbox{pbf_header_block, OSMFormat::HeaderBlock::optional_HeaderBBox_bbox};
osmium::Box box = header.joined_boxes();
pbf_header_bbox.add_sint64(OSMFormat::HeaderBBox::required_sint64_left, int64_t(box.bottom_left().lon() * lonlat_resolution));
@ -528,23 +527,23 @@ namespace osmium {
pbf_header_block.add_string(OSMFormat::HeaderBlock::optional_string_writingprogram, header.get("generator"));
const std::string osmosis_replication_timestamp = header.get("osmosis_replication_timestamp");
const std::string osmosis_replication_timestamp{header.get("osmosis_replication_timestamp")};
if (!osmosis_replication_timestamp.empty()) {
osmium::Timestamp ts(osmosis_replication_timestamp.c_str());
osmium::Timestamp ts{osmosis_replication_timestamp.c_str()};
pbf_header_block.add_int64(OSMFormat::HeaderBlock::optional_int64_osmosis_replication_timestamp, uint32_t(ts));
}
const std::string osmosis_replication_sequence_number = header.get("osmosis_replication_sequence_number");
const std::string osmosis_replication_sequence_number{header.get("osmosis_replication_sequence_number")};
if (!osmosis_replication_sequence_number.empty()) {
pbf_header_block.add_int64(OSMFormat::HeaderBlock::optional_int64_osmosis_replication_sequence_number, std::atoll(osmosis_replication_sequence_number.c_str()));
}
const std::string osmosis_replication_base_url = header.get("osmosis_replication_base_url");
const std::string osmosis_replication_base_url{header.get("osmosis_replication_base_url")};
if (!osmosis_replication_base_url.empty()) {
pbf_header_block.add_string(OSMFormat::HeaderBlock::optional_string_osmosis_replication_base_url, osmosis_replication_base_url);
}
m_output_queue.push(osmium::thread::Pool::instance().submit(
m_output_queue.push(m_pool.submit(
SerializeBlob{std::move(data),
pbf_blob_type::header,
m_options.use_compression}
@ -567,7 +566,7 @@ namespace osmium {
}
switch_primitive_block_type(OSMFormat::PrimitiveGroup::repeated_Node_nodes);
protozero::pbf_builder<OSMFormat::Node> pbf_node{ m_primitive_block.group(), OSMFormat::PrimitiveGroup::repeated_Node_nodes };
protozero::pbf_builder<OSMFormat::Node> pbf_node{m_primitive_block.group(), OSMFormat::PrimitiveGroup::repeated_Node_nodes};
pbf_node.add_sint64(OSMFormat::Node::required_sint64_id, node.id());
add_meta(node, pbf_node);
@ -578,7 +577,7 @@ namespace osmium {
void way(const osmium::Way& way) {
switch_primitive_block_type(OSMFormat::PrimitiveGroup::repeated_Way_ways);
protozero::pbf_builder<OSMFormat::Way> pbf_way{ m_primitive_block.group(), OSMFormat::PrimitiveGroup::repeated_Way_ways };
protozero::pbf_builder<OSMFormat::Way> pbf_way{m_primitive_block.group(), OSMFormat::PrimitiveGroup::repeated_Way_ways};
pbf_way.add_int64(OSMFormat::Way::required_int64_id, way.id());
add_meta(way, pbf_way);
@ -611,7 +610,7 @@ namespace osmium {
void relation(const osmium::Relation& relation) {
switch_primitive_block_type(OSMFormat::PrimitiveGroup::repeated_Relation_relations);
protozero::pbf_builder<OSMFormat::Relation> pbf_relation { m_primitive_block.group(), OSMFormat::PrimitiveGroup::repeated_Relation_relations };
protozero::pbf_builder<OSMFormat::Relation> pbf_relation{m_primitive_block.group(), OSMFormat::PrimitiveGroup::repeated_Relation_relations};
pbf_relation.add_int64(OSMFormat::Relation::required_int64_id, relation.id());
add_meta(relation, pbf_relation);
@ -644,8 +643,8 @@ namespace osmium {
// we want the register_output_format() function to run, setting
// the variable is only a side-effect, it will never be used
const bool registered_pbf_output = osmium::io::detail::OutputFormatFactory::instance().register_output_format(osmium::io::file_format::pbf,
[](const osmium::io::File& file, future_string_queue_type& output_queue) {
return new osmium::io::detail::PBFOutputFormat(file, output_queue);
[](osmium::thread::Pool& pool, const osmium::io::File& file, future_string_queue_type& output_queue) {
return new osmium::io::detail::PBFOutputFormat{pool, file, output_queue};
});
// dummy function to silence the unused variable warning from above

View File

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

View File

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

View File

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

View File

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

View File

@ -444,12 +444,14 @@ namespace osmium {
item_type type = item_type::undefined;
object_id_type ref = 0;
bool ref_is_set = false;
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")) {
type = char_to_item_type(value[0]);
} else if (!std::strcmp(name, "ref")) {
ref = osmium::string_to_object_id(value);
ref_is_set = true;
} else if (!std::strcmp(name, "role")) {
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) {
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"};
}
m_rml_builder->add_member(type, ref, role);
@ -625,11 +627,8 @@ namespace osmium {
public:
XMLParser(future_string_queue_type& input_queue,
future_buffer_queue_type& output_queue,
std::promise<osmium::io::Header>& header_promise,
osmium::io::detail::reader_options options) :
Parser(input_queue, output_queue, header_promise, options),
explicit XMLParser(parser_arguments& args) :
Parser(args),
m_context(context::root),
m_last_context(context::root),
m_in_delete_section(false),
@ -673,11 +672,8 @@ namespace osmium {
// the variable is only a side-effect, it will never be used
const bool registered_xml_parser = ParserFactory::instance().register_parser(
file_format::xml,
[](future_string_queue_type& input_queue,
future_buffer_queue_type& output_queue,
std::promise<osmium::io::Header>& header_promise,
osmium::io::detail::reader_options options) {
return std::unique_ptr<Parser>(new XMLParser{input_queue, output_queue, header_promise, options});
[](parser_arguments& args) {
return std::unique_ptr<Parser>(new XMLParser{args});
});
// 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 <memory>
#include <string>
@ -397,7 +396,8 @@ namespace osmium {
write_attribute("uid", changeset.uid());
}
if (changeset.bounds()) {
if (!changeset.bounds().bottom_left().is_undefined() ||
!changeset.bounds().top_right().is_undefined()) {
detail::append_lat_lon_attributes(*m_out, "min_lat", "min_lon", changeset.bounds().bottom_left());
detail::append_lat_lon_attributes(*m_out, "max_lat", "max_lon", changeset.bounds().top_right());
}
@ -431,8 +431,8 @@ namespace osmium {
public:
XMLOutputFormat(const osmium::io::File& file, future_string_queue_type& output_queue) :
OutputFormat(output_queue),
XMLOutputFormat(osmium::thread::Pool& pool, const osmium::io::File& file, future_string_queue_type& output_queue) :
OutputFormat(pool, output_queue),
m_options() {
m_options.add_metadata = file.is_not_false("add_metadata");
m_options.use_change_ops = file.is_true("xml_change_format");
@ -446,14 +446,14 @@ namespace osmium {
~XMLOutputFormat() noexcept final = default;
void write_header(const osmium::io::Header& header) final {
std::string out = "<?xml version='1.0' encoding='UTF-8'?>\n";
std::string out{"<?xml version='1.0' encoding='UTF-8'?>\n"};
if (m_options.use_change_ops) {
out += "<osmChange version=\"0.6\" generator=\"";
} else {
out += "<osm version=\"0.6\"";
std::string xml_josm_upload = header.get("xml_josm_upload");
const std::string xml_josm_upload{header.get("xml_josm_upload")};
if (xml_josm_upload == "true" || xml_josm_upload == "false") {
out += " upload=\"";
out += xml_josm_upload;
@ -475,7 +475,7 @@ namespace osmium {
}
void write_buffer(osmium::memory::Buffer&& buffer) final {
m_output_queue.push(osmium::thread::Pool::instance().submit(XMLOutputBlock{std::move(buffer), m_options}));
m_output_queue.push(m_pool.submit(XMLOutputBlock{std::move(buffer), m_options}));
}
void write_end() final {
@ -495,8 +495,8 @@ namespace osmium {
// we want the register_output_format() function to run, setting
// the variable is only a side-effect, it will never be used
const bool registered_xml_output = osmium::io::detail::OutputFormatFactory::instance().register_output_format(osmium::io::file_format::xml,
[](const osmium::io::File& file, future_string_queue_type& output_queue) {
return new osmium::io::detail::XMLOutputFormat(file, output_queue);
[](osmium::thread::Pool& pool, const osmium::io::File& file, future_string_queue_type& output_queue) {
return new osmium::io::detail::XMLOutputFormat(pool, file, output_queue);
});
// dummy function to silence the unused variable warning from above

View File

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

View File

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

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