[libosmium] 01/06: Imported Upstream version 2.9.0
Bas Couwenberg
sebastic at debian.org
Thu Sep 15 14:03:14 UTC 2016
This is an automated email from the git hooks/post-receive script.
sebastic pushed a commit to branch master
in repository libosmium.
commit 6928a9c709db4ac9fdd95e4ae7ba634283a7a27b
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date: Thu Sep 15 15:21:20 2016 +0200
Imported Upstream version 2.9.0
---
.gitignore | 2 +
.ycm_extra_conf.py | 5 +
CHANGELOG.md | 36 +-
CMakeLists.txt | 2 +-
CONTRIBUTING.md | 147 +--
CONTRIBUTING.md => NOTES_FOR_DEVELOPERS.md | 12 +-
appveyor.yml | 83 +-
benchmarks/osmium_benchmark_count.cpp | 8 +-
benchmarks/osmium_benchmark_count_tag.cpp | 8 +-
benchmarks/osmium_benchmark_index_map.cpp | 16 +-
.../osmium_benchmark_static_vs_dynamic_index.cpp | 58 +-
benchmarks/osmium_benchmark_write_pbf.cpp | 17 +-
build-appveyor.bat | 123 +++
build-local.bat | 43 +
cmake/iwyu.sh | 5 +
examples/CMakeLists.txt | 8 +-
examples/README.md | 32 +
examples/osmium_area_test.cpp | 131 ++-
examples/osmium_convert.cpp | 92 +-
examples/osmium_count.cpp | 69 +-
examples/osmium_create_node_cache.cpp | 55 -
examples/osmium_debug.cpp | 46 +-
examples/osmium_filter_discussions.cpp | 48 +-
examples/osmium_index.cpp | 22 +-
examples/osmium_location_cache_create.cpp | 87 ++
examples/osmium_location_cache_use.cpp | 101 ++
examples/osmium_pub_names.cpp | 89 ++
examples/osmium_read.cpp | 26 +-
examples/osmium_read_with_progress.cpp | 56 +
examples/osmium_road_length.cpp | 92 ++
examples/osmium_serdump.cpp | 24 +-
examples/osmium_tiles.cpp | 72 ++
examples/osmium_use_node_cache.cpp | 68 --
include/osmium/area/assembler.hpp | 46 +-
include/osmium/area/detail/node_ref_segment.hpp | 17 +-
include/osmium/area/detail/proto_ring.hpp | 5 +-
include/osmium/area/detail/segment_list.hpp | 23 +-
include/osmium/area/detail/vector.hpp | 1 +
include/osmium/area/multipolygon_collector.hpp | 7 +-
include/osmium/area/problem_reporter.hpp | 2 +
include/osmium/area/problem_reporter_exception.hpp | 1 +
include/osmium/area/problem_reporter_ogr.hpp | 8 +-
include/osmium/builder/attr.hpp | 37 +-
include/osmium/builder/builder.hpp | 3 +-
include/osmium/builder/builder_helper.hpp | 8 +-
include/osmium/builder/osm_object_builder.hpp | 10 +-
include/osmium/diff_iterator.hpp | 2 +
include/osmium/dynamic_handler.hpp | 7 +-
include/osmium/experimental/flex_reader.hpp | 3 +-
include/osmium/geom/factory.hpp | 8 +-
include/osmium/geom/geojson.hpp | 1 +
include/osmium/geom/geos.hpp | 32 +-
include/osmium/geom/haversine.hpp | 2 +-
include/osmium/geom/ogr.hpp | 2 +-
include/osmium/geom/projection.hpp | 22 +-
include/osmium/geom/rapid_geojson.hpp | 2 +
include/osmium/geom/tile.hpp | 45 +-
include/osmium/geom/util.hpp | 4 +-
include/osmium/geom/wkb.hpp | 8 +-
include/osmium/geom/wkt.hpp | 3 -
include/osmium/handler.hpp | 56 +-
include/osmium/handler/check_order.hpp | 4 +-
include/osmium/handler/node_locations_for_ways.hpp | 2 +-
include/osmium/index/detail/create_map_with_fd.hpp | 4 +-
include/osmium/index/detail/mmap_vector_file.hpp | 4 +-
include/osmium/index/detail/vector_map.hpp | 2 +-
include/osmium/index/detail/vector_multimap.hpp | 2 +-
include/osmium/index/index.hpp | 4 +-
include/osmium/index/map.hpp | 2 +-
include/osmium/index/map/sparse_mem_map.hpp | 1 -
include/osmium/io/any_input.hpp | 3 +-
include/osmium/io/bzip2_compression.hpp | 10 +-
include/osmium/io/compression.hpp | 31 +-
include/osmium/io/detail/debug_output_format.hpp | 119 ++-
include/osmium/io/detail/input_format.hpp | 2 +-
include/osmium/io/detail/o5m_input_format.hpp | 13 +-
include/osmium/io/detail/opl_input_format.hpp | 156 +++
include/osmium/io/detail/opl_output_format.hpp | 25 +-
include/osmium/io/detail/opl_parser_functions.hpp | 747 ++++++++++++++
include/osmium/io/detail/output_format.hpp | 4 +-
include/osmium/io/detail/pbf_decoder.hpp | 36 +-
include/osmium/io/detail/pbf_input_format.hpp | 15 +-
include/osmium/io/detail/pbf_output_format.hpp | 14 +-
include/osmium/io/detail/read_write.hpp | 7 +-
include/osmium/io/detail/string_table.hpp | 9 +-
include/osmium/io/detail/string_util.hpp | 27 +-
include/osmium/io/detail/write_thread.hpp | 1 +
include/osmium/io/detail/xml_input_format.hpp | 11 +-
include/osmium/io/detail/xml_output_format.hpp | 11 +-
include/osmium/io/detail/zlib.hpp | 6 +-
include/osmium/io/file.hpp | 6 +-
include/osmium/io/gzip_compression.hpp | 12 +-
include/osmium/io/input_iterator.hpp | 1 -
include/osmium/{version.hpp => io/opl_input.hpp} | 18 +-
include/osmium/io/output_iterator.hpp | 3 -
include/osmium/io/overwrite.hpp | 2 +-
include/osmium/io/reader.hpp | 43 +-
include/osmium/io/writer.hpp | 12 +-
include/osmium/memory/item.hpp | 34 +-
include/osmium/memory/item_iterator.hpp | 15 +-
include/osmium/object_pointer_collection.hpp | 2 -
include/osmium/{tags/taglist.hpp => opl.hpp} | 50 +-
include/osmium/osm.hpp | 15 +-
include/osmium/osm/area.hpp | 2 +
include/osmium/osm/box.hpp | 1 -
include/osmium/osm/changeset.hpp | 7 +
include/osmium/osm/crc.hpp | 28 +-
include/osmium/osm/diff_object.hpp | 5 +-
include/osmium/osm/location.hpp | 156 +--
include/osmium/osm/node_ref_list.hpp | 3 +-
include/osmium/osm/object.hpp | 23 +-
include/osmium/osm/object_comparisons.hpp | 3 +
include/osmium/osm/relation.hpp | 2 +-
include/osmium/osm/segment.hpp | 1 -
include/osmium/osm/tag.hpp | 1 -
include/osmium/osm/timestamp.hpp | 83 +-
include/osmium/osm/types_from_string.hpp | 3 +-
include/osmium/osm/way.hpp | 5 +-
include/osmium/relations/collector.hpp | 14 +-
include/osmium/relations/detail/member_meta.hpp | 2 -
include/osmium/tags/filter.hpp | 1 +
include/osmium/tags/taglist.hpp | 2 +-
include/osmium/thread/pool.hpp | 4 +-
include/osmium/thread/queue.hpp | 4 +-
include/osmium/thread/util.hpp | 2 +
include/osmium/util/delta.hpp | 3 +-
include/osmium/util/double.hpp | 3 +-
include/osmium/util/file.hpp | 82 +-
include/osmium/util/iterator.hpp | 3 +-
include/osmium/util/memory_mapping.hpp | 9 +-
include/osmium/util/options.hpp | 9 +-
include/osmium/util/progress_bar.hpp | 179 ++++
include/osmium/util/string.hpp | 2 +-
include/osmium/util/verbose_output.hpp | 8 +-
include/osmium/version.hpp | 4 +-
include/protozero/iterators.hpp | 10 +-
include/protozero/pbf_writer.hpp | 8 +-
include/protozero/version.hpp | 4 +-
osmium.imp | 9 +-
test/CMakeLists.txt | 2 +
test/data-tests/include/common.hpp | 6 +-
test/data-tests/testdata-multipolygon.cpp | 56 +-
test/data-tests/testdata-overview.cpp | 23 +-
test/data-tests/testdata-testcases.cpp | 6 +-
test/data-tests/testdata-xml.cpp | 90 +-
test/t/basic/test_area.cpp | 78 ++
test/t/basic/test_location.cpp | 93 +-
test/t/basic/test_node.cpp | 68 +-
test/t/basic/test_timestamp.cpp | 44 +
test/t/geom/test_tile.cpp | 140 +--
test/t/geom/test_wkb.cpp | 167 +--
test/t/geom/test_wkt.cpp | 188 ++--
test/t/index/test_id_to_location.cpp | 26 +-
test/t/io/test_opl_parser.cpp | 1075 ++++++++++++++++++++
test/t/io/test_reader_with_mock_decompression.cpp | 10 +-
test/t/io/test_reader_with_mock_parser.cpp | 6 +-
test/t/io/test_writer_with_mock_compression.cpp | 2 +-
test/t/tags/test_filter.cpp | 6 +-
test/t/util/test_cast_with_assert.cpp | 2 +-
159 files changed, 4938 insertions(+), 1368 deletions(-)
diff --git a/.gitignore b/.gitignore
index 5013903..79e5e65 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,4 @@
*.swp
.ycm_extra_conf.pyc
+/build
+/libosmium-deps
diff --git a/.ycm_extra_conf.py b/.ycm_extra_conf.py
index 2b87306..6fc1937 100644
--- a/.ycm_extra_conf.py
+++ b/.ycm_extra_conf.py
@@ -29,6 +29,11 @@ flags = [
'-x',
'c++',
+# workaround for https://github.com/Valloric/YouCompleteMe/issues/303
+# also see https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=800618
+'-isystem',
+'/usr/lib/ycmd/clang_includes/',
+
# libosmium include dirs
'-I%s/include' % basedir,
'-I%s/test/include' % basedir,
diff --git a/CHANGELOG.md b/CHANGELOG.md
index bb192ab..0d132ef 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,6 +13,39 @@ This project adheres to [Semantic Versioning](http://semver.org/).
### Fixed
+## [2.9.0] - 2016-09-15
+
+### Added
+
+- Support for reading OPL files.
+- For diff output OSM objects in buffers can be marked as only in one or the
+ other file. The OPL and debug output formats support diff output based on
+ this.
+- Add documentation and range checks to `Tile` struct.
+- More documentation.
+- More examples and more extensive comments on examples.
+- Support for a progress report in `osmium::io::Reader()` and a `ProgressBar`
+ utility class to use it.
+- New `OSMObject::set_timestamp(const char*)` function.
+
+### Changed
+
+- Parse coordinates in scientific notations ourselves.
+- Updated included protozero version to 1.4.2.
+- Lots of one-argument constructors are now explicit.
+- Timestamp parser now uses our own implementation instead of strptime.
+ This is faster and independant of locale settings.
+- More cases of invalid areas with duplicate segments are reported as
+ errors.
+
+### Fixed
+
+- Fixed a problem limiting cache file sizes on Windows to 32 bit.
+- Fixed includes.
+- Exception messages for invalid areas do not report "area contains no rings"
+ any more, but "invalid area".
+
+
## [2.8.0] - 2016-08-04
### Added
@@ -377,7 +410,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
Doxygen (up to version 1.8.8). This version contains a workaround to fix
this.
-[unreleased]: https://github.com/osmcode/libosmium/compare/v2.8.0...HEAD
+[unreleased]: https://github.com/osmcode/libosmium/compare/v2.9.0...HEAD
+[2.9.0]: https://github.com/osmcode/libosmium/compare/v2.8.0...v2.9.0
[2.8.0]: https://github.com/osmcode/libosmium/compare/v2.7.2...v2.8.0
[2.7.2]: https://github.com/osmcode/libosmium/compare/v2.7.1...v2.7.2
[2.7.1]: https://github.com/osmcode/libosmium/compare/v2.7.0...v2.7.1
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c82cdd0..095137b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -24,7 +24,7 @@ set(CMAKE_CONFIGURATION_TYPES "Debug;Release;RelWithDebInfo;MinSizeRel;Dev;Cover
project(libosmium)
set(LIBOSMIUM_VERSION_MAJOR 2)
-set(LIBOSMIUM_VERSION_MINOR 8)
+set(LIBOSMIUM_VERSION_MINOR 9)
set(LIBOSMIUM_VERSION_PATCH 0)
set(LIBOSMIUM_VERSION
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 1064b94..a054f36 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,143 +1,12 @@
-# Notes for Developers
+Some rules for contributing to this project:
-Read this if you want to contribute to Libosmium.
+* Please open a separate issue for each problem, question, or comment you have.
+ Do not re-use existing issues for other topics, even if they are similar. This
+ keeps issues small and manageable and makes it much easier to follow through
+ and make sure each problem is taken care of.
-
-## Versioning
-
-Osmium is currently considered in beta and doesn't use versioning yet. Proper
-versions will be introduced as soon as it is somewhat stable.
-
-
-## Namespace
-
-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.
-
-One drawback ist that you can't have static data in classes, because there
-is no place to put this data.
-
-All free functions must be declared `inline`.
-
-
-## Coding Conventions
-
-These coding conventions have been changing over time and some code is still
-different.
-
-* All include files have `#ifdef` guards around them, macros are the path name
- in all uppercase where the slashes (`/`) have been changed to underscore (`_`).
-* Class names begin with uppercase chars and use CamelCase. Smaller helper
- classes are usually defined as struct and have lowercase names.
-* Macros (and only macros) are all uppercase. Use macros sparingly, usually
- a simple (maybe constexpr) inline function is better. Undef macros after use
- if possible.
-* Macros should only be used for controlling which parts of the code should be
- included when compiling or to avoid major code repetitions.
-* Variables, attributes, and function names are lowercase with
- `underscores_between_words`.
-* Class attribute names start with `m_` (member).
-* Use `descriptive_variable_names`, exceptions are well-established conventions
- like `i` for a loop variable. Iterators are usually called `it`.
-* Declare variables where they are first used (C++ style), not at the beginning
- of a function (old C style).
-* Names from external namespaces (even `std`) are always mentioned explicitly.
- Do not use `using` (except for `std::swap`). This way we can't even by
- accident pollute the namespace of the code using Osmium.
-* Always use the standard swap idiom: `using std::swap; swap(foo, bar);`.
-* `#include` directives appear in three "blocks" after the copyright notice.
- The blocks are separated by blank lines. First block contains `#include`s for
- standard C/C++ includes, second block for any external libs used, third
- block for osmium internal includes. Within each block `#include`s are usually
- sorted by path name. All `#include`s use `<>` syntax not `""`.
-* Names not to be used from outside the library should be in a namespace
- called `detail` under the namespace where they would otherwise appear. If
- whole include files are never meant to be included from outside they should
- be in a subdirectory called `detail`.
-* All files have suffix `.hpp`.
-* Closing } of all classes and namespaces should have a trailing comment
- with the name of the class/namespace.
-* All constructors with one (or more arguments if they have a default) should
- be declared "explicit" unless there is a reason for them not to be. Document
- that reason.
-* If a class has any of the special methods (copy/move constructor/assigment,
- destructor) it should have all of them, possibly marking them as default or
- deleted.
-* Typedefs have `names_like_this_type` which end in `_type`. Typedefs should
- use the new `using foo_type = bar` syntax instead of the old
- `typedef bar foo_type`.
-* 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
- always has a space to the right: `template <typename... TArgs>` etc.
-
-Keep to the indentation and other styles used in the code. Use `make indent`
-in the toplevel directory to fix indentation and styling. It calls `astyle`
-with the right parameters. This program is in the `astyle` Debian package.
-
-
-## C++11
-
-Osmium uses C++11 and you can use its features such as auto, lambdas,
-threading, etc. There are a few features we do not use, because even modern
-compilers don't support them yet. This list might change as we get more data
-about which compilers support which feature and what operating system versions
-or distributions have which versions of these compilers installed.
-
-GCC 4.6 - too old, not supported (Ubuntu 12.04 LTS)
-GCC 4.7.2 - can probably not be supported (Debian wheezy)
-GCC 4.7.3 - probably works
-GCC 4.8 - works and is supported from here on
-clang 3.0 - too old, not supported (Debian wheezy, Ubuntu 12.04 LTS)
-clang 3.2 - probably works
-clang 3.5 - works and is supported from here on
-
-Use `include/osmium/util/compatibility.hpp` if there are compatibility problems
-between compilers due to different C++11 support.
-
-
-## Checking your code
-
-The Osmium makefiles use pretty draconian warning options for the compiler.
-This is good. Code MUST never produce any warnings, even with those settings.
-If absolutely necessary pragmas can be used to disable certain warnings in
-specific areas of the code.
-
-If the static code checker `cppcheck` is installed, the CMake configuration
-will add a new build target `cppcheck` that will check all `.cpp` and `.hpp`
-files. Cppcheck finds some bugs that gcc/clang doesn't. But take the result
-with a grain of salt, it also sometimes produces wrong warnings.
-
-Set `BUILD_HEADERS=ON` in the CMake config to enable compiling all include
-files on their own to check whether dependencies are all okay. All include
-files MUST include all other include files they depend on.
-
-Call `cmake/iwyu.sh` to check for proper includes and forward declarations.
-This uses the clang-based `include-what-you-use` program. Note that it does
-produce some false reports and crashes often. The `osmium.imp` file can be
-used to define mappings for iwyu. See the IWYU tool at
-<http://code.google.com/p/include-what-you-use/>.
-
-
-## 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.
-
-
-## Documenting the code
-
-All namespaces, classes, functions, attributes, etc. should be documented.
-
-Osmium uses the Doxygen (www.doxygen.org) source code documentation system.
-If it is installed, the CMake configuration will add a new build target, so
-you can build it with `make doc`.
+* We'd love for you to send pull requests for fixes you have made or new features
+ you have added. Please read the [notes for developers](NOTES_FOR_DEVELOPERS.md)
+ beforehand which contain some coding guidelines.
diff --git a/CONTRIBUTING.md b/NOTES_FOR_DEVELOPERS.md
similarity index 97%
copy from CONTRIBUTING.md
copy to NOTES_FOR_DEVELOPERS.md
index 1064b94..3c1f73b 100644
--- a/CONTRIBUTING.md
+++ b/NOTES_FOR_DEVELOPERS.md
@@ -4,12 +4,6 @@
Read this if you want to contribute to Libosmium.
-## Versioning
-
-Osmium is currently considered in beta and doesn't use versioning yet. Proper
-versions will be introduced as soon as it is somewhat stable.
-
-
## Namespace
All Osmium code MUST be in the `osmium` namespace or one of its sub-namespaces.
@@ -103,6 +97,12 @@ Use `include/osmium/util/compatibility.hpp` if there are compatibility problems
between compilers due to different C++11 support.
+## Operating systems
+
+Usually all code must work on Linux, OSX, and Windows. Execptions are allowed
+for some minor functionality, but please discuss this first.
+
+
## Checking your code
The Osmium makefiles use pretty draconian warning options for the compiler.
diff --git a/appveyor.yml b/appveyor.yml
index e33b08c..7e6060a 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -22,86 +22,5 @@ clone_folder: c:\projects\libosmium
platform: x64
-install:
- # show all available env vars
- - set
- - echo cmake on AppVeyor
- - cmake -version
- - call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64
- - set PATH=c:\projects\libosmium\cmake-3.1.0-win32-x86\bin;%PATH%
- - set LODEPSDIR=c:\projects\libosmium\libosmium-deps
- - set PROJ_LIB=%LODEPSDIR%\proj\share
- - set GDAL_DATA=%LODEPSDIR%\gdal\data
- #geos.dll
- - set PATH=%LODEPSDIR%\geos\lib;%PATH%
- #gdal.dll
- - set PATH=%LODEPSDIR%\gdal\lib;%PATH%
- #libexpat.dll
- - set PATH=%LODEPSDIR%\expat\lib;%PATH%
- #libtiff.dll
- - set PATH=%LODEPSDIR%\libtiff\lib;%PATH%
- #jpeg.dll
- - set PATH=%LODEPSDIR%\jpeg\lib;%PATH%
- #zlibwapi.dll
- - set PATH=%LODEPSDIR%\zlib\lib;%PATH%
- #convert backslashes in bzip2 path to forward slashes
- #cmake cannot find it otherwise
- - set LIBBZIP2=%LODEPSDIR%\bzip2\lib\libbz2.lib
- - set LIBBZIP2=%LIBBZIP2:\=/%
- - ps: Start-FileDownload https://mapbox.s3.amazonaws.com/windows-builds/windows-build-deps/cmake-3.1.0-win32-x86.7z -FileName cm.7z
- - ps: Start-FileDownload https://mapbox.s3.amazonaws.com/windows-builds/windows-build-deps/libosmium-deps-win-14.0-x64.7z -FileName lodeps.7z
- - 7z x cm.7z | %windir%\system32\find "ing archive"
- - 7z x lodeps.7z | %windir%\system32\find "ing archive"
- - echo %LODEPSDIR%
- - dir %LODEPSDIR%
- - echo our own cmake
- - cmake -version
- - cd c:\projects
- - git clone --depth 1 https://github.com/osmcode/osm-testdata.git
-
build_script:
- - cd c:\projects\libosmium
- - mkdir build
- - cd build
- - echo %config%
- # This will produce lots of LNK4099 warnings which can be ignored.
- # Unfortunately they can't be disabled, see
- # http://stackoverflow.com/questions/661606/visual-c-how-to-disable-specific-linker-warnings
- - cmake -LA -G "Visual Studio 14 Win64"
- -DOsmium_DEBUG=TRUE
- -DCMAKE_BUILD_TYPE=%config%
- -DBUILD_HEADERS=OFF
- -DBOOST_ROOT=%LODEPSDIR%\boost
- -DZLIB_LIBRARY=%LODEPSDIR%\zlib\lib\zlibwapi.lib
- -DBZIP2_LIBRARY_RELEASE=%LIBBZIP2%
- -DCMAKE_PREFIX_PATH=%LODEPSDIR%\zlib;%LODEPSDIR%\expat;%LODEPSDIR%\bzip2;%LODEPSDIR%\geos;%LODEPSDIR%\gdal;%LODEPSDIR%\proj;%LODEPSDIR%\sparsehash;%LODEPSDIR%\wingetopt
- ..
- - msbuild libosmium.sln /p:Configuration=%config% /toolsversion:14.0 /p:Platform=x64 /p:PlatformToolset=v140
- #- cmake .. -LA -G "NMake Makefiles"
- # -DOsmium_DEBUG=TRUE
- # -DCMAKE_BUILD_TYPE=%config%
- # -DBOOST_ROOT=%LODEPSDIR%\boost
- # -DZLIB_LIBRARY=%LODEPSDIR%\zlib\lib\zlibwapi.lib
- # -DZLIB_INCLUDE_DIR=%LODEPSDIR%\zlib\include
- # -DEXPAT_LIBRARY=%LODEPSDIR%\expat\lib\libexpat.lib
- # -DEXPAT_INCLUDE_DIR=%LODEPSDIR%\expat\include
- # -DBZIP2_LIBRARIES=%LIBBZIP2%
- # -DBZIP2_INCLUDE_DIR=%LODEPSDIR%\bzip2\include
- # -DGDAL_LIBRARY=%LODEPSDIR%\gdal\lib\gdal_i.lib
- # -DGDAL_INCLUDE_DIR=%LODEPSDIR%\gdal\include
- # -DGEOS_LIBRARY=%LODEPSDIR%\geos\lib\geos.lib
- # -DGEOS_INCLUDE_DIR=%LODEPSDIR%\geos\include
- # -DPROJ_LIBRARY=%LODEPSDIR%\proj\lib\proj.lib
- # -DPROJ_INCLUDE_DIR=%LODEPSDIR%\proj\include
- # -DSPARSEHASH_INCLUDE_DIR=%LODEPSDIR%\sparsehash\include
- # -DGETOPT_LIBRARY=%LODEPSDIR%\wingetopt\lib\wingetopt.lib
- # -DGETOPT_INCLUDE_DIR=%LODEPSDIR%\wingetopt\include
- #- nmake
-
-test_script:
- # "-E testdata-overview" exempts one test we know fails on Appveyor
- # because we currently don't have spatialite support.
- - ctest --output-on-failure
- -C %config%
- -E testdata-overview
-
+ - build-appveyor.bat
diff --git a/benchmarks/osmium_benchmark_count.cpp b/benchmarks/osmium_benchmark_count.cpp
index d50c53d..1a16275 100644
--- a/benchmarks/osmium_benchmark_count.cpp
+++ b/benchmarks/osmium_benchmark_count.cpp
@@ -5,7 +5,9 @@
*/
#include <cstdint>
+#include <cstdlib>
#include <iostream>
+#include <string>
#include <osmium/io/any_input.hpp>
#include <osmium/handler.hpp>
@@ -35,12 +37,12 @@ struct CountHandler : public osmium::handler::Handler {
int main(int argc, char* argv[]) {
if (argc != 2) {
std::cerr << "Usage: " << argv[0] << " OSMFILE\n";
- exit(1);
+ std::exit(1);
}
- std::string input_filename = argv[1];
+ const std::string input_filename{argv[1]};
- osmium::io::Reader reader(input_filename);
+ osmium::io::Reader reader{input_filename};
CountHandler handler;
osmium::apply(reader, handler);
diff --git a/benchmarks/osmium_benchmark_count_tag.cpp b/benchmarks/osmium_benchmark_count_tag.cpp
index 8fa696a..6062ecc 100644
--- a/benchmarks/osmium_benchmark_count_tag.cpp
+++ b/benchmarks/osmium_benchmark_count_tag.cpp
@@ -5,7 +5,9 @@
*/
#include <cstdint>
+#include <cstdlib>
#include <iostream>
+#include <string>
#include <osmium/io/any_input.hpp>
#include <osmium/handler.hpp>
@@ -38,12 +40,12 @@ struct CountHandler : public osmium::handler::Handler {
int main(int argc, char* argv[]) {
if (argc != 2) {
std::cerr << "Usage: " << argv[0] << " OSMFILE\n";
- exit(1);
+ std::exit(1);
}
- std::string input_filename = argv[1];
+ const std::string input_filename{argv[1]};
- osmium::io::Reader reader(input_filename);
+ osmium::io::Reader reader{input_filename};
CountHandler handler;
osmium::apply(reader, handler);
diff --git a/benchmarks/osmium_benchmark_index_map.cpp b/benchmarks/osmium_benchmark_index_map.cpp
index 0257826..2cf550c 100644
--- a/benchmarks/osmium_benchmark_index_map.cpp
+++ b/benchmarks/osmium_benchmark_index_map.cpp
@@ -4,7 +4,9 @@
*/
+#include <cstdlib>
#include <iostream>
+#include <string>
#include <osmium/index/map/all.hpp>
#include <osmium/handler/node_locations_for_ways.hpp>
@@ -13,24 +15,24 @@
#include <osmium/io/any_input.hpp>
#include <osmium/handler.hpp>
-typedef osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location> index_type;
+using index_type = osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>;
-typedef osmium::handler::NodeLocationsForWays<index_type> location_handler_type;
+using location_handler_type = osmium::handler::NodeLocationsForWays<index_type>;
int main(int argc, char* argv[]) {
if (argc != 3) {
std::cerr << "Usage: " << argv[0] << " OSMFILE FORMAT\n";
- exit(1);
+ std::exit(1);
}
- std::string input_filename = argv[1];
- std::string location_store = argv[2];
+ const std::string input_filename{argv[1]};
+ const std::string location_store{argv[2]};
- osmium::io::Reader reader(input_filename);
+ osmium::io::Reader reader{input_filename};
const auto& map_factory = osmium::index::MapFactory<osmium::unsigned_object_id_type, osmium::Location>::instance();
std::unique_ptr<index_type> index = map_factory.create_map(location_store);
- location_handler_type location_handler(*index);
+ location_handler_type location_handler{*index};
location_handler.ignore_errors();
osmium::apply(reader, location_handler);
diff --git a/benchmarks/osmium_benchmark_static_vs_dynamic_index.cpp b/benchmarks/osmium_benchmark_static_vs_dynamic_index.cpp
index 66e2a0b..e9f950c 100644
--- a/benchmarks/osmium_benchmark_static_vs_dynamic_index.cpp
+++ b/benchmarks/osmium_benchmark_static_vs_dynamic_index.cpp
@@ -19,8 +19,10 @@
#include <algorithm>
#include <chrono>
#include <cmath>
+#include <cstdlib>
#include <iostream>
#include <limits>
+#include <string>
#include <osmium/index/map/all.hpp>
#include <osmium/handler/node_locations_for_ways.hpp>
@@ -29,23 +31,23 @@
#include <osmium/io/any_input.hpp>
#include <osmium/handler.hpp>
-typedef osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, osmium::Location> static_index_type;
-const std::string location_store="sparse_mem_array";
+using static_index_type = osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, osmium::Location>;
+const std::string location_store{"sparse_mem_array"};
-typedef osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location> dynamic_index_type;
+using dynamic_index_type = osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>;
-typedef osmium::handler::NodeLocationsForWays<static_index_type> static_location_handler_type;
-typedef osmium::handler::NodeLocationsForWays<dynamic_index_type> dynamic_location_handler_type;
+using static_location_handler_type = osmium::handler::NodeLocationsForWays<static_index_type>;
+using dynamic_location_handler_type = osmium::handler::NodeLocationsForWays<dynamic_index_type>;
int main(int argc, char* argv[]) {
if (argc != 2) {
std::cerr << "Usage: " << argv[0] << " OSMFILE\n";
- exit(1);
+ std::exit(1);
}
- std::string input_filename = argv[1];
+ const std::string input_filename{argv[1]};
- osmium::memory::Buffer buffer = osmium::io::read_file(input_filename);
+ osmium::memory::Buffer buffer{osmium::io::read_file(input_filename)};
const auto& map_factory = osmium::index::MapFactory<osmium::unsigned_object_id_type, osmium::Location>::instance();
@@ -67,20 +69,20 @@ int main(int argc, char* argv[]) {
{
// static index
- osmium::memory::Buffer tmp_buffer(buffer.committed());
+ osmium::memory::Buffer tmp_buffer{buffer.committed()};
for (const auto& item : buffer) {
tmp_buffer.add_item(item);
tmp_buffer.commit();
}
static_index_type static_index;
- static_location_handler_type static_location_handler(static_index);
+ static_location_handler_type static_location_handler{static_index};
- auto start = std::chrono::steady_clock::now();
+ const auto start = std::chrono::steady_clock::now();
osmium::apply(tmp_buffer, static_location_handler);
- auto end = std::chrono::steady_clock::now();
+ const auto end = std::chrono::steady_clock::now();
- double duration = std::chrono::duration<double, std::milli>(end-start).count();
+ const double duration = std::chrono::duration<double, std::milli>(end-start).count();
if (duration < static_min) static_min = duration;
if (duration > static_max) static_max = duration;
@@ -89,21 +91,21 @@ int main(int argc, char* argv[]) {
{
// dynamic index
- osmium::memory::Buffer tmp_buffer(buffer.committed());
+ osmium::memory::Buffer tmp_buffer{buffer.committed()};
for (const auto& item : buffer) {
tmp_buffer.add_item(item);
tmp_buffer.commit();
}
std::unique_ptr<dynamic_index_type> index = map_factory.create_map(location_store);
- dynamic_location_handler_type dynamic_location_handler(*index);
+ dynamic_location_handler_type dynamic_location_handler{*index};
dynamic_location_handler.ignore_errors();
- auto start = std::chrono::steady_clock::now();
+ const auto start = std::chrono::steady_clock::now();
osmium::apply(tmp_buffer, dynamic_location_handler);
- auto end = std::chrono::steady_clock::now();
+ const auto end = std::chrono::steady_clock::now();
- double duration = std::chrono::duration<double, std::milli>(end-start).count();
+ const double duration = std::chrono::duration<double, std::milli>(end-start).count();
if (duration < dynamic_min) dynamic_min = duration;
if (duration > dynamic_max) dynamic_max = duration;
@@ -111,21 +113,21 @@ int main(int argc, char* argv[]) {
}
}
- double static_avg = static_sum/runs;
- double dynamic_avg = dynamic_sum/runs;
+ const double static_avg = static_sum/runs;
+ const double dynamic_avg = dynamic_sum/runs;
std::cout << "static min=" << static_min << "ms avg=" << static_avg << "ms max=" << static_max << "ms\n";
std::cout << "dynamic min=" << dynamic_min << "ms avg=" << dynamic_avg << "ms max=" << dynamic_max << "ms\n";
- double rfactor = 100.0;
- double diff_min = std::round((dynamic_min - static_min) * rfactor) / rfactor;
- double diff_avg = std::round((dynamic_avg - static_avg) * rfactor) / rfactor;
- double diff_max = std::round((dynamic_max - static_max) * rfactor) / rfactor;
+ const double rfactor = 100.0;
+ const double diff_min = std::round((dynamic_min - static_min) * rfactor) / rfactor;
+ const double diff_avg = std::round((dynamic_avg - static_avg) * rfactor) / rfactor;
+ const double diff_max = std::round((dynamic_max - static_max) * rfactor) / rfactor;
- double prfactor = 10.0;
- double percent_min = std::round((100.0 * diff_min / static_min) * prfactor) / prfactor;
- double percent_avg = std::round((100.0 * diff_avg / static_avg) * prfactor) / prfactor;
- double percent_max = std::round((100.0 * diff_max / static_max) * prfactor) / prfactor;
+ const double prfactor = 10.0;
+ const double percent_min = std::round((100.0 * diff_min / static_min) * prfactor) / prfactor;
+ const double percent_avg = std::round((100.0 * diff_avg / static_avg) * prfactor) / prfactor;
+ const double percent_max = std::round((100.0 * diff_max / static_max) * prfactor) / prfactor;
std::cout << "difference:";
std::cout << " min=" << diff_min << "ms (" << percent_min << "%)";
diff --git a/benchmarks/osmium_benchmark_write_pbf.cpp b/benchmarks/osmium_benchmark_write_pbf.cpp
index 869f3a8..632dd26 100644
--- a/benchmarks/osmium_benchmark_write_pbf.cpp
+++ b/benchmarks/osmium_benchmark_write_pbf.cpp
@@ -4,8 +4,9 @@
*/
-#include <cstdint>
-#include <vector>
+#include <cstdlib>
+#include <iostream>
+#include <string>
#include <osmium/io/any_input.hpp>
#include <osmium/io/any_output.hpp>
@@ -13,16 +14,16 @@
int main(int argc, char* argv[]) {
if (argc != 3) {
std::cerr << "Usage: " << argv[0] << " INPUT-FILE OUTPUT-FILE\n";
- exit(1);
+ std::exit(1);
}
- std::string input_filename = argv[1];
- std::string output_filename = argv[2];
+ std::string input_filename{argv[1]};
+ std::string output_filename{argv[2]};
- osmium::io::Reader reader(input_filename);
- osmium::io::File output_file(output_filename, "pbf");
+ osmium::io::Reader reader{input_filename};
+ osmium::io::File output_file{output_filename, "pbf"};
osmium::io::Header header;
- osmium::io::Writer writer(output_file, header, osmium::io::overwrite::allow);
+ osmium::io::Writer writer{output_file, header, osmium::io::overwrite::allow};
while (osmium::memory::Buffer buffer = reader.read()) {
writer(std::move(buffer));
diff --git a/build-appveyor.bat b/build-appveyor.bat
new file mode 100644
index 0000000..27d387c
--- /dev/null
+++ b/build-appveyor.bat
@@ -0,0 +1,123 @@
+ at ECHO OFF
+SETLOCAL
+SET EL=0
+
+ECHO ~~~~~~ %~f0 ~~~~~~
+
+SET CUSTOM_CMAKE=cmake-3.6.2-win64-x64
+::show all available env vars
+SET
+ECHO cmake on AppVeyor
+cmake -version
+
+ECHO activating VS cmd prompt && CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64
+IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+
+SET lodir=%CD%
+SET PATH=%lodir%\%CUSTOM_CMAKE%\bin;%PATH%
+SET LODEPSDIR=%lodir%\libosmium-deps
+SET PROJ_LIB=%LODEPSDIR%\proj\share
+SET GDAL_DATA=%LODEPSDIR%\gdal\data
+::gdal.dll
+SET PATH=%LODEPSDIR%\gdal\lib;%PATH%
+::geos.dll
+SET PATH=%LODEPSDIR%\geos\lib;%PATH%
+::libtiff.dll
+SET PATH=%LODEPSDIR%\libtiff\lib;%PATH%
+::jpeg.dll
+SET PATH=%LODEPSDIR%\jpeg\lib;%PATH%
+::libexpat.dll
+SET PATH=%LODEPSDIR%\expat\lib;%PATH%
+::zlibwapi.dll
+SET PATH=%LODEPSDIR%\zlib\lib;%PATH%
+::convert backslashes in bzip2 path to forward slashes
+::cmake cannot find it otherwise
+SET LIBBZIP2=%LODEPSDIR%\bzip2\lib\libbz2.lib
+SET LIBBZIP2=%LIBBZIP2:\=/%
+
+IF NOT EXIST cm.7z ECHO downloading cmake %CUSTOM_CMAKE% ... && powershell Invoke-WebRequest https://mapbox.s3.amazonaws.com/windows-builds/windows-build-deps/%CUSTOM_CMAKE%.7z -OutFile cm.7z
+IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+
+IF NOT EXIST lodeps.7z ECHO downloading binary dependencies... && powershell Invoke-WebRequest https://mapbox.s3.amazonaws.com/windows-builds/windows-build-deps/libosmium-deps-win-14.0-x64.7z -OutFile lodeps.7z
+IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+
+IF NOT EXIST %CUSTOM_CMAKE% ECHO extracting cmake... && 7z x cm.7z | %windir%\system32\find "ing archive"
+IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+
+IF NOT EXIST %LODEPSDIR% ECHO extracting binary dependencies... && 7z x lodeps.7z | %windir%\system32\find "ing archive"
+IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+
+ECHO %LODEPSDIR%
+DIR %LODEPSDIR%
+::TREE %LODEPSDIR%
+
+::powershell (Get-ChildItem $env:LODEPSDIR\boost\lib -Filter *boost*.dll)[0].BaseName.split('_')[-1]
+FOR /F "tokens=1 usebackq" %%i in (`powershell ^(Get-ChildItem %LODEPSDIR%\boost\lib -Filter *boost*.dll^)[0].BaseName.split^('_'^)[-1]`) DO SET BOOST_VERSION=%%i
+IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+
+ECHO BOOST_VERSION^: %BOOST_VERSION%
+
+ECHO our own cmake
+cmake -version
+
+CD %lodir%\..
+
+IF NOT EXIST osm-testdata ECHO cloning osm-testdata && git clone --depth 1 https://github.com/osmcode/osm-testdata.git
+IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+CD osm-testdata
+git fetch
+IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+git pull
+IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+
+CD %lodir%
+IF EXIST build ECHO deleting build dir... && RD /Q /S build
+IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+
+MKDIR build
+IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+
+CD build
+ECHO config^: %config%
+
+::This will produce lots of LNK4099 warnings which can be ignored.
+::Unfortunately they can't be disabled, see
+::http://stackoverflow.com/questions/661606/visual-c-how-to-disable-specific-linker-warnings
+SET CMAKE_CMD=cmake .. ^
+-LA -G "Visual Studio 14 Win64" ^
+-DOsmium_DEBUG=TRUE ^
+-DCMAKE_BUILD_TYPE=%config% ^
+-DBUILD_HEADERS=OFF ^
+-DBOOST_ROOT=%LODEPSDIR%\boost ^
+-DZLIB_LIBRARY=%LODEPSDIR%\zlib\lib\zlibwapi.lib ^
+-DBZIP2_LIBRARY_RELEASE=%LIBBZIP2% ^
+-DCMAKE_PREFIX_PATH=%LODEPSDIR%\zlib;%LODEPSDIR%\expat;%LODEPSDIR%\bzip2;%LODEPSDIR%\geos;%LODEPSDIR%\gdal;%LODEPSDIR%\proj;%LODEPSDIR%\sparsehash;%LODEPSDIR%\wingetopt
+
+ECHO calling^: %CMAKE_CMD%
+%CMAKE_CMD%
+IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+
+msbuild libosmium.sln ^
+/p:Configuration=%config% ^
+/toolsversion:14.0 ^
+/p:Platform=x64 ^
+/p:PlatformToolset=v140
+IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+
+ctest --output-on-failure ^
+-C %config% ^
+-E testdata-overview
+IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+
+
+GOTO DONE
+
+:ERROR
+ECHO ~~~~~~ ERROR %~f0 ~~~~~~
+SET EL=%ERRORLEVEL%
+
+:DONE
+IF %EL% NEQ 0 ECHO. && ECHO !!! ERRORLEVEL^: %EL% !!! && ECHO.
+ECHO ~~~~~~ DONE %~f0 ~~~~~~
+
+EXIT /b %EL%
diff --git a/build-local.bat b/build-local.bat
new file mode 100644
index 0000000..202d0b2
--- /dev/null
+++ b/build-local.bat
@@ -0,0 +1,43 @@
+ at ECHO OFF
+SETLOCAL
+SET EL=0
+
+ECHO ~~~~~~ %~f0 ~~~~~~
+
+ECHO.
+ECHO build-local ["config=Dev"]
+ECHO default config^: RelWithDebInfo
+ECHO.
+
+SET platform=x64
+SET config=RelWithDebInfo
+
+:: OVERRIDE PARAMETERS >>>>>>>>
+:NEXT-ARG
+
+IF '%1'=='' GOTO ARGS-DONE
+ECHO setting %1
+SET %1
+SHIFT
+GOTO NEXT-ARG
+
+:ARGS-DONE
+::<<<<< OVERRIDE PARAMETERS
+
+WHERE 7z
+IF %ERRORLEVEL% NEQ 0 ECHO 7zip not on PATH && GOTO ERROR
+
+CALL build-appveyor.bat
+IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+
+GOTO DONE
+
+:ERROR
+ECHO ~~~~~~ ERROR %~f0 ~~~~~~
+SET EL=%ERRORLEVEL%
+
+:DONE
+IF %EL% NEQ 0 ECHO. && ECHO !!! ERRORLEVEL^: %EL% !!! && ECHO.
+ECHO ~~~~~~ DONE %~f0 ~~~~~~
+
+EXIT /b %EL%
diff --git a/cmake/iwyu.sh b/cmake/iwyu.sh
index ceea106..b386159 100755
--- a/cmake/iwyu.sh
+++ b/cmake/iwyu.sh
@@ -6,6 +6,11 @@
# TODO: This script should be integrated with cmake in some way...
#
+# If these are set, the wrong compiler is used by iwyu and there will be
+# errors about missing includes.
+unset CC
+unset CXX
+
cmdline="iwyu -Xiwyu --mapping_file=osmium.imp -std=c++11 -I include"
log=build/iwyu.log
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index eff3363..b47cfdc 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -12,13 +12,17 @@ set(EXAMPLES
area_test
convert
count
- create_node_cache
debug
filter_discussions
index
+ location_cache_create
+ location_cache_use
+ pub_names
read
+ read_with_progress
+ road_length
serdump
- use_node_cache
+ tiles
CACHE STRING "Example programs"
)
diff --git a/examples/README.md b/examples/README.md
new file mode 100644
index 0000000..e291032
--- /dev/null
+++ b/examples/README.md
@@ -0,0 +1,32 @@
+
+# Osmium example programs
+
+The programs in this directory are intended as examples for developers. They
+contain extensive comments explaining what's going on. Note that the examples
+only cover a small part of what Osmium can do, you should also read the
+documentation and API documentation.
+
+All programs can be run without arguments and they will tell you how to run
+them.
+
+## Very simple examples
+
+* `osmium_read`
+* `osmium_count`
+* `osmium_debug`
+* `osmium_tiles`
+
+## Still reasonably simple examples
+
+* `osmium_filter_discussions`
+* `osmium_convert`
+
+## More advanced examples
+
+* `osmium_area_test`
+
+## License
+
+The code in these example files is released into the Public Domain. Feel free
+to copy the code and build on it.
+
diff --git a/examples/osmium_area_test.cpp b/examples/osmium_area_test.cpp
index e9b7a18..0303374 100644
--- a/examples/osmium_area_test.cpp
+++ b/examples/osmium_area_test.cpp
@@ -1,48 +1,81 @@
/*
- This is an example tool that creates multipolygons from OSM data
- and dumps them to stdout.
-
+ EXAMPLE osmium_area_test
+
+ Create multipolygons from OSM data and dump them to stdout in one of two
+ formats: WKT or using the built-in Dump format.
+
+ DEMONSTRATES USE OF:
+ * file input
+ * location indexes and the NodeLocationsForWays handler
+ * the MultipolygonCollector 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
+ * the DynamicHandler
+
+ SIMPLER EXAMPLES you might want to understand first:
+ * osmium_read
+ * osmium_count
+ * osmium_debug
+
+ LICENSE
The code in this example file is released into the Public Domain.
*/
-#include <iostream>
-
-#include <getopt.h>
+#include <cstdlib> // for std::exit
+#include <getopt.h> // for getopt_long
+#include <iostream> // for std::cout, std::cerr
+// For assembling multipolygons
#include <osmium/area/assembler.hpp>
#include <osmium/area/multipolygon_collector.hpp>
+
+// For the DynamicHandler class
#include <osmium/dynamic_handler.hpp>
+
+// For the WKT factory
#include <osmium/geom/wkt.hpp>
+
+// For the Dump handler
#include <osmium/handler/dump.hpp>
+
+// For the NodeLocationForWays handler
#include <osmium/handler/node_locations_for_ways.hpp>
-#include <osmium/index/map/dummy.hpp>
-#include <osmium/index/map/sparse_mem_array.hpp>
+
+// Allow any format of input files (XML, PBF, ...)
#include <osmium/io/any_input.hpp>
+
+// For osmium::apply()
#include <osmium/visitor.hpp>
-typedef osmium::index::map::Dummy<osmium::unsigned_object_id_type, osmium::Location> index_neg_type;
-typedef osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, osmium::Location> index_pos_type;
-typedef osmium::handler::NodeLocationsForWays<index_pos_type, index_neg_type> location_handler_type;
+// 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>
-class WKTDump : public osmium::handler::Handler {
+// 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>;
- osmium::geom::WKTFactory<> m_factory ;
+// The location handler always depends on the index type
+using location_handler_type = osmium::handler::NodeLocationsForWays<index_type>;
- std::ostream& m_out;
+// This handler writes all area geometries out in WKT (Well Known Text) format.
+class WKTDump : public osmium::handler::Handler {
-public:
+ // This factory is used to create a geometry in WKT format from OSM
+ // objects. The template parameter is empty here, because we output WGS84
+ // coordinates, but could be used for a projection.
+ osmium::geom::WKTFactory<> m_factory;
- WKTDump(std::ostream& out) :
- m_out(out) {
- }
+public:
+ // This callback is called by osmium::apply for each area in the data.
void area(const osmium::Area& area) {
try {
- m_out << m_factory.create_multipolygon(area) << "\n";
- } catch (osmium::geometry_error& e) {
- m_out << "GEOMETRY ERROR: " << e.what() << "\n";
+ std::cout << m_factory.create_multipolygon(area) << "\n";
+ } catch (const osmium::geometry_error& e) {
+ std::cout << "GEOMETRY ERROR: " << e.what() << "\n";
}
}
@@ -65,8 +98,13 @@ int main(int argc, char* argv[]) {
{0, 0, 0, 0}
};
+ // Initialize an empty DynamicHandler. Later it will be associated
+ // with one of the handlers. You can think of the DynamicHandler as
+ // a kind of "variant handler" or a "pointer handler" pointing to the
+ // real handler.
osmium::handler::DynamicHandler handler;
+ // Read options from command line.
while (true) {
int c = getopt_long(argc, argv, "hwo", long_options, 0);
if (c == -1) {
@@ -76,54 +114,81 @@ int main(int argc, char* argv[]) {
switch (c) {
case 'h':
print_help();
- exit(0);
+ std::exit(0);
case 'w':
- handler.set<WKTDump>(std::cout);
+ handler.set<WKTDump>();
break;
case 'o':
handler.set<osmium::handler::Dump>(std::cout);
break;
default:
- exit(1);
+ std::exit(1);
}
}
int remaining_args = argc - optind;
if (remaining_args != 1) {
std::cerr << "Usage: " << argv[0] << " [OPTIONS] OSMFILE\n";
- exit(1);
+ std::exit(1);
}
- osmium::io::File infile(argv[optind]);
+ osmium::io::File input_file{argv[optind]};
+ // Configuration for the multipolygon assembler. Here the default settings
+ // are used, but you could change multiple settings.
osmium::area::Assembler::config_type assembler_config;
- osmium::area::MultipolygonCollector<osmium::area::Assembler> collector(assembler_config);
+ // Initialize the MultipolygonCollector. 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};
+
+ // We read the input file twice. In the first pass, only relations are
+ // read and fed into the multipolygon collector.
std::cerr << "Pass 1...\n";
- osmium::io::Reader reader1(infile, osmium::osm_entity_bits::relation);
+ osmium::io::Reader reader1{input_file, osmium::osm_entity_bits::relation};
collector.read_relations(reader1);
reader1.close();
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();
- index_pos_type index_pos;
- index_neg_type index_neg;
- location_handler_type location_handler(index_pos, index_neg);
- location_handler.ignore_errors(); // XXX
+ // The index storing all node locations.
+ index_type index;
+
+ // The handler that stores all node locations in the index and adds them
+ // to the ways.
+ location_handler_type location_handler{index};
+
+ // If a location is not available in the index, we ignore it. It might
+ // not be needed (if it is not part of a multipolygon relation), so why
+ // create an error?
+ location_handler.ignore_errors();
+ // On the second pass we read all objects and run them first through the
+ // node location handler and then the multipolygon collector. The collector
+ // 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(infile);
+ osmium::io::Reader reader2{input_file};
osmium::apply(reader2, location_handler, collector.handler([&handler](osmium::memory::Buffer&& buffer) {
osmium::apply(buffer, handler);
}));
reader2.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();
+ // 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::cerr << "Warning! Some member ways missing for these multipolygon relations:";
diff --git a/examples/osmium_convert.cpp b/examples/osmium_convert.cpp
index 4f2ba33..48a0823 100644
--- a/examples/osmium_convert.cpp
+++ b/examples/osmium_convert.cpp
@@ -1,16 +1,32 @@
/*
+ EXAMPLE osmium_convert
+
Convert OSM files from one format into another.
+ DEMONSTRATES USE OF:
+ * file input and output
+ * file types
+ * Osmium buffers
+
+ SIMPLER EXAMPLES you might want to understand first:
+ * osmium_read
+
+ LICENSE
The code in this example file is released into the Public Domain.
*/
-#include <iostream>
-#include <getopt.h>
+#include <cstdlib> // for std::exit
+#include <exception> // for std::exception
+#include <getopt.h> // for getopt_long
+#include <iostream> // for std::cout, std::cerr
+#include <string> // for std::string
+// Allow any format of input files (XML, PBF, ...)
#include <osmium/io/any_input.hpp>
+// Allow any format of output files (XML, PBF, ...)
#include <osmium/io/any_output.hpp>
void print_help() {
@@ -43,9 +59,13 @@ int main(int argc, char* argv[]) {
{0, 0, 0, 0}
};
+ // Input and output format are empty by default. Later this will mean that
+ // the format should be taken from the input and output file suffix,
+ // respectively.
std::string input_format;
std::string output_format;
+ // Read options from command line.
while (true) {
int c = getopt_long(argc, argv, "dhf:t:", long_options, 0);
if (c == -1) {
@@ -55,7 +75,7 @@ int main(int argc, char* argv[]) {
switch (c) {
case 'h':
print_help();
- exit(0);
+ std::exit(0);
case 'f':
input_format = optarg;
break;
@@ -63,49 +83,73 @@ int main(int argc, char* argv[]) {
output_format = optarg;
break;
default:
- exit(1);
+ std::exit(1);
}
}
- std::string input;
- std::string output;
int remaining_args = argc - optind;
if (remaining_args > 2) {
- std::cerr << "Usage: " << argv[0] << " [OPTIONS] [INFILE [OUTFILE]]" << std::endl;
- exit(1);
- } else if (remaining_args == 2) {
- input = argv[optind];
- output = argv[optind+1];
- } else if (remaining_args == 1) {
- input = argv[optind];
+ std::cerr << "Usage: " << argv[0] << " [OPTIONS] [INFILE [OUTFILE]]\n";
+ std::exit(1);
}
- osmium::io::File infile(input, input_format);
+ // Get input file name from command line.
+ std::string input_file_name;
+ if (remaining_args >= 1) {
+ input_file_name = argv[optind];
+ }
- osmium::io::File outfile(output, output_format);
+ // Get output file name from command line.
+ std::string output_file_name;
+ if (remaining_args == 2) {
+ output_file_name = argv[optind+1];
+ }
- if (infile.has_multiple_object_versions() && !outfile.has_multiple_object_versions()) {
+ // 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};
+
+ // Input and output files can be OSM data files (without history) or
+ // OSM history files. History files are detected if they use the '.osh'
+ // file suffix.
+ if ( input_file.has_multiple_object_versions() &&
+ !output_file.has_multiple_object_versions()) {
std::cerr << "Warning! You are converting from an OSM file with (potentially) several versions of the same object to one that is not marked as such.\n";
}
- int exit_code = 0;
-
try {
- osmium::io::Reader reader(infile);
+ // Initialize Reader
+ osmium::io::Reader reader{input_file};
+
+ // Get header from input file and change the "generator" setting to
+ // outselves.
osmium::io::Header header = reader.header();
header.set("generator", "osmium_convert");
- osmium::io::Writer writer(outfile, header, osmium::io::overwrite::allow);
+ // Initialize Writer using the header from above and tell it that it
+ // is allowed to overwrite a possibly existing file.
+ osmium::io::Writer writer(output_file, header, osmium::io::overwrite::allow);
+
+ // Copy the contents from the input to the output file one buffer at
+ // a time. This is much easier and faster than copying each object
+ // in the file. Buffers are moved around, so there is no cost for
+ // copying in memory.
while (osmium::memory::Buffer buffer = reader.read()) {
writer(std::move(buffer));
}
+
+ // Explicitly close the writer and reader. Will throw an exception if
+ // there is a problem. If you wait for the destructor to close the writer
+ // and reader, you will not notice the problem, because destructors must
+ // not throw.
writer.close();
reader.close();
- } catch (std::exception& e) {
+ } catch (const std::exception& e) {
+ // All exceptions used by the Osmium library derive from std::exception.
std::cerr << e.what() << "\n";
- exit_code = 1;
+ std::exit(1);
}
-
- return exit_code;
}
diff --git a/examples/osmium_count.cpp b/examples/osmium_count.cpp
index baea153..7de1b6b 100644
--- a/examples/osmium_count.cpp
+++ b/examples/osmium_count.cpp
@@ -1,56 +1,95 @@
/*
- This is a small tool that counts the number of nodes, ways, and relations in
- the input file.
+ EXAMPLE osmium_count
+ Counts the number of nodes, ways, and relations in the input file.
+
+ DEMONSTRATES USE OF:
+ * OSM file input
+ * your own handler
+ * the memory usage utility class
+
+ SIMPLER EXAMPLES you might want to understand first:
+ * osmium_read
+
+ LICENSE
The code in this example file is released into the Public Domain.
*/
-#include <cstdint>
-#include <iostream>
+#include <cstdint> // for std::uint64_t
+#include <cstdlib> // for std::exit
+#include <iostream> // for std::cout, std::cerr
+// Allow any format of input files (XML, PBF, ...)
#include <osmium/io/any_input.hpp>
+
+// We want to use the handler interface
#include <osmium/handler.hpp>
+
+// Utility class gives us access to memory usage information
+#include <osmium/util/memory.hpp>
+
+// For osmium::apply()
#include <osmium/visitor.hpp>
+// Handler derive from the osmium::handler::Handler base class. Usually you
+// overwrite functions node(), way(), and relation(). Other functions are
+// available, too. Read the API documentation for details.
struct CountHandler : public osmium::handler::Handler {
- uint64_t nodes = 0;
- uint64_t ways = 0;
- uint64_t relations = 0;
+ std::uint64_t nodes = 0;
+ std::uint64_t ways = 0;
+ std::uint64_t relations = 0;
- void node(osmium::Node&) {
+ // This callback is called by osmium::apply for each node in the data.
+ void node(const osmium::Node&) noexcept {
++nodes;
}
- void way(osmium::Way&) {
+ // This callback is called by osmium::apply for each way in the data.
+ void way(const osmium::Way&) noexcept {
++ways;
}
- void relation(osmium::Relation&) {
+ // This callback is called by osmium::apply for each relation in the data.
+ void relation(const osmium::Relation&) noexcept {
++relations;
}
-};
+}; // struct CountHandler
int main(int argc, char* argv[]) {
-
if (argc != 2) {
std::cerr << "Usage: " << argv[0] << " OSMFILE\n";
- exit(1);
+ std::exit(1);
}
- osmium::io::File infile(argv[1]);
- osmium::io::Reader reader(infile);
+ // The Reader is initialized here with an osmium::io::File, but could
+ // also be directly initialized with a file name.
+ osmium::io::File input_file{argv[1]};
+ osmium::io::Reader reader{input_file};
+ // Create an instance of our own CountHandler and push the data from the
+ // input file through it.
CountHandler handler;
osmium::apply(reader, handler);
+
+ // You do not have to close the Reader explicitly, but because the
+ // destructor can't throw, you will not see any errors otherwise.
reader.close();
std::cout << "Nodes: " << handler.nodes << "\n";
std::cout << "Ways: " << handler.ways << "\n";
std::cout << "Relations: " << handler.relations << "\n";
+
+ // Because of the huge amount of OSM data, some Osmium-based programs
+ // (though not this one) can use huge amounts of data. So checking actual
+ // memore usage is often useful and can be done easily with this class.
+ // (Currently only works on Linux, not OSX and Windows.)
+ osmium::MemoryUsage memory;
+
+ std::cout << "\nMemory used: " << memory.peak() << " MBytes\n";
}
diff --git a/examples/osmium_create_node_cache.cpp b/examples/osmium_create_node_cache.cpp
deleted file mode 100644
index 359fa19..0000000
--- a/examples/osmium_create_node_cache.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
-
- This reads an OSM file and writes out the node locations to a cache
- file.
-
- The code in this example file is released into the Public Domain.
-
-*/
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <iostream>
-
-#include <osmium/io/any_input.hpp>
-
-#include <osmium/index/map/dummy.hpp>
-#include <osmium/index/map/dense_mmap_array.hpp>
-#include <osmium/index/map/dense_file_array.hpp>
-
-#include <osmium/handler/node_locations_for_ways.hpp>
-#include <osmium/visitor.hpp>
-
-typedef osmium::index::map::Dummy<osmium::unsigned_object_id_type, osmium::Location> index_neg_type;
-//typedef osmium::index::map::DenseMmapArray<osmium::unsigned_object_id_type, osmium::Location> index_pos_type;
-typedef osmium::index::map::DenseFileArray<osmium::unsigned_object_id_type, osmium::Location> index_pos_type;
-
-typedef osmium::handler::NodeLocationsForWays<index_pos_type, index_neg_type> location_handler_type;
-
-int main(int argc, char* argv[]) {
- if (argc != 3) {
- std::cerr << "Usage: " << argv[0] << " OSM_FILE CACHE_FILE\n";
- return 1;
- }
-
- std::string input_filename(argv[1]);
- osmium::io::Reader reader(input_filename, osmium::osm_entity_bits::node);
-
- int fd = open(argv[2], O_RDWR | O_CREAT, 0666);
- if (fd == -1) {
- std::cerr << "Can not open node cache file '" << argv[2] << "': " << strerror(errno) << "\n";
- return 1;
- }
-
- index_pos_type index_pos {fd};
- index_neg_type index_neg;
- location_handler_type location_handler(index_pos, index_neg);
- location_handler.ignore_errors();
-
- osmium::apply(reader, location_handler);
- reader.close();
-
- return 0;
-}
-
diff --git a/examples/osmium_debug.cpp b/examples/osmium_debug.cpp
index 365fc72..8133491 100644
--- a/examples/osmium_debug.cpp
+++ b/examples/osmium_debug.cpp
@@ -1,27 +1,46 @@
/*
- This is a small tool to dump the contents of the input file.
+ EXAMPLE osmium_debug
+ Dump the contents of the input file in a debug format.
+
+ DEMONSTRATES USE OF:
+ * file input reading only some types
+ * the dump handler
+
+ SIMPLER EXAMPLES you might want to understand first:
+ * osmium_read
+ * osmium_count
+
+ LICENSE
The code in this example file is released into the Public Domain.
*/
-#include <iostream>
+#include <cstdlib> // for std::exit
+#include <iostream> // for std::cout, std::cerr
+#include <string> // for std::string
+// The Dump handler
#include <osmium/handler/dump.hpp>
+
+// Allow any format of input files (XML, PBF, ...)
#include <osmium/io/any_input.hpp>
int main(int argc, char* argv[]) {
+ // Speed up output (not Osmium-specific)
std::ios_base::sync_with_stdio(false);
if (argc < 2 || argc > 3) {
std::cerr << "Usage: " << argv[0] << " OSMFILE [TYPES]\n";
std::cerr << "TYPES can be any combination of 'n', 'w', 'r', and 'c' to indicate what types of OSM entities you want (default: all).\n";
- exit(1);
+ std::exit(1);
}
+ // Default is all entity types: nodes, ways, relations, and changesets
osmium::osm_entity_bits::type read_types = osmium::osm_entity_bits::all;
+ // Get entity types from command line if there is a 2nd argument.
if (argc == 3) {
read_types = osmium::osm_entity_bits::nothing;
std::string types = argv[2];
@@ -31,20 +50,27 @@ int main(int argc, char* argv[]) {
if (types.find('c') != std::string::npos) read_types |= osmium::osm_entity_bits::changeset;
}
- osmium::io::Reader reader(argv[1], read_types);
- osmium::io::Header header = reader.header();
+ // Initialize Reader with file name and the types of entities we want to
+ // read.
+ osmium::io::Reader reader{argv[1], read_types};
+ // The file header can contain metadata such as the program that generated
+ // the file and the bounding box of the data.
+ osmium::io::Header header = reader.header();
std::cout << "HEADER:\n generator=" << header.get("generator") << "\n";
- for (auto& bbox : header.boxes()) {
+ for (const auto& bbox : header.boxes()) {
std::cout << " bbox=" << bbox << "\n";
}
- osmium::handler::Dump dump(std::cout);
- while (osmium::memory::Buffer buffer = reader.read()) {
- osmium::apply(buffer, dump);
- }
+ // Initialize Dump handler.
+ osmium::handler::Dump dump{std::cout};
+
+ // Read from input and send everything to Dump handler.
+ osmium::apply(reader, dump);
+ // You do not have to close the Reader explicitly, but because the
+ // destructor can't throw, you will not see any errors otherwise.
reader.close();
}
diff --git a/examples/osmium_filter_discussions.cpp b/examples/osmium_filter_discussions.cpp
index bba25b7..6334981 100644
--- a/examples/osmium_filter_discussions.cpp
+++ b/examples/osmium_filter_discussions.cpp
@@ -1,53 +1,73 @@
/*
+ EXAMPLE osmium_filter_discussions
+
Read OSM changesets with discussions from a changeset dump like the one
you get from http://planet.osm.org/planet/discussions-latest.osm.bz2
and write out only those changesets which have discussions (ie comments).
+ DEMONSTRATES USE OF:
+ * file input and output
+ * setting file formats using the osmium::io::File class
+ * OSM file headers
+ * input and output iterators
+
+ SIMPLER EXAMPLES you might want to understand first:
+ * osmium_read
+ * osmium_count
+
+ LICENSE
The code in this example file is released into the Public Domain.
*/
#include <algorithm> // for std::copy_if
-#include <iostream> // for std::cout, std::cerr
+#include <cstdlib> // for std::exit
+#include <iostream> // for std::cout, std::cerr
-// we want to read OSM files in XML format
-// (other formats don't support full changesets, so only XML is needed here)
+// We want to read OSM files in XML format
+// (other formats don't support full changesets, so only XML is needed here).
#include <osmium/io/xml_input.hpp>
-#include <osmium/io/input_iterator.hpp>
-// we want to write OSM files in XML format
+// We want to write OSM files in XML format.
#include <osmium/io/xml_output.hpp>
+
+// We want to use input and output iterators for easy integration with the
+// algorithms of the standard library.
+#include <osmium/io/input_iterator.hpp>
#include <osmium/io/output_iterator.hpp>
-// we want to support any compressioon (.gz2 and .bz2)
+// We want to support any compression (none, gzip, and bzip2).
#include <osmium/io/any_compression.hpp>
int main(int argc, char* argv[]) {
if (argc != 3) {
std::cout << "Usage: " << argv[0] << " INFILE OUTFILE\n";
- exit(1);
+ std::exit(1);
}
- // The input file, deduce file format from file suffix
- osmium::io::File infile(argv[1]);
+ // The input file, deduce file format from file suffix.
+ osmium::io::File input_file{argv[1]};
- // The output file, force class XML OSM file format
- osmium::io::File outfile(argv[2], "osm");
+ // The output file, force XML OSM file format.
+ osmium::io::File output_file{argv[2], "osm"};
// Initialize Reader for the input file.
// Read only changesets (will ignore nodes, ways, and
// relations if there are any).
- osmium::io::Reader reader(infile, osmium::osm_entity_bits::changeset);
+ osmium::io::Reader reader{input_file, osmium::osm_entity_bits::changeset};
- // Get the header from the input file
+ // Get the header from the input file.
osmium::io::Header header = reader.header();
+ // Set the "generator" on the header to ourselves.
+ header.set("generator", "osmium_filter_discussions");
+
// Initialize writer for the output file. Use the header from the input
// file for the output file. This will copy over some header information.
// The last parameter will tell the writer that it is allowed to overwrite
// an existing file. Without it, it will refuse to do so.
- osmium::io::Writer writer(outfile, header, osmium::io::overwrite::allow);
+ osmium::io::Writer writer(output_file, header, osmium::io::overwrite::allow);
// Create range of input iterators that will iterator over all changesets
// delivered from input file through the "reader".
diff --git a/examples/osmium_index.cpp b/examples/osmium_index.cpp
index 8d5c5d9..478b6c6 100644
--- a/examples/osmium_index.cpp
+++ b/examples/osmium_index.cpp
@@ -31,7 +31,7 @@ class IndexSearch {
void dump_dense() {
dense_index_type index(m_fd);
- for (size_t i = 0; i < index.size(); ++i) {
+ for (std::size_t i = 0; i < index.size(); ++i) {
if (index.get(i) != TValue()) {
std::cout << i << " " << index.get(i) << "\n";
}
@@ -51,9 +51,9 @@ class IndexSearch {
try {
TValue value = index.get(key);
- std::cout << key << " " << value << std::endl;
+ std::cout << key << " " << value << "\n";
} catch (...) {
- std::cout << key << " not found" << std::endl;
+ std::cout << key << " not found\n";
return false;
}
@@ -69,7 +69,7 @@ class IndexSearch {
return lhs.first < rhs.first;
});
if (positions.first == positions.second) {
- std::cout << key << " not found" << std::endl;
+ std::cout << key << " not found\n";
return false;
}
@@ -103,7 +103,7 @@ public:
}
}
- bool search(std::vector<TKey> keys) {
+ bool search(const std::vector<TKey>& keys) {
bool found_all = true;
for (const auto key : keys) {
@@ -173,7 +173,7 @@ public:
break;
case 'h':
print_help();
- exit(return_code::okay);
+ std::exit(return_code::okay);
case 'l':
m_list_format = true;
m_filename = optarg;
@@ -185,22 +185,22 @@ public:
m_type = optarg;
if (m_type != "location" && m_type != "offset") {
std::cerr << "Unknown type '" << m_type << "'. Must be 'location' or 'offset'.\n";
- exit(return_code::fatal);
+ std::exit(return_code::fatal);
}
break;
default:
- exit(return_code::fatal);
+ std::exit(return_code::fatal);
}
}
if (m_array_format == m_list_format) {
std::cerr << "Need option --array or --list, but not both\n";
- exit(return_code::fatal);
+ std::exit(return_code::fatal);
}
if (m_type.empty()) {
std::cerr << "Need --type argument.\n";
- exit(return_code::fatal);
+ std::exit(return_code::fatal);
}
}
@@ -255,6 +255,6 @@ int main(int argc, char* argv[]) {
}
}
- exit(result_okay ? return_code::okay : return_code::not_found);
+ std::exit(result_okay ? return_code::okay : return_code::not_found);
}
diff --git a/examples/osmium_location_cache_create.cpp b/examples/osmium_location_cache_create.cpp
new file mode 100644
index 0000000..9de41d1
--- /dev/null
+++ b/examples/osmium_location_cache_create.cpp
@@ -0,0 +1,87 @@
+/*
+
+ EXAMPLE osmium_location_cache_create
+
+ Reads nodes from an OSM file and writes out their locations to a cache
+ file. The cache file can then be read with osmium_location_cache_use.
+
+ Warning: The locations cache file will get huge (>32GB) if you are using
+ the DenseFileArray index even if the input file is small, because
+ it depends on the *largest* node ID, not the number of nodes.
+
+ DEMONSTRATES USE OF:
+ * file input
+ * location indexes and the NodeLocationsForWays handler
+ * location indexes on disk
+
+ SIMPLER EXAMPLES you might want to understand first:
+ * osmium_read
+ * osmium_count
+ * osmium_road_length
+
+ LICENSE
+ The code in this example file is released into the Public Domain.
+
+*/
+
+#include <cerrno> // for errno
+#include <cstdlib> // for std::exit
+#include <cstring> // for strerror
+#include <fcntl.h> // for open
+#include <iostream> // for std::cout, std::cerr
+#include <string> // for std::string
+#include <sys/stat.h> // for open
+#include <sys/types.h> // for open
+
+// Allow any format of input files (XML, PBF, ...)
+#include <osmium/io/any_input.hpp>
+
+// For the location index. There are different types of index implementation
+// available. These implementations put the index on disk. See below.
+#include <osmium/index/map/sparse_file_array.hpp>
+#include <osmium/index/map/dense_file_array.hpp>
+
+// For the NodeLocationForWays handler
+#include <osmium/handler/node_locations_for_ways.hpp>
+
+// For osmium::apply()
+#include <osmium/visitor.hpp>
+
+// Chose one of these two. "sparse" is best used for small and medium extracts,
+// the "dense" index for large extracts or the whole planet.
+using index_type = osmium::index::map::SparseFileArray<osmium::unsigned_object_id_type, osmium::Location>;
+//using index_type = osmium::index::map::DenseFileArray<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>;
+
+int main(int argc, char* argv[]) {
+ if (argc != 3) {
+ std::cerr << "Usage: " << argv[0] << " OSM_FILE CACHE_FILE\n";
+ std::exit(1);
+ }
+
+ const std::string input_filename{argv[1]};
+ const std::string cache_filename{argv[2]};
+
+ // Construct Reader reading only nodes
+ 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);
+ if (fd == -1) {
+ std::cerr << "Can not open location cache file '" << cache_filename << "': " << std::strerror(errno) << "\n";
+ std::exit(1);
+ }
+ index_type index{fd};
+
+ // The handler that stores all node locations in the index.
+ location_handler_type location_handler{index};
+
+ // Feed all nodes through the location handler.
+ osmium::apply(reader, location_handler);
+
+ // Explicitly close input so we get notified of any errors.
+ reader.close();
+}
+
diff --git a/examples/osmium_location_cache_use.cpp b/examples/osmium_location_cache_use.cpp
new file mode 100644
index 0000000..f5db0be
--- /dev/null
+++ b/examples/osmium_location_cache_use.cpp
@@ -0,0 +1,101 @@
+/*
+
+ EXAMPLE osmium_location_cache_use
+
+ This reads ways from an OSM file and writes out the way node locations
+ it got from a location cache generated with osmium_location_cache_create.
+
+ Warning: The locations cache file will get huge (>32GB) if you are using
+ the DenseFileArray index even if the input file is small, because
+ it depends on the *largest* node ID, not the number of nodes.
+
+ DEMONSTRATES USE OF:
+ * file input
+ * location indexes and the NodeLocationsForWays handler
+ * location indexes on disk
+
+ SIMPLER EXAMPLES you might want to understand first:
+ * osmium_read
+ * osmium_count
+ * osmium_road_length
+
+ LICENSE
+ The code in this example file is released into the Public Domain.
+
+*/
+
+#include <cerrno> // for errno
+#include <cstdlib> // for std::exit
+#include <cstring> // for strerror
+#include <fcntl.h> // for open
+#include <iostream> // for std::cout, std::cerr
+#include <string> // for std::string
+#include <sys/stat.h> // for open
+#include <sys/types.h> // for open
+
+// Allow any format of input files (XML, PBF, ...)
+#include <osmium/io/any_input.hpp>
+
+// For the location index. There are different types of index implementation
+// available. These implementations put the index on disk. See below.
+#include <osmium/index/map/dense_file_array.hpp>
+#include <osmium/index/map/sparse_file_array.hpp>
+
+// For the NodeLocationForWays handler
+#include <osmium/handler/node_locations_for_ways.hpp>
+
+// For osmium::apply()
+#include <osmium/visitor.hpp>
+
+// Chose one of these two. "sparse" is best used for small and medium extracts,
+// the "dense" index for large extracts or the whole planet.
+using index_type = osmium::index::map::SparseFileArray<osmium::unsigned_object_id_type, osmium::Location>;
+//using index_type = osmium::index::map::DenseFileArray<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>;
+
+// This handler only implements the way() function which prints out the way
+// ID and all nodes IDs and locations in those ways.
+struct MyHandler : public osmium::handler::Handler {
+
+ void way(const osmium::Way& way) {
+ std::cout << "way " << way.id() << "\n";
+ for (const auto& nr : way.nodes()) {
+ std::cout << " node " << nr.ref() << " " << nr.location() << "\n";
+ }
+ }
+
+}; // struct MyHandler
+
+int main(int argc, char* argv[]) {
+ if (argc != 3) {
+ std::cerr << "Usage: " << argv[0] << " OSM_FILE CACHE_FILE\n";
+ std::exit(1);
+ }
+
+ const std::string input_filename{argv[1]};
+ const std::string cache_filename{argv[2]};
+
+ // Construct Reader reading only ways
+ 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);
+ if (fd == -1) {
+ std::cerr << "Can not open location cache file '" << cache_filename << "': " << std::strerror(errno) << "\n";
+ return 1;
+ }
+ index_type index{fd};
+
+ // The handler that adds node locations from the index to the ways.
+ location_handler_type location_handler{index};
+
+ // Feed all ways through the location handler and then our own handler.
+ MyHandler handler;
+ osmium::apply(reader, location_handler, handler);
+
+ // Explicitly close input so we get notified of any errors.
+ reader.close();
+}
+
diff --git a/examples/osmium_pub_names.cpp b/examples/osmium_pub_names.cpp
new file mode 100755
index 0000000..dbc37c3
--- /dev/null
+++ b/examples/osmium_pub_names.cpp
@@ -0,0 +1,89 @@
+/*
+
+ EXAMPLE osmium_pub_names
+
+ Show the names and addresses of all pubs found in an OSM file.
+
+ DEMONSTRATES USE OF:
+ * file input
+ * your own handler
+ * access to tags
+
+ SIMPLER EXAMPLES you might want to understand first:
+ * osmium_read
+ * osmium_count
+
+ LICENSE
+ The code in this example file is released into the Public Domain.
+
+*/
+
+#include <cstdlib> // for std::exit
+#include <cstring> // for std::strncmp
+#include <iostream> // for std::cout, std::cerr
+
+// Allow any format of input files (XML, PBF, ...)
+#include <osmium/io/any_input.hpp>
+
+// We want to use the handler interface
+#include <osmium/handler.hpp>
+
+// For osmium::apply()
+#include <osmium/visitor.hpp>
+
+class NamesHandler : public osmium::handler::Handler {
+
+ void output_pubs(const osmium::OSMObject& object) {
+ const osmium::TagList& tags = object.tags();
+ if (tags.has_tag("amenity", "pub")) {
+
+ // Print name of the pub if it is set.
+ const char* name = tags["name"];
+ if (name) {
+ std::cout << name << "\n";
+ } else {
+ std::cout << "pub with unknown name\n";
+ }
+
+ // Iterate over all tags finding those which start with "addr:"
+ // and print them.
+ for (const osmium::Tag& tag : tags) {
+ if (!std::strncmp(tag.key(), "addr:", 5)) {
+ std::cout << " " << tag.key() << ": " << tag.value() << "\n";
+ }
+ }
+ }
+ }
+
+public:
+
+ // Nodes can be tagged amenity=pub.
+ void node(const osmium::Node& node) {
+ output_pubs(node);
+ }
+
+ // Ways can be tagged amenity=pub, too (typically buildings).
+ void way(const osmium::Way& way) {
+ output_pubs(way);
+ }
+
+}; // class NamesHandler
+
+int main(int argc, char* argv[]) {
+ if (argc != 2) {
+ std::cerr << "Usage: " << argv[0] << " OSMFILE\n";
+ std::exit(1);
+ }
+
+ // Construct the handler defined above
+ NamesHandler names_handler;
+
+ // Initialize the reader with the filename from the command line and
+ // tell it to only read nodes and ways. We are ignoring multipolygon
+ // relations in this simple example.
+ osmium::io::Reader reader{argv[1], osmium::osm_entity_bits::node | osmium::osm_entity_bits::way};
+
+ // Apply input data to our own handler
+ osmium::apply(reader, names_handler);
+}
+
diff --git a/examples/osmium_read.cpp b/examples/osmium_read.cpp
index 6536006..9f391c8 100644
--- a/examples/osmium_read.cpp
+++ b/examples/osmium_read.cpp
@@ -1,30 +1,42 @@
/*
- This is a small tool that reads and discards the contents of the input file.
- (Used for timing.)
+ EXAMPLE osmium_read
+ Reads and discards the contents of the input file.
+ (It can be used for timing.)
+
+ DEMONSTRATES USE OF:
+ * file input
+
+ LICENSE
The code in this example file is released into the Public Domain.
*/
-#include <iostream>
+#include <cstdlib> // for std::exit
+#include <iostream> // for std::cerr
+// Allow any format of input files (XML, PBF, ...)
#include <osmium/io/any_input.hpp>
int main(int argc, char* argv[]) {
-
if (argc != 2) {
std::cerr << "Usage: " << argv[0] << " OSMFILE\n";
- exit(1);
+ std::exit(1);
}
- osmium::io::File infile(argv[1]);
- osmium::io::Reader reader(infile);
+ // The Reader is initialized here with an osmium::io::File, but could
+ // also be directly initialized with a file name.
+ osmium::io::File input_file{argv[1]};
+ osmium::io::Reader reader{input_file};
+ // OSM data comes in buffers, read until there are no more.
while (osmium::memory::Buffer buffer = reader.read()) {
// do nothing
}
+ // You do not have to close the Reader explicitly, but because the
+ // destructor can't throw, you will not see any errors otherwise.
reader.close();
}
diff --git a/examples/osmium_read_with_progress.cpp b/examples/osmium_read_with_progress.cpp
new file mode 100644
index 0000000..81437a6
--- /dev/null
+++ b/examples/osmium_read_with_progress.cpp
@@ -0,0 +1,56 @@
+/*
+
+ EXAMPLE osmium_read_with_progress
+
+ Reads the contents of the input file showing a progress bar.
+
+ DEMONSTRATES USE OF:
+ * file input
+ * ProgressBar utility function
+
+ SIMPLER EXAMPLES you might want to understand first:
+ * osmium_read
+
+ LICENSE
+ The code in this example file is released into the Public Domain.
+
+*/
+
+#include <cstdlib> // for std::exit
+#include <iostream> // for std::cerr
+
+// Allow any format of input files (XML, PBF, ...)
+#include <osmium/io/any_input.hpp>
+
+// Get access to isatty utility function and progress bar utility class.
+#include <osmium/util/file.hpp>
+#include <osmium/util/progress_bar.hpp>
+
+int main(int argc, char* argv[]) {
+ if (argc != 2) {
+ std::cerr << "Usage: " << argv[0] << " OSMFILE\n";
+ std::exit(1);
+ }
+
+ // The Reader is initialized here with an osmium::io::File, but could
+ // also be directly initialized with a file name.
+ osmium::io::File input_file{argv[1]};
+ osmium::io::Reader reader{input_file};
+
+ // Initialize progress bar, enable it only if STDERR is a TTY.
+ osmium::ProgressBar progress{reader.file_size(), osmium::util::isatty(2)};
+
+ // OSM data comes in buffers, read until there are no more.
+ while (osmium::memory::Buffer buffer = reader.read()) {
+ // Update progress bar for each buffer.
+ progress.update(reader.offset());
+ }
+
+ // Progress bar is done.
+ progress.done();
+
+ // You do not have to close the Reader explicitly, but because the
+ // destructor can't throw, you will not see any errors otherwise.
+ reader.close();
+}
+
diff --git a/examples/osmium_road_length.cpp b/examples/osmium_road_length.cpp
new file mode 100755
index 0000000..2e1be90
--- /dev/null
+++ b/examples/osmium_road_length.cpp
@@ -0,0 +1,92 @@
+/*
+
+ EXAMPLE osmium_road_length
+
+ Calculate the length of the road network (everything tagged `highway=*`)
+ from the given OSM file.
+
+ DEMONSTRATES USE OF:
+ * file input
+ * location indexes and the NodeLocationsForWays handler
+ * length calculation on the earth using the haversine function
+
+ SIMPLER EXAMPLES you might want to understand first:
+ * osmium_read
+ * osmium_count
+ * osmium_pub_names
+
+ LICENSE
+ The code in this example file is released into the Public Domain.
+
+*/
+
+#include <cstdlib> // for std::exit
+#include <iostream> // for std::cout, std::cerr
+
+// Allow any format of input files (XML, PBF, ...)
+#include <osmium/io/any_input.hpp>
+
+// For the osmium::geom::haversine::distance() function
+#include <osmium/geom/haversine.hpp>
+
+// For osmium::apply()
+#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>
+
+// 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>;
+
+// The location handler always depends on the index type
+using location_handler_type = osmium::handler::NodeLocationsForWays<index_type>;
+
+// This handler only implements the way() function, we are not interested in
+// any other objects.
+struct RoadLengthHandler : public osmium::handler::Handler {
+
+ double length = 0;
+
+ // If the way has a "highway" tag, find its length and add it to the
+ // overall length.
+ void way(const osmium::Way& way) {
+ const char* highway = way.tags()["highway"];
+ if (highway) {
+ length += osmium::geom::haversine::distance(way.nodes());
+ }
+ }
+
+}; // struct RoadLengthHandler
+
+int main(int argc, char* argv[]) {
+ if (argc != 2) {
+ std::cerr << "Usage: " << argv[0] << " OSMFILE\n";
+ std::exit(1);
+ }
+
+ // Initialize the reader with the filename from the command line and
+ // tell it to only read nodes and ways.
+ osmium::io::Reader reader{argv[1], osmium::osm_entity_bits::node | osmium::osm_entity_bits::way};
+
+ // The index to hold node locations.
+ index_type index;
+
+ // The location handler will add the node locations to the index and then
+ // to the ways
+ location_handler_type location_handler{index};
+
+ // Our handler defined above
+ RoadLengthHandler road_length_handler;
+
+ // Apply input data to first the location handler and then our own handler
+ osmium::apply(reader, location_handler, road_length_handler);
+
+ // Output the length. The haversine function calculates it in meters,
+ // so we first devide by 1000 to get kilometers.
+ std::cout << "Length: " << road_length_handler.length / 1000 << " km\n";
+}
+
diff --git a/examples/osmium_serdump.cpp b/examples/osmium_serdump.cpp
index 9ab26e4..81a6d0c 100644
--- a/examples/osmium_serdump.cpp
+++ b/examples/osmium_serdump.cpp
@@ -69,9 +69,9 @@ int main(int argc, char* argv[]) {
switch (c) {
case 'h':
print_help();
- exit(0);
+ std::exit(0);
default:
- exit(2);
+ std::exit(2);
}
}
@@ -79,7 +79,7 @@ int main(int argc, char* argv[]) {
if (remaining_args != 2) {
std::cerr << "Usage: " << argv[0] << " OSMFILE DIR\n";
- exit(2);
+ std::exit(2);
}
std::string dir(argv[optind+1]);
@@ -90,14 +90,14 @@ int main(int argc, char* argv[]) {
#endif
if (result == -1 && errno != EEXIST) {
std::cerr << "Problem creating directory '" << dir << "': " << strerror(errno) << "\n";
- exit(2);
+ std::exit(2);
}
std::string data_file(dir + "/data.osm.ser");
int data_fd = ::open(data_file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (data_fd < 0) {
std::cerr << "Can't open data file '" << data_file << "': " << strerror(errno) << "\n";
- exit(2);
+ std::exit(2);
}
offset_index_type node_index;
@@ -127,7 +127,7 @@ int main(int argc, char* argv[]) {
int fd = ::open(index_file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (fd < 0) {
std::cerr << "Can't open nodes index file '" << index_file << "': " << strerror(errno) << "\n";
- exit(2);
+ std::exit(2);
}
node_index.dump_as_list(fd);
close(fd);
@@ -138,7 +138,7 @@ int main(int argc, char* argv[]) {
int fd = ::open(index_file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (fd < 0) {
std::cerr << "Can't open ways index file '" << index_file << "': " << strerror(errno) << "\n";
- exit(2);
+ std::exit(2);
}
way_index.dump_as_list(fd);
close(fd);
@@ -149,7 +149,7 @@ int main(int argc, char* argv[]) {
int fd = ::open(index_file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (fd < 0) {
std::cerr << "Can't open relations index file '" << index_file << "': " << strerror(errno) << "\n";
- exit(2);
+ std::exit(2);
}
relation_index.dump_as_list(fd);
close(fd);
@@ -161,7 +161,7 @@ int main(int argc, char* argv[]) {
int fd = ::open(index_file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (fd < 0) {
std::cerr << "Can't open node->way map file '" << index_file << "': " << strerror(errno) << "\n";
- exit(2);
+ std::exit(2);
}
map_node2way.dump_as_list(fd);
close(fd);
@@ -173,7 +173,7 @@ int main(int argc, char* argv[]) {
int fd = ::open(index_file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (fd < 0) {
std::cerr << "Can't open node->rel map file '" << index_file << "': " << strerror(errno) << "\n";
- exit(2);
+ std::exit(2);
}
map_node2relation.dump_as_list(fd);
close(fd);
@@ -185,7 +185,7 @@ int main(int argc, char* argv[]) {
int fd = ::open(index_file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (fd < 0) {
std::cerr << "Can't open way->rel map file '" << index_file << "': " << strerror(errno) << "\n";
- exit(2);
+ std::exit(2);
}
map_way2relation.dump_as_list(fd);
close(fd);
@@ -197,7 +197,7 @@ int main(int argc, char* argv[]) {
int fd = ::open(index_file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (fd < 0) {
std::cerr << "Can't open rel->rel map file '" << index_file << "': " << strerror(errno) << "\n";
- exit(2);
+ std::exit(2);
}
map_relation2relation.dump_as_list(fd);
close(fd);
diff --git a/examples/osmium_tiles.cpp b/examples/osmium_tiles.cpp
new file mode 100644
index 0000000..7dbeb3e
--- /dev/null
+++ b/examples/osmium_tiles.cpp
@@ -0,0 +1,72 @@
+/*
+
+ EXAMPLE osmium_tiles
+
+ Convert WGS84 longitude and latitude to Mercator coordinates and tile
+ coordinates.
+
+ DEMONSTRATES USE OF:
+ * the Location and Coordinates classes
+ * the Mercator projection function
+ * the Tile class
+
+ LICENSE
+ The code in this example file is released into the Public Domain.
+
+*/
+
+#include <cstdlib> // for std::exit, std::atoi, std::atof
+#include <iostream> // for std::cout, std::cerr
+
+// The Location contains a longitude and latitude and is usually used inside
+// a node to store its location in the world.
+#include <osmium/osm/location.hpp>
+
+// Needed for the Mercator projection function. Osmium supports the Mercator
+// projection out of the box, or pretty much any projection using the Proj.4
+// library (with the osmium::geom::Projection class).
+#include <osmium/geom/mercator_projection.hpp>
+
+// The Tile class handles tile coordinates and zoom levels.
+#include <osmium/geom/tile.hpp>
+
+int main(int argc, char* argv[]) {
+ if (argc != 4) {
+ std::cerr << "Usage: " << argv[0] << " ZOOM LON LAT\n";
+ std::exit(1);
+ }
+
+ const int zoom = std::atoi(argv[1]);
+
+ if (zoom < 0 || zoom > 30) {
+ std::cerr << "ERROR: Zoom must be between 0 and 30\n";
+ std::exit(1);
+ }
+
+ const double lon = std::atof(argv[2]);
+ const double lat = std::atof(argv[3]);
+
+ // Create location from WGS84 coordinates. In Osmium the order of
+ // coordinate values is always x/longitude first, then y/latitude.
+ const osmium::Location location{lon, lat};
+
+ std::cout << "WGS84: lon=" << lon << " lat=" << lat << "\n";
+
+ // A location can store some invalid locations, ie locations outside the
+ // -180 to 180 and -90 to 90 degree range. This function checks for that.
+ if (!location.valid()) {
+ std::cerr << "ERROR: Location is invalid\n";
+ std::exit(1);
+ }
+
+ // Project the coordinates using a helper function. You can also use the
+ // osmium::geom::MercatorProjection class.
+ const osmium::geom::Coordinates c = osmium::geom::lonlat_to_mercator(location);
+ std::cout << "Mercator: x=" << c.x << " y=" << c.y << "\n";
+
+ // Create a tile at this location. This will also internally use the
+ // Mercator projection and then calculate the tile coordinates.
+ const osmium::geom::Tile tile{uint32_t(zoom), location};
+ std::cout << "Tile: zoom=" << tile.z << " x=" << tile.x << " y=" << tile.y << "\n";
+}
+
diff --git a/examples/osmium_use_node_cache.cpp b/examples/osmium_use_node_cache.cpp
deleted file mode 100644
index cfee6df..0000000
--- a/examples/osmium_use_node_cache.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
-
- This reads ways from an OSM file and writes out the node locations
- it got from a node cache generated with osmium_create_node_cache.
-
- The code in this example file is released into the Public Domain.
-
-*/
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <iostream>
-
-#include <osmium/io/any_input.hpp>
-
-#include <osmium/index/map/dummy.hpp>
-#include <osmium/index/map/dense_file_array.hpp>
-#include <osmium/index/map/dense_mmap_array.hpp>
-
-#include <osmium/handler/node_locations_for_ways.hpp>
-#include <osmium/visitor.hpp>
-
-typedef osmium::index::map::Dummy<osmium::unsigned_object_id_type, osmium::Location> index_neg_type;
-//typedef osmium::index::map::DenseMmapArray<osmium::unsigned_object_id_type, osmium::Location> index_pos_type;
-typedef osmium::index::map::DenseFileArray<osmium::unsigned_object_id_type, osmium::Location> index_pos_type;
-
-typedef osmium::handler::NodeLocationsForWays<index_pos_type, index_neg_type> location_handler_type;
-
-class MyHandler : public osmium::handler::Handler {
-
-public:
-
- void way(osmium::Way& way) {
- for (auto& nr : way.nodes()) {
- std::cout << nr << "\n";
- }
- }
-
-}; // class MyHandler
-
-int main(int argc, char* argv[]) {
- if (argc != 3) {
- std::cerr << "Usage: " << argv[0] << " OSM_FILE CACHE_FILE\n";
- return 1;
- }
-
- std::string input_filename(argv[1]);
- osmium::io::Reader reader(input_filename, osmium::osm_entity_bits::way);
-
- int fd = open(argv[2], O_RDWR);
- if (fd == -1) {
- std::cerr << "Can not open node cache file '" << argv[2] << "': " << strerror(errno) << "\n";
- return 1;
- }
-
- index_pos_type index_pos {fd};
- index_neg_type index_neg;
- location_handler_type location_handler(index_pos, index_neg);
- location_handler.ignore_errors();
-
- MyHandler handler;
- osmium::apply(reader, location_handler, handler);
- reader.close();
-
- return 0;
-}
-
diff --git a/include/osmium/area/assembler.hpp b/include/osmium/area/assembler.hpp
index 9095302..d5bf8d8 100644
--- a/include/osmium/area/assembler.hpp
+++ b/include/osmium/area/assembler.hpp
@@ -35,6 +35,8 @@ DEALINGS IN THE SOFTWARE.
#include <algorithm>
#include <cassert>
+#include <cstdint>
+#include <cstdlib>
#include <cstring>
#include <iostream>
#include <iterator>
@@ -42,16 +44,21 @@ DEALINGS IN THE SOFTWARE.
#include <set>
#include <string>
#include <map>
-#include <numeric>
#include <unordered_map>
#include <unordered_set>
+#include <utility>
#include <vector>
#include <osmium/builder/osm_object_builder.hpp>
#include <osmium/memory/buffer.hpp>
#include <osmium/osm/area.hpp>
+#include <osmium/osm/item_type.hpp>
#include <osmium/osm/location.hpp>
+#include <osmium/osm/node_ref.hpp>
#include <osmium/osm/relation.hpp>
+#include <osmium/osm/tag.hpp>
+#include <osmium/osm/types.hpp>
+#include <osmium/osm/way.hpp>
#include <osmium/tags/filter.hpp>
#include <osmium/util/compatibility.hpp>
#include <osmium/util/iterator.hpp>
@@ -259,6 +266,9 @@ namespace osmium {
// Statistics
area_stats m_stats;
+ // The number of members the multipolygon relation has
+ size_t m_num_members = 0;
+
bool debug() const noexcept {
return m_config.debug_level > 1;
}
@@ -582,7 +592,7 @@ namespace osmium {
if (debug()) {
std::cerr << " Segment belongs to outer ring\n";
}
- int32_t y = int32_t(ay + (by - ay) * (lx - ax) / (bx - ax));
+ const int32_t y = int32_t(ay + (by - ay) * (lx - ax) / (bx - ax));
outer_rings.emplace_back(y, segment->ring());
}
}
@@ -819,7 +829,7 @@ namespace osmium {
}
void create_rings_simple_case() {
- uint32_t count_remaining = m_segment_list.size();
+ auto count_remaining = m_segment_list.size();
for (slocation& sl : m_locations) {
const detail::NodeRefSegment& segment = m_segment_list[sl.item];
if (!segment.is_done()) {
@@ -1005,7 +1015,7 @@ namespace osmium {
std::vector<location_to_ring_map> xrings = create_location_to_ring_map(open_ring_its);
- auto ring_min = std::min_element(xrings.begin(), xrings.end(), [](const location_to_ring_map& a, const location_to_ring_map& b) {
+ const auto ring_min = std::min_element(xrings.begin(), xrings.end(), [](const location_to_ring_map& a, const location_to_ring_map& b) {
return a.ring().min_segment() < b.ring().min_segment();
});
@@ -1057,7 +1067,7 @@ namespace osmium {
}
// Find the candidate with the smallest/largest area
- auto chosen_cand = ring_min_is_outer ?
+ const auto chosen_cand = ring_min_is_outer ?
std::min_element(candidates.cbegin(), candidates.cend(), [](const candidate& a, const candidate& b) {
return std::abs(a.sum) < std::abs(b.sum);
}) :
@@ -1088,7 +1098,7 @@ namespace osmium {
bool create_rings_complex_case() {
// First create all the (partial) rings starting at the split locations
- uint32_t count_remaining = m_segment_list.size();
+ auto count_remaining = m_segment_list.size();
for (const osmium::Location& location : m_split_locations) {
const auto locs = make_range(std::equal_range(m_locations.begin(),
m_locations.end(),
@@ -1162,6 +1172,20 @@ namespace osmium {
}
/**
+ * Checks if any ways were completely removed in the
+ * erase_duplicate_segments step.
+ */
+ bool ways_were_lost() {
+ std::unordered_set<const osmium::Way*> ways_in_segments;
+
+ for (const auto& segment : m_segment_list) {
+ ways_in_segments.insert(segment.way());
+ }
+
+ return ways_in_segments.size() < m_num_members;
+ }
+
+ /**
* Create rings from segments.
*/
bool create_rings() {
@@ -1189,6 +1213,15 @@ namespace osmium {
return false;
}
+ // If one or more complete ways was removed because of
+ // duplicate segments, this isn't a valid area.
+ if (ways_were_lost()) {
+ if (debug()) {
+ std::cerr << " Complete ways removed because of duplicate segments\n";
+ }
+ return false;
+ }
+
if (m_config.debug_level >= 3) {
std::cerr << "Sorted de-duplicated segment list:\n";
for (const auto& s : m_segment_list) {
@@ -1348,6 +1381,7 @@ namespace osmium {
}
bool create_area(osmium::memory::Buffer& out_buffer, const osmium::Relation& relation, const std::vector<const osmium::Way*>& members) {
+ m_num_members = members.size();
osmium::builder::AreaBuilder builder(out_buffer);
builder.initialize_from_object(relation);
diff --git a/include/osmium/area/detail/node_ref_segment.hpp b/include/osmium/area/detail/node_ref_segment.hpp
index bb97520..b131a43 100644
--- a/include/osmium/area/detail/node_ref_segment.hpp
+++ b/include/osmium/area/detail/node_ref_segment.hpp
@@ -36,7 +36,6 @@ DEALINGS IN THE SOFTWARE.
#include <algorithm>
#include <cassert>
#include <cstdint>
-#include <cstring>
#include <iosfwd>
#include <utility>
@@ -242,19 +241,19 @@ namespace osmium {
*/
inline bool operator<(const NodeRefSegment& lhs, const NodeRefSegment& rhs) noexcept {
if (lhs.first().location() == rhs.first().location()) {
- vec p0{lhs.first().location()};
- vec p1{lhs.second().location()};
- vec q0{rhs.first().location()};
- vec q1{rhs.second().location()};
- vec p = p1 - p0;
- vec q = q1 - q0;
+ const vec p0{lhs.first().location()};
+ const vec p1{lhs.second().location()};
+ const vec q0{rhs.first().location()};
+ const vec q1{rhs.second().location()};
+ const vec p = p1 - p0;
+ const vec q = q1 - q0;
if (p.x == 0 && q.x == 0) {
return p.y < q.y;
}
- auto a = p.y * q.x;
- auto b = q.y * p.x;
+ const auto a = p.y * q.x;
+ const auto b = q.y * p.x;
if (a == b) {
return p.x < q.x;
}
diff --git a/include/osmium/area/detail/proto_ring.hpp b/include/osmium/area/detail/proto_ring.hpp
index c71a5d3..bce6817 100644
--- a/include/osmium/area/detail/proto_ring.hpp
+++ b/include/osmium/area/detail/proto_ring.hpp
@@ -34,10 +34,9 @@ DEALINGS IN THE SOFTWARE.
*/
#include <algorithm>
+#include <cassert>
#include <cstdint>
-#include <cstdlib>
#include <iostream>
-#include <iterator>
#include <set>
#include <vector>
@@ -47,6 +46,8 @@ DEALINGS IN THE SOFTWARE.
namespace osmium {
+ class Way;
+
namespace area {
namespace detail {
diff --git a/include/osmium/area/detail/segment_list.hpp b/include/osmium/area/detail/segment_list.hpp
index d7c5927..a4361e0 100644
--- a/include/osmium/area/detail/segment_list.hpp
+++ b/include/osmium/area/detail/segment_list.hpp
@@ -35,13 +35,16 @@ DEALINGS IN THE SOFTWARE.
#include <algorithm>
#include <cassert>
+#include <cstdint>
+#include <cstring>
#include <iostream>
+#include <iterator>
#include <numeric>
#include <vector>
-#include <osmium/area/problem_reporter.hpp>
#include <osmium/area/detail/node_ref_segment.hpp>
-#include <osmium/memory/buffer.hpp>
+#include <osmium/area/problem_reporter.hpp>
+#include <osmium/osm/item_type.hpp>
#include <osmium/osm/location.hpp>
#include <osmium/osm/node_ref.hpp>
#include <osmium/osm/relation.hpp>
@@ -60,7 +63,7 @@ namespace osmium {
* non-way members in the relation.
*/
template <typename F>
- inline void for_each_member(const osmium::Relation& relation, const std::vector<const osmium::Way*> ways, F&& func) {
+ inline void for_each_member(const osmium::Relation& relation, const std::vector<const osmium::Way*>& ways, F&& func) {
auto way_it = ways.cbegin();
for (const osmium::RelationMember& member : relation.members()) {
if (member.type() == osmium::item_type::way) {
@@ -225,7 +228,7 @@ namespace osmium {
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());
- size_t num_segments = get_num_segments(members);
+ const size_t num_segments = get_num_segments(members);
if (problem_reporter) {
problem_reporter->set_nodes(num_segments);
}
@@ -258,11 +261,13 @@ namespace osmium {
}
// Only count and report duplicate segments if they
- // belong to the same way. Those cases are definitely
- // wrong. If the duplicate segments belong to
- // different ways, they could be touching inner rings
- // which are perfectly okay.
- if (it->way() == std::next(it)->way()) {
+ // belong to the same way or if they don't both have
+ // the role "inner". Those cases are definitely wrong.
+ // If the duplicate segments belong to different
+ // "inner" ways, they could be touching inner rings
+ // which are perfectly okay. Note that for this check
+ // the role has to be correct in the member data.
+ if (it->way() == std::next(it)->way() || !it->role_inner() || !std::next(it)->role_inner()) {
++duplicate_segments;
if (problem_reporter) {
problem_reporter->report_duplicate_segment(it->first(), it->second());
diff --git a/include/osmium/area/detail/vector.hpp b/include/osmium/area/detail/vector.hpp
index 283801a..44983cc 100644
--- a/include/osmium/area/detail/vector.hpp
+++ b/include/osmium/area/detail/vector.hpp
@@ -34,6 +34,7 @@ DEALINGS IN THE SOFTWARE.
*/
#include <cstdint>
+#include <iosfwd>
#include <osmium/osm/location.hpp>
#include <osmium/osm/node_ref.hpp>
diff --git a/include/osmium/area/multipolygon_collector.hpp b/include/osmium/area/multipolygon_collector.hpp
index 0f5e4d7..8b37052 100644
--- a/include/osmium/area/multipolygon_collector.hpp
+++ b/include/osmium/area/multipolygon_collector.hpp
@@ -47,7 +47,6 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/osm/tag.hpp>
#include <osmium/osm/way.hpp>
#include <osmium/relations/collector.hpp>
-#include <osmium/relations/detail/member_meta.hpp>
namespace osmium {
@@ -164,7 +163,7 @@ namespace osmium {
m_stats += assembler.stats();
possibly_flush_output_buffer();
}
- } catch (osmium::invalid_location&) {
+ } catch (const osmium::invalid_location&) {
// XXX ignore
}
}
@@ -176,7 +175,7 @@ namespace osmium {
std::vector<const osmium::Way*> ways;
for (const auto& member : relation.members()) {
if (member.ref() != 0) {
- size_t offset = this->get_offset(member.type(), member.ref());
+ const size_t offset = this->get_offset(member.type(), member.ref());
ways.push_back(&buffer.get<const osmium::Way>(offset));
}
}
@@ -186,7 +185,7 @@ namespace osmium {
assembler(relation, ways, m_output_buffer);
m_stats += assembler.stats();
possibly_flush_output_buffer();
- } catch (osmium::invalid_location&) {
+ } catch (const osmium::invalid_location&) {
// XXX ignore
}
}
diff --git a/include/osmium/area/problem_reporter.hpp b/include/osmium/area/problem_reporter.hpp
index 13fb096..6c56231 100644
--- a/include/osmium/area/problem_reporter.hpp
+++ b/include/osmium/area/problem_reporter.hpp
@@ -33,6 +33,8 @@ DEALINGS IN THE SOFTWARE.
*/
+#include <cstddef>
+
#include <osmium/osm/item_type.hpp>
#include <osmium/osm/location.hpp>
#include <osmium/osm/types.hpp>
diff --git a/include/osmium/area/problem_reporter_exception.hpp b/include/osmium/area/problem_reporter_exception.hpp
index 8acd181..009a5f4 100644
--- a/include/osmium/area/problem_reporter_exception.hpp
+++ b/include/osmium/area/problem_reporter_exception.hpp
@@ -43,6 +43,7 @@ DEALINGS IN THE SOFTWARE.
namespace osmium {
class NodeRef;
+ class Way;
namespace area {
diff --git a/include/osmium/area/problem_reporter_ogr.hpp b/include/osmium/area/problem_reporter_ogr.hpp
index b7704a7..0889a58 100644
--- a/include/osmium/area/problem_reporter_ogr.hpp
+++ b/include/osmium/area/problem_reporter_ogr.hpp
@@ -42,7 +42,6 @@ DEALINGS IN THE SOFTWARE.
* @attention If you include this file, you'll need to link with `libgdal`.
*/
-#include <cstdint>
#include <memory>
#include <gdalcpp.hpp>
@@ -50,6 +49,7 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/area/problem_reporter.hpp>
#include <osmium/geom/factory.hpp>
#include <osmium/geom/ogr.hpp>
+#include <osmium/osm/item_type.hpp>
#include <osmium/osm/location.hpp>
#include <osmium/osm/node_ref.hpp>
#include <osmium/osm/node_ref_list.hpp>
@@ -181,7 +181,7 @@ namespace osmium {
feature.set_field("id2", 0);
feature.set_field("problem", "way_in_multiple_rings");
feature.add_to_layer();
- } catch (osmium::geometry_error& e) {
+ } catch (const osmium::geometry_error&) {
// XXX
}
}
@@ -197,7 +197,7 @@ namespace osmium {
feature.set_field("id2", 0);
feature.set_field("problem", "inner_with_same_tags");
feature.add_to_layer();
- } catch (osmium::geometry_error& e) {
+ } catch (const osmium::geometry_error&) {
// XXX
}
}
@@ -216,7 +216,7 @@ namespace osmium {
set_object(feature);
feature.set_field("way_id", int32_t(way.id()));
feature.add_to_layer();
- } catch (osmium::geometry_error& e) {
+ } catch (const osmium::geometry_error&) {
// XXX
}
}
diff --git a/include/osmium/builder/attr.hpp b/include/osmium/builder/attr.hpp
index d9831c2..2a5b690 100644
--- a/include/osmium/builder/attr.hpp
+++ b/include/osmium/builder/attr.hpp
@@ -46,8 +46,15 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/builder/builder.hpp>
#include <osmium/builder/osm_object_builder.hpp>
#include <osmium/memory/buffer.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/relation.hpp>
+#include <osmium/osm/timestamp.hpp>
#include <osmium/osm/types.hpp>
-#include <osmium/osm.hpp>
namespace osmium {
@@ -261,6 +268,34 @@ namespace osmium {
}; // class member_type
+ class member_type_string {
+
+ osmium::item_type m_type;
+ osmium::object_id_type m_ref;
+ std::string m_role;
+
+ public:
+
+ member_type_string(osmium::item_type type, osmium::object_id_type ref, std::string&& role) :
+ m_type(type),
+ m_ref(ref),
+ m_role(std::move(role)) {
+ }
+
+ osmium::item_type type() const noexcept {
+ return m_type;
+ }
+
+ osmium::object_id_type ref() const noexcept {
+ return m_ref;
+ }
+
+ const char* role() const noexcept {
+ return m_role.c_str();
+ }
+
+ }; // class member_type_string
+
class comment_type {
osmium::Timestamp m_date;
diff --git a/include/osmium/builder/builder.hpp b/include/osmium/builder/builder.hpp
index 869fe44..1b274ad 100644
--- a/include/osmium/builder/builder.hpp
+++ b/include/osmium/builder/builder.hpp
@@ -35,7 +35,6 @@ DEALINGS IN THE SOFTWARE.
#include <algorithm>
#include <cassert>
-#include <cstddef>
#include <cstdint>
#include <cstring>
#include <new>
@@ -101,7 +100,7 @@ namespace osmium {
*
*/
void add_padding(bool self = false) {
- auto padding = osmium::memory::align_bytes - (size() % osmium::memory::align_bytes);
+ const auto padding = osmium::memory::align_bytes - (size() % osmium::memory::align_bytes);
if (padding != osmium::memory::align_bytes) {
std::fill_n(m_buffer.reserve_space(padding), padding, 0);
if (self) {
diff --git a/include/osmium/builder/builder_helper.hpp b/include/osmium/builder/builder_helper.hpp
index e1b7c52..5e0f218 100644
--- a/include/osmium/builder/builder_helper.hpp
+++ b/include/osmium/builder/builder_helper.hpp
@@ -56,7 +56,7 @@ namespace osmium {
* Use osmium::builder::add_way_node_list() instead.
*/
OSMIUM_DEPRECATED inline const osmium::WayNodeList& build_way_node_list(osmium::memory::Buffer& buffer, const std::initializer_list<osmium::NodeRef>& nodes) {
- size_t pos = buffer.committed();
+ const size_t pos = buffer.committed();
{
osmium::builder::WayNodeListBuilder wnl_builder(buffer);
for (const auto& node_ref : nodes) {
@@ -72,7 +72,7 @@ namespace osmium {
* 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) {
- size_t pos = buffer.committed();
+ const size_t pos = buffer.committed();
{
osmium::builder::TagListBuilder tl_builder(buffer);
for (const auto& p : tags) {
@@ -88,7 +88,7 @@ namespace osmium {
* 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) {
- size_t pos = buffer.committed();
+ const size_t pos = buffer.committed();
{
osmium::builder::TagListBuilder tl_builder(buffer);
for (const auto& p : tags) {
@@ -104,7 +104,7 @@ namespace osmium {
* 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) {
- size_t pos = buffer.committed();
+ const size_t pos = buffer.committed();
{
osmium::builder::TagListBuilder tl_builder(buffer);
func(tl_builder);
diff --git a/include/osmium/builder/osm_object_builder.hpp b/include/osmium/builder/osm_object_builder.hpp
index 2ab0e7f..e7a8298 100644
--- a/include/osmium/builder/osm_object_builder.hpp
+++ b/include/osmium/builder/osm_object_builder.hpp
@@ -34,7 +34,6 @@ DEALINGS IN THE SOFTWARE.
*/
#include <cassert>
-#include <cstddef>
#include <cstring>
#include <initializer_list>
#include <limits>
@@ -44,16 +43,23 @@ DEALINGS IN THE SOFTWARE.
#include <utility>
#include <osmium/builder/builder.hpp>
-#include <osmium/osm.hpp>
#include <osmium/osm/item_type.hpp>
#include <osmium/osm/location.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/timestamp.hpp>
+#include <osmium/osm/way.hpp>
namespace osmium {
+ class Node;
+
namespace memory {
class Buffer;
} // namespace memory
diff --git a/include/osmium/diff_iterator.hpp b/include/osmium/diff_iterator.hpp
index 0814fef..fc92b36 100644
--- a/include/osmium/diff_iterator.hpp
+++ b/include/osmium/diff_iterator.hpp
@@ -34,8 +34,10 @@ DEALINGS IN THE SOFTWARE.
*/
#include <cassert>
+#include <cstddef>
#include <iterator>
#include <type_traits>
+#include <utility>
#include <osmium/osm/diff_object.hpp>
diff --git a/include/osmium/dynamic_handler.hpp b/include/osmium/dynamic_handler.hpp
index b250b57..01d1554 100644
--- a/include/osmium/dynamic_handler.hpp
+++ b/include/osmium/dynamic_handler.hpp
@@ -36,11 +36,16 @@ DEALINGS IN THE SOFTWARE.
#include <memory>
#include <utility>
-#include <osmium/fwd.hpp>
#include <osmium/handler.hpp>
namespace osmium {
+ class Node;
+ class Way;
+ class Relation;
+ class Area;
+ class Changeset;
+
namespace handler {
namespace detail {
diff --git a/include/osmium/experimental/flex_reader.hpp b/include/osmium/experimental/flex_reader.hpp
index 8059ea3..0a2a668 100644
--- a/include/osmium/experimental/flex_reader.hpp
+++ b/include/osmium/experimental/flex_reader.hpp
@@ -34,11 +34,12 @@ DEALINGS IN THE SOFTWARE.
*/
#include <string>
+#include <utility>
#include <vector>
#include <osmium/area/assembler.hpp>
#include <osmium/area/multipolygon_collector.hpp>
-#include <osmium/handler/node_locations_for_ways.hpp>
+#include <osmium/handler/node_locations_for_ways.hpp> // IWYU pragma: keep
#include <osmium/io/file.hpp>
#include <osmium/io/header.hpp>
#include <osmium/io/reader.hpp>
diff --git a/include/osmium/geom/factory.hpp b/include/osmium/geom/factory.hpp
index f03eec5..14c51df 100644
--- a/include/osmium/geom/factory.hpp
+++ b/include/osmium/geom/factory.hpp
@@ -46,6 +46,8 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/osm/location.hpp>
#include <osmium/osm/node.hpp>
#include <osmium/osm/node_ref.hpp>
+#include <osmium/osm/node_ref_list.hpp>
+#include <osmium/osm/types.hpp>
#include <osmium/osm/way.hpp>
namespace osmium {
@@ -281,7 +283,7 @@ namespace osmium {
}
if (num_points < 2) {
- throw osmium::geometry_error("need at least two points for linestring");
+ throw osmium::geometry_error{"need at least two points for linestring"};
}
return linestring_finish(num_points);
@@ -355,7 +357,7 @@ namespace osmium {
}
if (num_points < 4) {
- throw osmium::geometry_error("need at least four points for polygon");
+ throw osmium::geometry_error{"need at least four points for polygon"};
}
return polygon_finish(num_points);
@@ -401,7 +403,7 @@ namespace osmium {
// if there are no rings, this area is invalid
if (num_rings == 0) {
- throw osmium::geometry_error("area contains no rings");
+ throw osmium::geometry_error{"invalid area"};
}
m_impl.multipolygon_polygon_finish();
diff --git a/include/osmium/geom/geojson.hpp b/include/osmium/geom/geojson.hpp
index ffa9440..e9f722f 100644
--- a/include/osmium/geom/geojson.hpp
+++ b/include/osmium/geom/geojson.hpp
@@ -34,6 +34,7 @@ DEALINGS IN THE SOFTWARE.
*/
#include <cassert>
+#include <cstddef>
#include <string>
#include <utility>
diff --git a/include/osmium/geom/geos.hpp b/include/osmium/geom/geos.hpp
index 4a097e9..f406076 100644
--- a/include/osmium/geom/geos.hpp
+++ b/include/osmium/geom/geos.hpp
@@ -42,9 +42,14 @@ DEALINGS IN THE SOFTWARE.
* @attention If you include this file, you'll need to link with `libgeos`.
*/
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <iterator>
#include <memory>
#include <string>
#include <utility>
+#include <vector>
#include <geos/geom/Coordinate.h>
#include <geos/geom/CoordinateSequence.h>
@@ -65,6 +70,7 @@ DEALINGS IN THE SOFTWARE.
#ifdef _MSC_VER
# define THROW throw
#else
+# include <exception>
# define THROW std::throw_with_nested
#endif
@@ -72,8 +78,8 @@ namespace osmium {
struct geos_geometry_error : public geometry_error {
- geos_geometry_error(const char* message) :
- geometry_error(std::string("geometry creation failed in GEOS library: ") + message) {
+ explicit geos_geometry_error(const char* message) :
+ geometry_error(std::string{"geometry creation failed in GEOS library: "} + message) {
}
}; // struct geos_geometry_error
@@ -127,7 +133,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)));
- } catch (geos::util::GEOSException& e) {
+ } catch (const geos::util::GEOSException& e) {
THROW(osmium::geos_geometry_error(e.what()));
}
}
@@ -137,7 +143,7 @@ namespace osmium {
void linestring_start() {
try {
m_coordinate_sequence.reset(m_geos_factory->getCoordinateSequenceFactory()->create(static_cast<size_t>(0), 2));
- } catch (geos::util::GEOSException& e) {
+ } catch (const geos::util::GEOSException& e) {
THROW(osmium::geos_geometry_error(e.what()));
}
}
@@ -145,7 +151,7 @@ namespace osmium {
void linestring_add_location(const osmium::geom::Coordinates& xy) {
try {
m_coordinate_sequence->add(geos::geom::Coordinate(xy.x, xy.y));
- } catch (geos::util::GEOSException& e) {
+ } catch (const geos::util::GEOSException& e) {
THROW(osmium::geos_geometry_error(e.what()));
}
}
@@ -153,7 +159,7 @@ namespace osmium {
linestring_type linestring_finish(size_t /* num_points */) {
try {
return linestring_type(m_geos_factory->createLineString(m_coordinate_sequence.release()));
- } catch (geos::util::GEOSException& e) {
+ } catch (const geos::util::GEOSException& e) {
THROW(osmium::geos_geometry_error(e.what()));
}
}
@@ -177,7 +183,7 @@ namespace osmium {
});
m_polygons.emplace_back(m_geos_factory->createPolygon(m_rings[0].release(), inner_rings));
m_rings.clear();
- } catch (geos::util::GEOSException& e) {
+ } catch (const geos::util::GEOSException& e) {
THROW(osmium::geos_geometry_error(e.what()));
}
}
@@ -185,7 +191,7 @@ namespace osmium {
void multipolygon_outer_ring_start() {
try {
m_coordinate_sequence.reset(m_geos_factory->getCoordinateSequenceFactory()->create(static_cast<size_t>(0), 2));
- } catch (geos::util::GEOSException& e) {
+ } catch (const geos::util::GEOSException& e) {
THROW(osmium::geos_geometry_error(e.what()));
}
}
@@ -193,7 +199,7 @@ namespace osmium {
void multipolygon_outer_ring_finish() {
try {
m_rings.emplace_back(m_geos_factory->createLinearRing(m_coordinate_sequence.release()));
- } catch (geos::util::GEOSException& e) {
+ } catch (const geos::util::GEOSException& e) {
THROW(osmium::geos_geometry_error(e.what()));
}
}
@@ -201,7 +207,7 @@ namespace osmium {
void multipolygon_inner_ring_start() {
try {
m_coordinate_sequence.reset(m_geos_factory->getCoordinateSequenceFactory()->create(static_cast<size_t>(0), 2));
- } catch (geos::util::GEOSException& e) {
+ } catch (const geos::util::GEOSException& e) {
THROW(osmium::geos_geometry_error(e.what()));
}
}
@@ -209,7 +215,7 @@ namespace osmium {
void multipolygon_inner_ring_finish() {
try {
m_rings.emplace_back(m_geos_factory->createLinearRing(m_coordinate_sequence.release()));
- } catch (geos::util::GEOSException& e) {
+ } catch (const geos::util::GEOSException& e) {
THROW(osmium::geos_geometry_error(e.what()));
}
}
@@ -217,7 +223,7 @@ namespace osmium {
void multipolygon_add_location(const osmium::geom::Coordinates& xy) {
try {
m_coordinate_sequence->add(geos::geom::Coordinate(xy.x, xy.y));
- } catch (geos::util::GEOSException& e) {
+ } catch (const geos::util::GEOSException& e) {
THROW(osmium::geos_geometry_error(e.what()));
}
}
@@ -230,7 +236,7 @@ namespace osmium {
});
m_polygons.clear();
return multipolygon_type(m_geos_factory->createMultiPolygon(polygons));
- } catch (geos::util::GEOSException& e) {
+ } catch (const geos::util::GEOSException& e) {
THROW(osmium::geos_geometry_error(e.what()));
}
}
diff --git a/include/osmium/geom/haversine.hpp b/include/osmium/geom/haversine.hpp
index 632bc16..ef3f1ff 100644
--- a/include/osmium/geom/haversine.hpp
+++ b/include/osmium/geom/haversine.hpp
@@ -56,7 +56,7 @@ namespace osmium {
namespace haversine {
/// @brief Earth's quadratic mean radius for WGS84
- constexpr double EARTH_RADIUS_IN_METERS = 6372797.560856;
+ constexpr const double EARTH_RADIUS_IN_METERS = 6372797.560856;
/**
* Calculate distance in meters between two sets of coordinates.
diff --git a/include/osmium/geom/ogr.hpp b/include/osmium/geom/ogr.hpp
index a457d66..a91fbe5 100644
--- a/include/osmium/geom/ogr.hpp
+++ b/include/osmium/geom/ogr.hpp
@@ -77,7 +77,7 @@ namespace osmium {
public:
- OGRFactoryImpl(int /* srid */) {
+ explicit OGRFactoryImpl(int /* srid */) {
}
/* Point */
diff --git a/include/osmium/geom/projection.hpp b/include/osmium/geom/projection.hpp
index 42d95b2..eaa9b53 100644
--- a/include/osmium/geom/projection.hpp
+++ b/include/osmium/geom/projection.hpp
@@ -70,15 +70,19 @@ namespace osmium {
public:
- CRS(const std::string& crs) :
+ explicit CRS(const std::string& crs) :
m_crs(pj_init_plus(crs.c_str()), 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()));
}
}
- CRS(int epsg) :
- CRS(std::string("+init=epsg:") + std::to_string(epsg)) {
+ explicit CRS(const char* crs) :
+ CRS(std::string{crs}) {
+ }
+
+ explicit CRS(int epsg) :
+ CRS(std::string{"+init=epsg:"} + std::to_string(epsg)) {
}
/**
@@ -127,13 +131,19 @@ namespace osmium {
public:
- Projection(const std::string& proj_string) :
+ explicit Projection(const std::string& proj_string) :
+ m_epsg(-1),
+ m_proj_string(proj_string),
+ m_crs_user(proj_string) {
+ }
+
+ explicit Projection(const char* proj_string) :
m_epsg(-1),
m_proj_string(proj_string),
m_crs_user(proj_string) {
}
- Projection(int epsg) :
+ explicit Projection(int epsg) :
m_epsg(epsg),
m_proj_string(std::string("+init=epsg:") + std::to_string(epsg)),
m_crs_user(epsg) {
diff --git a/include/osmium/geom/rapid_geojson.hpp b/include/osmium/geom/rapid_geojson.hpp
index 340f0c1..7817389 100644
--- a/include/osmium/geom/rapid_geojson.hpp
+++ b/include/osmium/geom/rapid_geojson.hpp
@@ -33,6 +33,8 @@ DEALINGS IN THE SOFTWARE.
*/
+#include <cstddef>
+
#include <osmium/geom/coordinates.hpp>
#include <osmium/geom/factory.hpp>
diff --git a/include/osmium/geom/tile.hpp b/include/osmium/geom/tile.hpp
index e35c2ee..672ae54 100644
--- a/include/osmium/geom/tile.hpp
+++ b/include/osmium/geom/tile.hpp
@@ -33,9 +33,12 @@ DEALINGS IN THE SOFTWARE.
*/
+#include <cassert>
#include <cstdint>
+#include <osmium/geom/coordinates.hpp>
#include <osmium/geom/mercator_projection.hpp>
+#include <osmium/osm/location.hpp>
namespace osmium {
@@ -57,24 +60,64 @@ namespace osmium {
*/
struct Tile {
+ /// x coordinate
uint32_t x;
+
+ /// y coordinate
uint32_t y;
+
+ /// Zoom level
uint32_t z;
+ /**
+ * Create a tile with the given zoom level and x any y tile
+ * coordinates.
+ *
+ * The values are not checked for validity.
+ *
+ * @pre @code zoom <= 30 && x < 2^zoom && y < 2^zoom @endcode
+ */
explicit Tile(uint32_t zoom, uint32_t tx, uint32_t ty) noexcept : x(tx), y(ty), z(zoom) {
+ assert(zoom <= 30u);
+ assert(x < (1u << zoom));
+ assert(y < (1u << zoom));
}
+ /**
+ * Create a tile with the given zoom level that contains the given
+ * location.
+ *
+ * The values are not checked for validity.
+ *
+ * @pre @code location.valid() && zoom <= 30 @endcode
+ */
explicit Tile(uint32_t zoom, const osmium::Location& location) :
z(zoom) {
- osmium::geom::Coordinates c = lonlat_to_mercator(location);
+ assert(zoom <= 30u);
+ assert(location.valid());
+ const osmium::geom::Coordinates c = lonlat_to_mercator(location);
const int32_t n = 1 << zoom;
const double scale = detail::max_coordinate_epsg3857 * 2 / n;
x = uint32_t(detail::restrict_to_range<int32_t>(int32_t((c.x + detail::max_coordinate_epsg3857) / scale), 0, n-1));
y = uint32_t(detail::restrict_to_range<int32_t>(int32_t((detail::max_coordinate_epsg3857 - c.y) / scale), 0, n-1));
}
+ /**
+ * Check whether this tile is valid. For a tile to be valid the
+ * zoom level must be between 0 and 30 and the coordinates must
+ * each be between 0 and 2^zoom-1.
+ */
+ bool valid() const noexcept {
+ if (z > 30) {
+ return false;
+ }
+ const uint32_t max = 1 << z;
+ return x < max && y < max;
+ }
+
}; // struct Tile
+ /// Tiles are equal if all their attributes are equal.
inline bool operator==(const Tile& a, const Tile& b) {
return a.z == b.z && a.x == b.x && a.y == b.y;
}
diff --git a/include/osmium/geom/util.hpp b/include/osmium/geom/util.hpp
index fa9c8bc..b5682f9 100644
--- a/include/osmium/geom/util.hpp
+++ b/include/osmium/geom/util.hpp
@@ -44,11 +44,11 @@ namespace osmium {
*/
struct projection_error : public std::runtime_error {
- projection_error(const std::string& what) :
+ explicit projection_error(const std::string& what) :
std::runtime_error(what) {
}
- projection_error(const char* what) :
+ explicit projection_error(const char* what) :
std::runtime_error(what) {
}
diff --git a/include/osmium/geom/wkb.hpp b/include/osmium/geom/wkb.hpp
index efb07c6..d6b7798 100644
--- a/include/osmium/geom/wkb.hpp
+++ b/include/osmium/geom/wkb.hpp
@@ -33,6 +33,7 @@ DEALINGS IN THE SOFTWARE.
*/
+#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <string>
@@ -60,14 +61,13 @@ namespace osmium {
template <typename T>
inline void str_push(std::string& str, T data) {
- size_t size = str.size();
- str.resize(size + sizeof(T));
- std::copy_n(reinterpret_cast<char*>(&data), sizeof(T), &str[size]);
+ str.append(reinterpret_cast<const char*>(&data), sizeof(T));
}
inline std::string convert_to_hex(const std::string& str) {
static const char* lookup_hex = "0123456789ABCDEF";
std::string out;
+ out.reserve(str.size() * 2);
for (char c : str) {
out += lookup_hex[(c >> 4) & 0xf];
@@ -132,7 +132,7 @@ namespace osmium {
} else {
str_push(str, type);
}
- size_t offset = str.size();
+ const size_t offset = str.size();
if (add_length) {
str_push(str, static_cast<uint32_t>(0));
}
diff --git a/include/osmium/geom/wkt.hpp b/include/osmium/geom/wkt.hpp
index 6113674..e360f71 100644
--- a/include/osmium/geom/wkt.hpp
+++ b/include/osmium/geom/wkt.hpp
@@ -59,9 +59,6 @@ namespace osmium {
int m_precision;
wkt_type m_wkt_type;
- void init_srid() {
- }
-
public:
using point_type = std::string;
diff --git a/include/osmium/handler.hpp b/include/osmium/handler.hpp
index 3620d65..1263910 100644
--- a/include/osmium/handler.hpp
+++ b/include/osmium/handler.hpp
@@ -33,56 +33,82 @@ DEALINGS IN THE SOFTWARE.
*/
-#include <osmium/fwd.hpp>
-
namespace osmium {
+ class Area;
+ class Changeset;
+ class ChangesetDiscussion;
+ class InnerRing;
+ class Node;
+ class OSMObject;
+ class OuterRing;
+ class Relation;
+ class RelationMemberList;
+ class TagList;
+ class Way;
+ class WayNodeList;
+
/**
* @brief Osmium handlers provide callbacks for OSM objects
*/
namespace handler {
+ /**
+ * Handler base class. Never used directly. Derive your own class from
+ * this class and "overwrite" the functions. Your functions must be
+ * named the same, but don't have to be const or noexcept or take
+ * their argument as const.
+ *
+ * Usually you will overwrite the node(), way(), and relation()
+ * functions. If your program supports multipolygons, also the area()
+ * function. You can also use the osm_object() function which is
+ * called for all OSM objects (nodes, ways, relations, and areas)
+ * right before each of their specific callbacks is called.
+ *
+ * If you are working with changesets, implement the changeset()
+ * function.
+ */
class Handler {
public:
- void osm_object(const osmium::OSMObject&) const {
+ void osm_object(const osmium::OSMObject&) const noexcept {
}
- void node(const osmium::Node&) const {
+ void node(const osmium::Node&) const noexcept {
}
- void way(const osmium::Way&) const {
+ void way(const osmium::Way&) const noexcept {
}
- void relation(const osmium::Relation&) const {
+ void relation(const osmium::Relation&) const noexcept {
}
- void area(const osmium::Area&) const {
+ void area(const osmium::Area&) const noexcept {
}
- void changeset(const osmium::Changeset&) const {
+ void changeset(const osmium::Changeset&) const noexcept {
}
- void tag_list(const osmium::TagList&) const {
+ void tag_list(const osmium::TagList&) const noexcept {
}
- void way_node_list(const osmium::WayNodeList&) const {
+ void way_node_list(const osmium::WayNodeList&) const noexcept {
}
- void relation_member_list(const osmium::RelationMemberList&) const {
+ void relation_member_list(const osmium::RelationMemberList&) const noexcept {
}
- void outer_ring(const osmium::OuterRing&) const {
+ void outer_ring(const osmium::OuterRing&) const noexcept {
}
- void inner_ring(const osmium::InnerRing&) const {
+ void inner_ring(const osmium::InnerRing&) const noexcept {
}
- void changeset_discussion(const osmium::ChangesetDiscussion&) const {
+ void changeset_discussion(const osmium::ChangesetDiscussion&) const noexcept {
}
- void flush() const {
+ void flush() const noexcept {
}
}; // class Handler
diff --git a/include/osmium/handler/check_order.hpp b/include/osmium/handler/check_order.hpp
index 143794b..a9b6834 100644
--- a/include/osmium/handler/check_order.hpp
+++ b/include/osmium/handler/check_order.hpp
@@ -51,11 +51,11 @@ namespace osmium {
*/
struct out_of_order_error : public std::runtime_error {
- out_of_order_error(const std::string& what) :
+ explicit out_of_order_error(const std::string& what) :
std::runtime_error(what) {
}
- out_of_order_error(const char* what) :
+ explicit out_of_order_error(const char* what) :
std::runtime_error(what) {
}
diff --git a/include/osmium/handler/node_locations_for_ways.hpp b/include/osmium/handler/node_locations_for_ways.hpp
index e836397..a490f9e 100644
--- a/include/osmium/handler/node_locations_for_ways.hpp
+++ b/include/osmium/handler/node_locations_for_ways.hpp
@@ -160,7 +160,7 @@ namespace osmium {
if (!node_ref.location()) {
error = true;
}
- } catch (osmium::not_found&) {
+ } catch (const osmium::not_found&) {
error = true;
}
}
diff --git a/include/osmium/index/detail/create_map_with_fd.hpp b/include/osmium/index/detail/create_map_with_fd.hpp
index 640b3c6..72b326a 100644
--- a/include/osmium/index/detail/create_map_with_fd.hpp
+++ b/include/osmium/index/detail/create_map_with_fd.hpp
@@ -54,9 +54,9 @@ namespace osmium {
}
assert(config.size() > 1);
const std::string& filename = config[1];
- int fd = ::open(filename.c_str(), O_CREAT | O_RDWR, 0644);
+ const int fd = ::open(filename.c_str(), O_CREAT | O_RDWR, 0644);
if (fd == -1) {
- throw std::runtime_error(std::string("can't open file '") + filename + "': " + strerror(errno));
+ throw std::runtime_error(std::string("can't open file '") + filename + "': " + std::strerror(errno));
}
return new T(fd);
}
diff --git a/include/osmium/index/detail/mmap_vector_file.hpp b/include/osmium/index/detail/mmap_vector_file.hpp
index e077c60..9e72f5a 100644
--- a/include/osmium/index/detail/mmap_vector_file.hpp
+++ b/include/osmium/index/detail/mmap_vector_file.hpp
@@ -34,6 +34,8 @@ DEALINGS IN THE SOFTWARE.
*/
#include <algorithm>
+#include <cstddef>
+#include <stdexcept>
#include <string>
#include <osmium/index/detail/mmap_vector_base.hpp>
@@ -52,7 +54,7 @@ namespace osmium {
class mmap_vector_file : public mmap_vector_base<T> {
size_t filesize(int fd) const {
- size_t size = osmium::util::file_size(fd);
+ const size_t 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)) + ").");
diff --git a/include/osmium/index/detail/vector_map.hpp b/include/osmium/index/detail/vector_map.hpp
index 390a402..ac87c2f 100644
--- a/include/osmium/index/detail/vector_map.hpp
+++ b/include/osmium/index/detail/vector_map.hpp
@@ -88,7 +88,7 @@ namespace osmium {
not_found_error(id);
}
return value;
- } catch (std::out_of_range&) {
+ } catch (const std::out_of_range&) {
not_found_error(id);
}
}
diff --git a/include/osmium/index/detail/vector_multimap.hpp b/include/osmium/index/detail/vector_multimap.hpp
index af2ec53..f859f5b 100644
--- a/include/osmium/index/detail/vector_multimap.hpp
+++ b/include/osmium/index/detail/vector_multimap.hpp
@@ -127,7 +127,7 @@ namespace osmium {
}
void remove(const TId id, const TValue value) {
- auto r = get_all(id);
+ const auto r = get_all(id);
for (auto it = r.first; it != r.second; ++it) {
if (it->second == value) {
it->second = 0;
diff --git a/include/osmium/index/index.hpp b/include/osmium/index/index.hpp
index 37d022d..c3deead 100644
--- a/include/osmium/index/index.hpp
+++ b/include/osmium/index/index.hpp
@@ -49,11 +49,11 @@ namespace osmium {
*/
struct not_found : public std::runtime_error {
- not_found(const std::string& what) :
+ explicit not_found(const std::string& what) :
std::runtime_error(what) {
}
- not_found(const char* what) :
+ explicit not_found(const char* what) :
std::runtime_error(what) {
}
diff --git a/include/osmium/index/map.hpp b/include/osmium/index/map.hpp
index c8f7598..1d2d5aa 100644
--- a/include/osmium/index/map.hpp
+++ b/include/osmium/index/map.hpp
@@ -207,7 +207,7 @@ namespace osmium {
}
bool has_map_type(const std::string& map_type_name) const {
- return m_callbacks.count(map_type_name);
+ return m_callbacks.count(map_type_name) != 0;
}
std::vector<std::string> map_types() const {
diff --git a/include/osmium/index/map/sparse_mem_map.hpp b/include/osmium/index/map/sparse_mem_map.hpp
index 95f570b..1e3c58c 100644
--- a/include/osmium/index/map/sparse_mem_map.hpp
+++ b/include/osmium/index/map/sparse_mem_map.hpp
@@ -37,7 +37,6 @@ DEALINGS IN THE SOFTWARE.
#include <cstddef>
#include <iterator>
#include <map>
-#include <stdexcept>
#include <vector>
#include <osmium/index/map.hpp>
diff --git a/include/osmium/io/any_input.hpp b/include/osmium/io/any_input.hpp
index dd84451..e4617e8 100644
--- a/include/osmium/io/any_input.hpp
+++ b/include/osmium/io/any_input.hpp
@@ -45,8 +45,9 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/io/any_compression.hpp> // IWYU pragma: export
+#include <osmium/io/o5m_input.hpp> // IWYU pragma: export
+#include <osmium/io/opl_input.hpp> // IWYU pragma: export
#include <osmium/io/pbf_input.hpp> // IWYU pragma: export
#include <osmium/io/xml_input.hpp> // IWYU pragma: export
-#include <osmium/io/o5m_input.hpp> // IWYU pragma: export
#endif // OSMIUM_IO_ANY_INPUT_HPP
diff --git a/include/osmium/io/bzip2_compression.hpp b/include/osmium/io/bzip2_compression.hpp
index e5cad0b..63b4cad 100644
--- a/include/osmium/io/bzip2_compression.hpp
+++ b/include/osmium/io/bzip2_compression.hpp
@@ -43,10 +43,9 @@ DEALINGS IN THE SOFTWARE.
*/
#include <cerrno>
-#include <cstddef>
#include <cstdio>
-#include <stdexcept>
#include <string>
+#include <system_error>
#include <bzlib.h>
@@ -55,6 +54,7 @@ DEALINGS IN THE SOFTWARE.
#endif
#include <osmium/io/compression.hpp>
+#include <osmium/io/detail/read_write.hpp>
#include <osmium/io/error.hpp>
#include <osmium/io/file_compression.hpp>
#include <osmium/io/writer_options.hpp>
@@ -109,7 +109,7 @@ namespace osmium {
explicit Bzip2Compressor(int fd, fsync sync) :
Compressor(sync),
- m_file(fdopen(dup(fd), "wb")),
+ m_file(fdopen(::dup(fd), "wb")),
m_bzerror(BZ_OK),
m_bzfile(::BZ2_bzWriteOpen(&m_bzerror, m_file, 6, 0, 0)) {
if (!m_bzfile) {
@@ -165,7 +165,7 @@ namespace osmium {
explicit Bzip2Decompressor(int fd) :
Decompressor(),
- m_file(fdopen(dup(fd), "rb")),
+ m_file(fdopen(::dup(fd), "rb")),
m_bzerror(BZ_OK),
m_bzfile(::BZ2_bzReadOpen(&m_bzerror, m_file, 0, 0, nullptr, 0)) {
if (!m_bzfile) {
@@ -215,6 +215,8 @@ namespace osmium {
buffer.resize(static_cast<std::string::size_type>(nread));
}
+ set_offset(size_t(ftell(m_file)));
+
return buffer;
}
diff --git a/include/osmium/io/compression.hpp b/include/osmium/io/compression.hpp
index fc14e26..e7f93bd 100644
--- a/include/osmium/io/compression.hpp
+++ b/include/osmium/io/compression.hpp
@@ -33,11 +33,12 @@ DEALINGS IN THE SOFTWARE.
*/
+#include <atomic>
#include <cerrno>
+#include <cstddef>
#include <functional>
#include <map>
#include <memory>
-#include <stdexcept>
#include <string>
#include <system_error>
#include <tuple>
@@ -54,6 +55,7 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/io/file_compression.hpp>
#include <osmium/io/writer_options.hpp>
#include <osmium/util/compatibility.hpp>
+#include <osmium/util/file.hpp>
namespace osmium {
@@ -86,6 +88,9 @@ namespace osmium {
class Decompressor {
+ std::atomic<size_t> m_file_size {0};
+ std::atomic<size_t> m_offset {0};
+
public:
static constexpr unsigned int input_buffer_size = 1024 * 1024;
@@ -105,6 +110,22 @@ namespace osmium {
virtual void close() = 0;
+ size_t file_size() const noexcept {
+ return m_file_size;
+ }
+
+ void set_file_size(size_t size) noexcept {
+ m_file_size = size;
+ }
+
+ size_t offset() const noexcept {
+ return m_offset;
+ }
+
+ void set_offset(size_t offset) noexcept {
+ m_offset = offset;
+ }
+
}; // class Decompressor
/**
@@ -182,7 +203,9 @@ namespace osmium {
auto it = m_callbacks.find(compression);
if (it != m_callbacks.end()) {
- return std::unique_ptr<osmium::io::Decompressor>(std::get<1>(it->second)(fd));
+ auto p = std::unique_ptr<osmium::io::Decompressor>(std::get<1>(it->second)(fd));
+ p->set_file_size(osmium::util::file_size(fd));
+ return p;
}
error(compression);
@@ -241,6 +264,7 @@ namespace osmium {
int m_fd;
const char *m_buffer;
size_t m_buffer_size;
+ size_t m_offset = 0;
public:
@@ -284,6 +308,9 @@ namespace osmium {
buffer.resize(std::string::size_type(nread));
}
+ m_offset += buffer.size();
+ set_offset(m_offset);
+
return buffer;
}
diff --git a/include/osmium/io/detail/debug_output_format.hpp b/include/osmium/io/detail/debug_output_format.hpp
index 7ae0807..dc5323a 100644
--- a/include/osmium/io/detail/debug_output_format.hpp
+++ b/include/osmium/io/detail/debug_output_format.hpp
@@ -34,32 +34,35 @@ DEALINGS IN THE SOFTWARE.
*/
#include <cinttypes>
-#include <cstddef>
-#include <cstdint>
-#include <cstdio>
-#include <future>
+#include <cmath>
+#include <cstring>
#include <iterator>
#include <memory>
#include <string>
-#include <thread>
#include <utility>
#include <boost/crc.hpp>
#include <osmium/io/detail/output_format.hpp>
+#include <osmium/io/detail/queue_util.hpp>
+#include <osmium/io/detail/string_util.hpp>
+#include <osmium/io/file.hpp>
#include <osmium/io/file_format.hpp>
+#include <osmium/io/header.hpp>
#include <osmium/memory/buffer.hpp>
-#include <osmium/memory/collection.hpp>
+#include <osmium/memory/item_iterator.hpp>
#include <osmium/osm/box.hpp>
#include <osmium/osm/changeset.hpp>
#include <osmium/osm/crc.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/relation.hpp>
#include <osmium/osm/tag.hpp>
#include <osmium/osm/timestamp.hpp>
+#include <osmium/osm/types.hpp>
#include <osmium/osm/way.hpp>
#include <osmium/thread/pool.hpp>
#include <osmium/util/minmax.hpp>
@@ -69,8 +72,6 @@ namespace osmium {
namespace io {
- class File;
-
namespace detail {
constexpr const char* color_bold = "\x1b[1m";
@@ -83,6 +84,10 @@ namespace osmium {
constexpr const char* color_magenta = "\x1b[35m";
constexpr const char* color_cyan = "\x1b[36m";
constexpr const char* color_white = "\x1b[37m";
+
+ constexpr const char* color_backg_red = "\x1b[41m";
+ constexpr const char* color_backg_green = "\x1b[42m";
+
constexpr const char* color_reset = "\x1b[0m";
struct debug_output_options {
@@ -96,6 +101,8 @@ namespace osmium {
/// Add CRC32 checksum to each object?
bool add_crc32;
+ /// Write in form of a diff file?
+ bool format_as_diff;
};
/**
@@ -108,6 +115,8 @@ namespace osmium {
const char* m_utf8_prefix = "";
const char* m_utf8_suffix = "";
+ char m_diff_char = '\0';
+
void append_encoded_string(const char* data) {
append_debug_encoded_string(*m_out, data, m_utf8_prefix, m_utf8_suffix);
}
@@ -123,6 +132,30 @@ namespace osmium {
}
}
+ void write_diff() {
+ if (!m_diff_char) {
+ return;
+ }
+ if (m_options.use_color) {
+ if (m_diff_char == '-') {
+ *m_out += color_backg_red;
+ *m_out += color_white;
+ *m_out += color_bold;
+ *m_out += '-';
+ *m_out += color_reset;
+ return;
+ } else if (m_diff_char == '+') {
+ *m_out += color_backg_green;
+ *m_out += color_white;
+ *m_out += color_bold;
+ *m_out += '+';
+ *m_out += color_reset;
+ return;
+ }
+ }
+ *m_out += m_diff_char;
+ }
+
void write_string(const char* string) {
*m_out += '"';
write_color(color_blue);
@@ -132,6 +165,7 @@ namespace osmium {
}
void write_object_type(const char* object_type, bool visible = true) {
+ write_diff();
if (visible) {
write_color(color_bold);
} else {
@@ -143,6 +177,7 @@ namespace osmium {
}
void write_fieldname(const char* name) {
+ write_diff();
*m_out += " ";
write_color(color_cyan);
*m_out += name;
@@ -208,28 +243,30 @@ namespace osmium {
}
void write_tags(const osmium::TagList& tags, const char* padding="") {
- if (!tags.empty()) {
- write_fieldname("tags");
- *m_out += padding;
- *m_out += " ";
- output_int(tags.size());
- *m_out += '\n';
+ if (tags.empty()) {
+ return;
+ }
+ write_fieldname("tags");
+ *m_out += padding;
+ *m_out += " ";
+ output_int(tags.size());
+ *m_out += '\n';
- osmium::max_op<size_t> max;
- for (const auto& tag : tags) {
- max.update(std::strlen(tag.key()));
- }
- for (const auto& tag : tags) {
- *m_out += " ";
- write_string(tag.key());
- auto spacing = max() - std::strlen(tag.key());
- while (spacing--) {
- *m_out += " ";
- }
- *m_out += " = ";
- write_string(tag.value());
- *m_out += '\n';
+ osmium::max_op<size_t> max;
+ for (const auto& tag : tags) {
+ max.update(std::strlen(tag.key()));
+ }
+ for (const auto& tag : tags) {
+ write_diff();
+ *m_out += " ";
+ write_string(tag.key());
+ auto spacing = max() - std::strlen(tag.key());
+ while (spacing--) {
+ *m_out += " ";
}
+ *m_out += " = ";
+ write_string(tag.value());
+ *m_out += '\n';
}
}
@@ -303,6 +340,8 @@ namespace osmium {
}
void node(const osmium::Node& node) {
+ m_diff_char = m_options.format_as_diff ? node.diff_as_char() : '\0';
+
write_object_type("node", node.visible());
write_meta(node);
@@ -320,6 +359,8 @@ namespace osmium {
}
void way(const osmium::Way& way) {
+ m_diff_char = m_options.format_as_diff ? way.diff_as_char() : '\0';
+
write_object_type("way", way.visible());
write_meta(way);
write_tags(way.tags());
@@ -338,9 +379,10 @@ namespace osmium {
*m_out += " (open)\n";
}
- int width = int(log10(way.nodes().size())) + 1;
+ const int width = int(std::log10(way.nodes().size())) + 1;
int n = 0;
for (const auto& node_ref : way.nodes()) {
+ write_diff();
write_counter(width, n++);
output_formatted("%10" PRId64, node_ref.ref());
if (node_ref.location().valid()) {
@@ -360,6 +402,9 @@ namespace osmium {
void relation(const osmium::Relation& relation) {
static const char* short_typename[] = { "node", "way ", "rel " };
+
+ m_diff_char = m_options.format_as_diff ? relation.diff_as_char() : '\0';
+
write_object_type("relation", relation.visible());
write_meta(relation);
write_tags(relation.tags());
@@ -369,9 +414,10 @@ namespace osmium {
output_int(relation.members().size());
*m_out += '\n';
- int width = int(log10(relation.members().size())) + 1;
+ const int width = int(std::log10(relation.members().size())) + 1;
int n = 0;
for (const auto& member : relation.members()) {
+ write_diff();
write_counter(width, n++);
*m_out += short_typename[item_type_to_nwr_index(member.type())];
output_formatted(" %10" PRId64 " ", member.ref());
@@ -426,7 +472,7 @@ namespace osmium {
output_int(changeset.num_comments());
*m_out += '\n';
- int width = int(log10(changeset.num_comments())) + 1;
+ const int width = int(std::log10(changeset.num_comments())) + 1;
int n = 0;
for (const auto& comment : changeset.discussion()) {
write_counter(width, n++);
@@ -477,9 +523,10 @@ namespace osmium {
DebugOutputFormat(const osmium::io::File& file, future_string_queue_type& output_queue) :
OutputFormat(output_queue),
m_options() {
- m_options.add_metadata = file.is_not_false("add_metadata");
- m_options.use_color = file.is_true("color");
- m_options.add_crc32 = file.is_true("add_crc32");
+ m_options.add_metadata = file.is_not_false("add_metadata");
+ m_options.use_color = file.is_true("color");
+ m_options.add_crc32 = file.is_true("add_crc32");
+ m_options.format_as_diff = file.is_true("diff");
}
DebugOutputFormat(const DebugOutputFormat&) = delete;
@@ -488,6 +535,10 @@ namespace osmium {
~DebugOutputFormat() noexcept final = default;
void write_header(const osmium::io::Header& header) final {
+ if (m_options.format_as_diff) {
+ return;
+ }
+
std::string out;
if (m_options.use_color) {
diff --git a/include/osmium/io/detail/input_format.hpp b/include/osmium/io/detail/input_format.hpp
index e04e57f..98081e3 100644
--- a/include/osmium/io/detail/input_format.hpp
+++ b/include/osmium/io/detail/input_format.hpp
@@ -38,11 +38,11 @@ DEALINGS IN THE SOFTWARE.
#include <future>
#include <map>
#include <memory>
-#include <stdexcept>
#include <string>
#include <utility>
#include <osmium/io/detail/queue_util.hpp>
+#include <osmium/io/error.hpp>
#include <osmium/io/file.hpp>
#include <osmium/io/file_format.hpp>
#include <osmium/io/header.hpp>
diff --git a/include/osmium/io/detail/o5m_input_format.hpp b/include/osmium/io/detail/o5m_input_format.hpp
index 7293cfa..d642879 100644
--- a/include/osmium/io/detail/o5m_input_format.hpp
+++ b/include/osmium/io/detail/o5m_input_format.hpp
@@ -42,9 +42,9 @@ DEALINGS IN THE SOFTWARE.
#include <string>
#include <utility>
+#include <protozero/exception.hpp>
#include <protozero/varint.hpp>
-#include <osmium/builder/builder.hpp>
#include <osmium/builder/osm_object_builder.hpp>
#include <osmium/io/detail/input_format.hpp>
#include <osmium/io/detail/queue_util.hpp>
@@ -52,19 +52,26 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/io/file_format.hpp>
#include <osmium/io/header.hpp>
#include <osmium/memory/buffer.hpp>
-#include <osmium/osm.hpp>
#include <osmium/osm/box.hpp>
#include <osmium/osm/entity_bits.hpp>
#include <osmium/osm/item_type.hpp>
#include <osmium/osm/location.hpp>
+#include <osmium/osm/node.hpp>
#include <osmium/osm/object.hpp>
+#include <osmium/osm/relation.hpp>
+#include <osmium/osm/timestamp.hpp>
#include <osmium/osm/types.hpp>
+#include <osmium/osm/way.hpp>
#include <osmium/thread/util.hpp>
#include <osmium/util/cast.hpp>
#include <osmium/util/delta.hpp>
namespace osmium {
+ namespace builder {
+ class Builder;
+ } // namespace builder
+
/**
* Exception thrown when the o5m deocder failed. The exception contains
* (if available) information about the place where the error happened
@@ -529,7 +536,7 @@ namespace osmium {
uint64_t length = 0;
try {
length = protozero::decode_varint(&m_data, m_end);
- } catch (protozero::end_of_buffer_exception&) {
+ } catch (const protozero::end_of_buffer_exception&) {
throw o5m_error("premature end of file");
}
diff --git a/include/osmium/io/detail/opl_input_format.hpp b/include/osmium/io/detail/opl_input_format.hpp
new file mode 100644
index 0000000..15a31f3
--- /dev/null
+++ b/include/osmium/io/detail/opl_input_format.hpp
@@ -0,0 +1,156 @@
+#ifndef OSMIUM_IO_DETAIL_OPL_INPUT_FORMAT_HPP
+#define OSMIUM_IO_DETAIL_OPL_INPUT_FORMAT_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2016 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstdlib>
+#include <future>
+#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 {
+
+ namespace io {
+
+ namespace detail {
+
+ 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() {
+ if (m_buffer.committed() > 800*1024) {
+ osmium::memory::Buffer buffer{1024*1024};
+ using std::swap;
+ swap(m_buffer, buffer);
+ send_to_output_queue(std::move(buffer));
+
+ }
+ }
+
+ 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::osm_entity_bits::type read_types) :
+ Parser(input_queue, output_queue, header_promise, read_types) {
+ set_header_value(osmium::io::Header{});
+ }
+
+ ~OPLParser() noexcept final = default;
+
+ 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 (m_buffer.committed() > 0) {
+ send_to_output_queue(std::move(m_buffer));
+ }
+ }
+
+ }; // class OPLParser
+
+ // we want the register_parser() function to run, setting
+ // 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::osm_entity_bits::type read_which_entities) {
+ return std::unique_ptr<Parser>(new OPLParser(input_queue, output_queue, header_promise, read_which_entities));
+ });
+
+ // dummy function to silence the unused variable warning from above
+ inline bool get_registered_opl_parser() noexcept {
+ return registered_opl_parser;
+ }
+
+ } // namespace detail
+
+ } // namespace io
+
+} // namespace osmium
+
+
+#endif // OSMIUM_IO_DETAIL_OPL_INPUT_FORMAT_HPP
diff --git a/include/osmium/io/detail/opl_output_format.hpp b/include/osmium/io/detail/opl_output_format.hpp
index 56c0182..acdfe29 100644
--- a/include/osmium/io/detail/opl_output_format.hpp
+++ b/include/osmium/io/detail/opl_output_format.hpp
@@ -33,26 +33,26 @@ DEALINGS IN THE SOFTWARE.
*/
-#include <cinttypes>
-#include <cstddef>
#include <cstdint>
-#include <cstdio>
-#include <future>
#include <iterator>
#include <memory>
#include <string>
-#include <thread>
#include <utility>
#include <osmium/io/detail/output_format.hpp>
+#include <osmium/io/detail/queue_util.hpp>
+#include <osmium/io/detail/string_util.hpp>
+#include <osmium/io/file.hpp>
#include <osmium/io/file_format.hpp>
#include <osmium/memory/buffer.hpp>
#include <osmium/memory/collection.hpp>
+#include <osmium/memory/item_iterator.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/relation.hpp>
#include <osmium/osm/tag.hpp>
@@ -65,8 +65,6 @@ namespace osmium {
namespace io {
- class File;
-
namespace detail {
struct opl_output_options {
@@ -77,6 +75,9 @@ namespace osmium {
/// Should node locations be added to ways?
bool locations_on_ways;
+ /// Write in form of a diff file?
+ bool format_as_diff;
+
};
/**
@@ -152,6 +153,12 @@ namespace osmium {
}
}
+ void write_diff(const osmium::OSMObject& object) {
+ if (m_options.format_as_diff) {
+ *m_out += object.diff_as_char();
+ }
+ }
+
public:
OPLOutputBlock(osmium::memory::Buffer&& buffer, const opl_output_options& options) :
@@ -178,6 +185,7 @@ namespace osmium {
}
void node(const osmium::Node& node) {
+ write_diff(node);
*m_out += 'n';
write_meta(node);
write_location(node.location(), 'x', 'y');
@@ -195,6 +203,7 @@ namespace osmium {
}
void way(const osmium::Way& way) {
+ write_diff(way);
*m_out += 'w';
write_meta(way);
@@ -228,6 +237,7 @@ namespace osmium {
}
void relation(const osmium::Relation& relation) {
+ write_diff(relation);
*m_out += 'r';
write_meta(relation);
@@ -278,6 +288,7 @@ namespace osmium {
m_options() {
m_options.add_metadata = file.is_not_false("add_metadata");
m_options.locations_on_ways = file.is_true("locations_on_ways");
+ m_options.format_as_diff = file.is_true("diff");
}
OPLOutputFormat(const OPLOutputFormat&) = delete;
diff --git a/include/osmium/io/detail/opl_parser_functions.hpp b/include/osmium/io/detail/opl_parser_functions.hpp
new file mode 100644
index 0000000..97c5927
--- /dev/null
+++ b/include/osmium/io/detail/opl_parser_functions.hpp
@@ -0,0 +1,747 @@
+#ifndef OSMIUM_IO_DETAIL_OPL_PARSER_FUNCTIONS_HPP
+#define OSMIUM_IO_DETAIL_OPL_PARSER_FUNCTIONS_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2016 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <cstdint>
+#include <cstdlib>
+#include <iterator>
+#include <limits>
+#include <stdexcept>
+#include <string>
+
+#include <utf8.h>
+
+#include <osmium/builder/osm_object_builder.hpp>
+#include <osmium/io/error.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/osm/box.hpp>
+#include <osmium/osm/changeset.hpp>
+#include <osmium/osm/entity_bits.hpp>
+#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/location.hpp>
+#include <osmium/osm/node.hpp>
+#include <osmium/osm/relation.hpp>
+#include <osmium/osm/timestamp.hpp>
+#include <osmium/osm/types.hpp>
+#include <osmium/osm/way.hpp>
+
+namespace osmium {
+
+ namespace builder {
+ class Builder;
+ } // namespace builder
+
+ /**
+ * Exception thrown when there was a problem with parsing the OPL format
+ * of a file.
+ */
+ struct opl_error : public io_error {
+
+ uint64_t line = 0;
+ uint64_t column = 0;
+ const char* data;
+ std::string msg;
+
+ explicit opl_error(const std::string& what, const char* d = nullptr) :
+ io_error(std::string("OPL error: ") + what),
+ data(d),
+ msg("OPL error: ") {
+ msg.append(what);
+ }
+
+ explicit opl_error(const char* what, const char* d = nullptr) :
+ io_error(std::string("OPL error: ") + what),
+ data(d),
+ msg("OPL error: ") {
+ msg.append(what);
+ }
+
+ void set_pos(uint64_t l, uint64_t col) {
+ line = l;
+ column = col;
+ msg.append(" on line ");
+ msg.append(std::to_string(line));
+ msg.append(" column ");
+ msg.append(std::to_string(column));
+ }
+
+ const char* what() const noexcept override {
+ return msg.c_str();
+ }
+
+ }; // struct opl_error
+
+ namespace io {
+
+ namespace detail {
+
+ /**
+ * Consume consecutive space and tab characters. There must be
+ * at least one.
+ */
+ inline void opl_parse_space(const char** s) {
+ if (**s != ' ' && **s != '\t') {
+ throw opl_error{"expected space or tab character", *s};
+ }
+ do {
+ ++*s;
+ } while (**s == ' ' || **s == '\t');
+ }
+
+ /**
+ * Check whether s points to something else than the end of the
+ * string or a space or tab.
+ */
+ inline bool opl_non_empty(const char *s) {
+ return *s != '\0' && *s != ' ' && *s != '\t';
+ }
+
+ /**
+ * Skip to the next space or tab character or the end of the
+ * string.
+ */
+ inline const char* opl_skip_section(const char** s) noexcept {
+ while (opl_non_empty(*s)) {
+ ++*s;
+ }
+ return *s;
+ }
+
+ /**
+ * Parse OPL-escaped strings with hex code with a '%' at the end.
+ * Appends resulting unicode character to the result string.
+ *
+ * Returns a pointer to next character that needs to be consumed.
+ */
+ inline void opl_parse_escaped(const char** data, std::string& result) {
+ const char* s = *data;
+ uint32_t value = 0;
+ const int max_length = sizeof(value) * 2 /* hex chars per byte */;
+ int length = 0;
+ while (++length <= max_length) {
+ if (*s == '\0') {
+ throw opl_error{"eol", s};
+ }
+ if (*s == '%') {
+ ++s;
+ utf8::utf32to8(&value, &value + 1, std::back_inserter(result));
+ *data = s;
+ return;
+ }
+ value <<= 4;
+ if (*s >= '0' && *s <= '9') {
+ value += *s - '0';
+ } else if (*s >= 'a' && *s <= 'f') {
+ value += *s - 'a' + 10;
+ } else if (*s >= 'A' && *s <= 'F') {
+ value += *s - 'A' + 10;
+ } else {
+ throw opl_error{"not a hex char", s};
+ }
+ ++s;
+ }
+ throw opl_error{"hex escape too long", s};
+ }
+
+ /**
+ * Parse a string up to end of string or next space, tab, comma, or
+ * equal sign.
+ *
+ * Appends characters to the result string.
+ *
+ * Returns a pointer to next character that needs to be consumed.
+ */
+ inline void opl_parse_string(const char** data, std::string& result) {
+ const char* s = *data;
+ while (true) {
+ if (*s == '\0' || *s == ' ' || *s == '\t' || *s == ',' || *s == '=') {
+ break;
+ } else if (*s == '%') {
+ ++s;
+ opl_parse_escaped(&s, result);
+ } else {
+ result += *s;
+ ++s;
+ }
+ }
+ *data = s;
+ }
+
+ // Arbitrary limit how long integers can get
+ constexpr const int max_int_len = 16;
+
+ template <typename T>
+ inline T opl_parse_int(const char** s) {
+ if (**s == '\0') {
+ throw opl_error{"expected integer", *s};
+ }
+ const bool negative = (**s == '-');
+ if (negative) {
+ ++*s;
+ }
+
+ int64_t value = 0;
+
+ int n = max_int_len;
+ while (**s >= '0' && **s <= '9') {
+ if (--n == 0) {
+ throw opl_error{"integer too long", *s};
+ }
+ value *= 10;
+ value += **s - '0';
+ ++*s;
+ }
+
+ if (n == max_int_len) {
+ throw opl_error{"expected integer", *s};
+ }
+
+ if (negative) {
+ value = -value;
+ if (value < std::numeric_limits<T>::min()) {
+ throw opl_error{"integer too long", *s};
+ }
+ } else {
+ if (value > std::numeric_limits<T>::max()) {
+ throw opl_error{"integer too long", *s};
+ }
+ }
+
+ return T(value);
+ }
+
+ inline osmium::object_id_type opl_parse_id(const char** s) {
+ return opl_parse_int<osmium::object_id_type>(s);
+ }
+
+ inline osmium::changeset_id_type opl_parse_changeset_id(const char** s) {
+ return opl_parse_int<osmium::changeset_id_type>(s);
+ }
+
+ inline osmium::object_version_type opl_parse_version(const char** s) {
+ return opl_parse_int<osmium::object_version_type>(s);
+ }
+
+ inline bool opl_parse_visible(const char** data) {
+ if (**data == 'V') {
+ ++*data;
+ return true;
+ }
+ if (**data == 'D') {
+ ++*data;
+ return false;
+ }
+ throw opl_error{"invalid visible flag", *data};
+ }
+
+ inline osmium::user_id_type opl_parse_uid(const char** s) {
+ return opl_parse_int<osmium::user_id_type>(s);
+ }
+
+ inline osmium::Timestamp opl_parse_timestamp(const char** s) {
+ try {
+ if (**s == '\0' || **s == ' ' || **s == '\t') {
+ return osmium::Timestamp{};
+ }
+ osmium::Timestamp timestamp{*s};
+ *s += 20;
+ return timestamp;
+ } catch (const std::invalid_argument&) {
+ throw opl_error{"can not parse timestamp", *s};
+ }
+ }
+
+ /**
+ * Check if data points to given character and consume it.
+ * Throw error otherwise.
+ */
+ inline void opl_parse_char(const char** data, char c) {
+ if (**data == c) {
+ ++*data;
+ return;
+ }
+ std::string msg = "expected '";
+ msg += c;
+ msg += "'";
+ throw opl_error{msg, *data};
+ }
+
+ /**
+ * Parse a list of tags in the format 'key=value,key=value,...'
+ *
+ * Tags will be added to the buffer using a TagListBuilder.
+ */
+ inline void opl_parse_tags(const char* s, osmium::memory::Buffer& buffer, osmium::builder::Builder* parent_builder = nullptr) {
+ osmium::builder::TagListBuilder builder{buffer, parent_builder};
+ std::string key;
+ std::string value;
+ while (true) {
+ opl_parse_string(&s, key);
+ opl_parse_char(&s, '=');
+ opl_parse_string(&s, value);
+ builder.add_tag(key, value);
+ if (*s == ' ' || *s == '\t' || *s == '\0') {
+ break;
+ }
+ opl_parse_char(&s, ',');
+ key.clear();
+ value.clear();
+ }
+ }
+
+ /**
+ * Parse a number of nodes in the format "nID,nID,nID..."
+ *
+ * Nodes will be added to the buffer using a WayNodeListBuilder.
+ */
+ inline void opl_parse_way_nodes(const char* s, const char* e, osmium::memory::Buffer& buffer, osmium::builder::WayBuilder* parent_builder = nullptr) {
+ if (s == e) {
+ return;
+ }
+ osmium::builder::WayNodeListBuilder builder{buffer, parent_builder};
+
+ while (s < e) {
+ opl_parse_char(&s, 'n');
+ if (s == e) {
+ throw opl_error{"expected integer", s};
+ }
+
+ const osmium::object_id_type ref = opl_parse_id(&s);
+ if (s == e) {
+ builder.add_node_ref(ref);
+ return;
+ }
+
+ osmium::Location location;
+ if (*s == 'x') {
+ ++s;
+ location.set_lon_partial(&s);
+ if (*s == 'y') {
+ ++s;
+ location.set_lat_partial(&s);
+ }
+ }
+
+ builder.add_node_ref(ref, location);
+
+ if (s == e) {
+ return;
+ }
+
+ opl_parse_char(&s, ',');
+ }
+ }
+
+ inline void opl_parse_node(const char** data, osmium::memory::Buffer& buffer) {
+ osmium::builder::NodeBuilder builder{buffer};
+ osmium::Node& node = builder.object();
+
+ node.set_id(opl_parse_id(data));
+
+ const char* tags_begin = nullptr;
+
+ std::string user;
+ osmium::Location location;
+ while (**data) {
+ opl_parse_space(data);
+ const char c = **data;
+ if (c == '\0') {
+ break;
+ }
+ ++(*data);
+ switch (c) {
+ case 'v':
+ node.set_version(opl_parse_version(data));
+ break;
+ case 'd':
+ node.set_visible(opl_parse_visible(data));
+ break;
+ case 'c':
+ node.set_changeset(opl_parse_changeset_id(data));
+ break;
+ case 't':
+ node.set_timestamp(opl_parse_timestamp(data));
+ break;
+ case 'i':
+ node.set_uid(opl_parse_uid(data));
+ break;
+ case 'u':
+ opl_parse_string(data, user);
+ break;
+ case 'T':
+ if (opl_non_empty(*data)) {
+ tags_begin = *data;
+ opl_skip_section(data);
+ }
+ break;
+ case 'x':
+ if (opl_non_empty(*data)) {
+ location.set_lon_partial(data);
+ }
+ break;
+ case 'y':
+ if (opl_non_empty(*data)) {
+ location.set_lat_partial(data);
+ }
+ break;
+ default:
+ --(*data);
+ throw opl_error{"unknown attribute", *data};
+ }
+ }
+
+ if (location.valid()) {
+ node.set_location(location);
+ }
+
+ builder.add_user(user);
+
+ if (tags_begin) {
+ opl_parse_tags(tags_begin, buffer, &builder);
+ }
+
+ buffer.commit();
+ }
+
+ inline void opl_parse_way(const char** data, osmium::memory::Buffer& buffer) {
+ osmium::builder::WayBuilder builder{buffer};
+ osmium::Way& way = builder.object();
+
+ way.set_id(opl_parse_id(data));
+
+ const char* tags_begin = nullptr;
+
+ const char* nodes_begin = nullptr;
+ const char* nodes_end = nullptr;
+
+ std::string user;
+ while (**data) {
+ opl_parse_space(data);
+ const char c = **data;
+ if (c == '\0') {
+ break;
+ }
+ ++(*data);
+ switch (c) {
+ case 'v':
+ way.set_version(opl_parse_version(data));
+ break;
+ case 'd':
+ way.set_visible(opl_parse_visible(data));
+ break;
+ case 'c':
+ way.set_changeset(opl_parse_changeset_id(data));
+ break;
+ case 't':
+ way.set_timestamp(opl_parse_timestamp(data));
+ break;
+ case 'i':
+ way.set_uid(opl_parse_uid(data));
+ break;
+ case 'u':
+ opl_parse_string(data, user);
+ break;
+ case 'T':
+ if (opl_non_empty(*data)) {
+ tags_begin = *data;
+ opl_skip_section(data);
+ }
+ break;
+ case 'N':
+ nodes_begin = *data;
+ nodes_end = opl_skip_section(data);
+ break;
+ default:
+ --(*data);
+ throw opl_error{"unknown attribute", *data};
+ }
+ }
+
+ builder.add_user(user);
+
+ if (tags_begin) {
+ opl_parse_tags(tags_begin, buffer, &builder);
+ }
+
+ opl_parse_way_nodes(nodes_begin, nodes_end, buffer, &builder);
+
+ buffer.commit();
+ }
+
+ inline void opl_parse_relation_members(const char* s, const char* e, osmium::memory::Buffer& buffer, osmium::builder::RelationBuilder* parent_builder = nullptr) {
+ if (s == e) {
+ return;
+ }
+ osmium::builder::RelationMemberListBuilder builder{buffer, parent_builder};
+
+ while (s < e) {
+ osmium::item_type type = osmium::char_to_item_type(*s);
+ if (type != osmium::item_type::node &&
+ type != osmium::item_type::way &&
+ type != osmium::item_type::relation) {
+ throw opl_error{"unknown object type", s};
+ }
+ ++s;
+
+ if (s == e) {
+ throw opl_error{"expected integer", s};
+ }
+ osmium::object_id_type ref = opl_parse_id(&s);
+ opl_parse_char(&s, '@');
+ if (s == e) {
+ builder.add_member(type, ref, "");
+ return;
+ }
+ std::string role;
+ opl_parse_string(&s, role);
+ builder.add_member(type, ref, role);
+
+ if (s == e) {
+ return;
+ }
+ opl_parse_char(&s, ',');
+ }
+ }
+
+ inline void opl_parse_relation(const char** data, osmium::memory::Buffer& buffer) {
+ osmium::builder::RelationBuilder builder{buffer};
+ osmium::Relation& relation = builder.object();
+
+ relation.set_id(opl_parse_id(data));
+
+ const char* tags_begin = nullptr;
+
+ const char* members_begin = nullptr;
+ const char* members_end = nullptr;
+
+ std::string user;
+ while (**data) {
+ opl_parse_space(data);
+ const char c = **data;
+ if (c == '\0') {
+ break;
+ }
+ ++(*data);
+ switch (c) {
+ case 'v':
+ relation.set_version(opl_parse_version(data));
+ break;
+ case 'd':
+ relation.set_visible(opl_parse_visible(data));
+ break;
+ case 'c':
+ relation.set_changeset(opl_parse_changeset_id(data));
+ break;
+ case 't':
+ relation.set_timestamp(opl_parse_timestamp(data));
+ break;
+ case 'i':
+ relation.set_uid(opl_parse_uid(data));
+ break;
+ case 'u':
+ opl_parse_string(data, user);
+ break;
+ case 'T':
+ if (opl_non_empty(*data)) {
+ tags_begin = *data;
+ opl_skip_section(data);
+ }
+ break;
+ case 'M':
+ members_begin = *data;
+ members_end = opl_skip_section(data);
+ break;
+ default:
+ --(*data);
+ throw opl_error{"unknown attribute", *data};
+ }
+ }
+
+ builder.add_user(user);
+
+ if (tags_begin) {
+ opl_parse_tags(tags_begin, buffer, &builder);
+ }
+
+ if (members_begin != members_end) {
+ opl_parse_relation_members(members_begin, members_end, buffer, &builder);
+ }
+
+ buffer.commit();
+ }
+
+ inline void opl_parse_changeset(const char** data, osmium::memory::Buffer& buffer) {
+ osmium::builder::ChangesetBuilder builder{buffer};
+ osmium::Changeset& changeset = builder.object();
+
+ changeset.set_id(opl_parse_changeset_id(data));
+
+ const char* tags_begin = nullptr;
+
+ osmium::Location location1;
+ osmium::Location location2;
+ std::string user;
+ while (**data) {
+ opl_parse_space(data);
+ const char c = **data;
+ if (c == '\0') {
+ break;
+ }
+ ++(*data);
+ switch (c) {
+ case 'k':
+ changeset.set_num_changes(opl_parse_int<osmium::num_changes_type>(data));
+ break;
+ case 's':
+ changeset.set_created_at(opl_parse_timestamp(data));
+ break;
+ case 'e':
+ changeset.set_closed_at(opl_parse_timestamp(data));
+ break;
+ case 'd':
+ changeset.set_num_comments(opl_parse_int<osmium::num_comments_type>(data));
+ break;
+ case 'i':
+ changeset.set_uid(opl_parse_uid(data));
+ break;
+ case 'u':
+ opl_parse_string(data, user);
+ break;
+ case 'x':
+ if (opl_non_empty(*data)) {
+ location1.set_lon_partial(data);
+ }
+ break;
+ case 'y':
+ if (opl_non_empty(*data)) {
+ location1.set_lat_partial(data);
+ }
+ break;
+ case 'X':
+ if (opl_non_empty(*data)) {
+ location2.set_lon_partial(data);
+ }
+ break;
+ case 'Y':
+ if (opl_non_empty(*data)) {
+ location2.set_lat_partial(data);
+ }
+ break;
+ case 'T':
+ if (opl_non_empty(*data)) {
+ tags_begin = *data;
+ opl_skip_section(data);
+ }
+ break;
+ default:
+ --(*data);
+ throw opl_error{"unknown attribute", *data};
+ }
+
+ }
+
+ if (location1.valid() && location2.valid()) {
+ changeset.bounds().extend(location1);
+ changeset.bounds().extend(location2);
+ }
+
+ builder.add_user(user);
+
+ if (tags_begin) {
+ opl_parse_tags(tags_begin, buffer, &builder);
+ }
+
+ buffer.commit();
+ }
+
+ inline bool opl_parse_line(uint64_t line_count,
+ const char* data,
+ osmium::memory::Buffer& buffer,
+ osmium::osm_entity_bits::type read_types = osmium::osm_entity_bits::all) {
+ const char* start_of_line = data;
+ try {
+ switch (*data) {
+ case '\0':
+ // ignore empty lines
+ break;
+ case '#':
+ // ignore lines starting with #
+ break;
+ case 'n':
+ if (read_types & osmium::osm_entity_bits::node) {
+ ++data;
+ opl_parse_node(&data, buffer);
+ return true;
+ }
+ break;
+ case 'w':
+ if (read_types & osmium::osm_entity_bits::way) {
+ ++data;
+ opl_parse_way(&data, buffer);
+ return true;
+ }
+ break;
+ case 'r':
+ if (read_types & osmium::osm_entity_bits::relation) {
+ ++data;
+ opl_parse_relation(&data, buffer);
+ return true;
+ }
+ break;
+ case 'c':
+ if (read_types & osmium::osm_entity_bits::changeset) {
+ ++data;
+ opl_parse_changeset(&data, buffer);
+ return true;
+ }
+ break;
+ default:
+ throw opl_error{"unknown type", data};
+ }
+ } catch (opl_error& e) {
+ e.set_pos(line_count, e.data ? e.data - start_of_line : 0);
+ throw;
+ }
+
+ return false;
+ }
+
+ } // namespace detail
+
+ } // namespace io
+
+} // namespace osmium
+
+
+#endif // OSMIUM_IO_DETAIL_OPL_PARSER_FUNCTIONS_HPP
diff --git a/include/osmium/io/detail/output_format.hpp b/include/osmium/io/detail/output_format.hpp
index eaff001..0fe4915 100644
--- a/include/osmium/io/detail/output_format.hpp
+++ b/include/osmium/io/detail/output_format.hpp
@@ -33,16 +33,16 @@ DEALINGS IN THE SOFTWARE.
*/
+#include <cstdint>
#include <functional>
#include <map>
#include <memory>
-#include <stdexcept>
#include <string>
#include <utility>
#include <osmium/handler.hpp>
#include <osmium/io/detail/queue_util.hpp>
-#include <osmium/io/detail/string_util.hpp>
+#include <osmium/io/error.hpp>
#include <osmium/io/file.hpp>
#include <osmium/io/file_format.hpp>
#include <osmium/memory/buffer.hpp>
diff --git a/include/osmium/io/detail/pbf_decoder.hpp b/include/osmium/io/detail/pbf_decoder.hpp
index 6980c48..5df191d 100644
--- a/include/osmium/io/detail/pbf_decoder.hpp
+++ b/include/osmium/io/detail/pbf_decoder.hpp
@@ -33,10 +33,8 @@ DEALINGS IN THE SOFTWARE.
*/
-#include <cstddef>
#include <cstdint>
#include <cstring>
-#include <algorithm>
#include <limits>
#include <memory>
#include <stdexcept>
@@ -44,23 +42,35 @@ DEALINGS IN THE SOFTWARE.
#include <utility>
#include <vector>
+#include <protozero/iterators.hpp>
#include <protozero/pbf_message.hpp>
+#include <protozero/types.hpp>
#include <osmium/builder/osm_object_builder.hpp>
#include <osmium/io/detail/pbf.hpp> // IWYU pragma: export
#include <osmium/io/detail/protobuf_tags.hpp>
#include <osmium/io/detail/zlib.hpp>
#include <osmium/io/header.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/osm/box.hpp>
+#include <osmium/osm/entity_bits.hpp>
+#include <osmium/osm/item_type.hpp>
#include <osmium/osm/location.hpp>
#include <osmium/osm/node.hpp>
+#include <osmium/osm/object.hpp>
+#include <osmium/osm/relation.hpp>
+#include <osmium/osm/timestamp.hpp>
#include <osmium/osm/types.hpp>
-#include <osmium/memory/buffer.hpp>
-#include <osmium/osm/entity_bits.hpp>
+#include <osmium/osm/way.hpp>
#include <osmium/util/cast.hpp>
#include <osmium/util/delta.hpp>
namespace osmium {
+ namespace builder {
+ class Builder;
+ } // namespace builder
+
namespace io {
namespace detail {
@@ -70,7 +80,7 @@ namespace osmium {
class PBFPrimitiveBlockDecoder {
- static constexpr size_t initial_buffer_size = 2 * 1024 * 1024;
+ static constexpr const size_t initial_buffer_size = 2 * 1024 * 1024;
data_view m_data;
std::vector<osm_string_len_type> m_stringtable;
@@ -91,7 +101,7 @@ namespace osmium {
protozero::pbf_message<OSMFormat::StringTable> pbf_string_table(data);
while (pbf_string_table.next(OSMFormat::StringTable::repeated_bytes_s)) {
- auto str_view = pbf_string_table.get_view();
+ const auto str_view = pbf_string_table.get_view();
if (str_view.size() > osmium::max_osm_string_length) {
throw osmium::pbf_error("overlong string in string table");
}
@@ -173,7 +183,7 @@ namespace osmium {
switch (pbf_info.tag()) {
case OSMFormat::Info::optional_int32_version:
{
- auto version = pbf_info.get_int32();
+ const auto version = pbf_info.get_int32();
if (version < 0) {
throw osmium::pbf_error("object version must not be negative");
}
@@ -185,7 +195,7 @@ namespace osmium {
break;
case OSMFormat::Info::optional_int64_changeset:
{
- auto changeset_id = pbf_info.get_int64();
+ const auto changeset_id = pbf_info.get_int64();
if (changeset_id < 0) {
throw osmium::pbf_error("object changeset_id must not be negative");
}
@@ -404,7 +414,7 @@ namespace osmium {
osmium::util::DeltaDecode<int64_t> ref;
while (!roles.empty() && !refs.empty() && !types.empty()) {
const auto& r = m_stringtable.at(roles.front());
- int type = types.front();
+ const int type = types.front();
if (type < 0 || type > 2) {
throw osmium::pbf_error("unknown relation member type");
}
@@ -528,14 +538,14 @@ namespace osmium {
throw osmium::pbf_error("PBF format error");
}
- auto version = versions.front();
+ const auto version = versions.front();
versions.drop_front();
if (version < 0) {
throw osmium::pbf_error("object version must not be negative");
}
node.set_version(static_cast<osmium::object_version_type>(version));
- auto changeset_id = dense_changeset.update(changesets.front());
+ 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");
@@ -617,7 +627,7 @@ namespace osmium {
try {
decode_primitive_block_metadata();
decode_primitive_block_data();
- } catch (std::out_of_range&) {
+ } catch (const std::out_of_range&) {
throw osmium::pbf_error("string id out of range");
}
@@ -743,7 +753,7 @@ namespace osmium {
break;
case OSMFormat::HeaderBlock::optional_int64_osmosis_replication_timestamp:
{
- 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);
}
diff --git a/include/osmium/io/detail/pbf_input_format.hpp b/include/osmium/io/detail/pbf_input_format.hpp
index 8361c72..1253447 100644
--- a/include/osmium/io/detail/pbf_input_format.hpp
+++ b/include/osmium/io/detail/pbf_input_format.hpp
@@ -38,25 +38,22 @@ DEALINGS IN THE SOFTWARE.
#include <cstddef>
#include <cstdint>
#include <cstring>
+#include <future>
#include <memory>
-#include <sstream>
#include <string>
-#include <thread>
#include <type_traits>
#include <protozero/pbf_message.hpp>
+#include <protozero/types.hpp>
#include <osmium/io/detail/input_format.hpp>
#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/error.hpp>
-#include <osmium/io/file.hpp>
+#include <osmium/io/detail/queue_util.hpp>
#include <osmium/io/file_format.hpp>
-#include <osmium/osm.hpp>
+#include <osmium/io/header.hpp>
#include <osmium/osm/entity_bits.hpp>
-#include <osmium/osm/object.hpp>
-#include <osmium/osm/timestamp.hpp>
#include <osmium/thread/pool.hpp>
#include <osmium/thread/util.hpp>
#include <osmium/util/config.hpp>
@@ -80,7 +77,7 @@ namespace osmium {
*/
std::string read_from_input_queue(size_t size) {
while (m_input_buffer.size() < size) {
- std::string new_data = get_input();
+ const std::string new_data = get_input();
if (input_done()) {
throw osmium::pbf_error("truncated data (EOF encountered)");
}
@@ -106,7 +103,7 @@ namespace osmium {
try {
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 (osmium::pbf_error&) {
+ } catch (const osmium::pbf_error&) {
return 0; // EOF
}
diff --git a/include/osmium/io/detail/pbf_output_format.hpp b/include/osmium/io/detail/pbf_output_format.hpp
index d5f8cd4..43aa8cc 100644
--- a/include/osmium/io/detail/pbf_output_format.hpp
+++ b/include/osmium/io/detail/pbf_output_format.hpp
@@ -41,30 +41,34 @@ DEALINGS IN THE SOFTWARE.
#include <iterator>
#include <memory>
#include <string>
-#include <time.h>
#include <utility>
#include <protozero/pbf_builder.hpp>
+#include <protozero/pbf_writer.hpp>
+#include <protozero/types.hpp>
#include <osmium/handler.hpp>
#include <osmium/io/detail/output_format.hpp>
#include <osmium/io/detail/pbf.hpp> // IWYU pragma: export
#include <osmium/io/detail/protobuf_tags.hpp>
+#include <osmium/io/detail/queue_util.hpp>
#include <osmium/io/detail/string_table.hpp>
#include <osmium/io/detail/zlib.hpp>
#include <osmium/io/file.hpp>
#include <osmium/io/file_format.hpp>
#include <osmium/io/header.hpp>
#include <osmium/memory/buffer.hpp>
-#include <osmium/memory/collection.hpp>
+#include <osmium/memory/item_iterator.hpp>
#include <osmium/osm/box.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/relation.hpp>
#include <osmium/osm/tag.hpp>
#include <osmium/osm/timestamp.hpp>
+#include <osmium/osm/types.hpp>
#include <osmium/osm/way.hpp>
#include <osmium/thread/pool.hpp>
#include <osmium/util/cast.hpp>
@@ -524,18 +528,18 @@ namespace osmium {
pbf_header_block.add_string(OSMFormat::HeaderBlock::optional_string_writingprogram, header.get("generator"));
- 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());
pbf_header_block.add_int64(OSMFormat::HeaderBlock::optional_int64_osmosis_replication_timestamp, uint32_t(ts));
}
- 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()));
}
- 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);
}
diff --git a/include/osmium/io/detail/read_write.hpp b/include/osmium/io/detail/read_write.hpp
index 769e2b3..a086e5b 100644
--- a/include/osmium/io/detail/read_write.hpp
+++ b/include/osmium/io/detail/read_write.hpp
@@ -35,7 +35,6 @@ DEALINGS IN THE SOFTWARE.
#include <cerrno>
#include <cstddef>
-#include <errno.h>
#include <fcntl.h>
#include <string>
#include <system_error>
@@ -84,7 +83,7 @@ namespace osmium {
#ifdef _WIN32
flags |= O_BINARY;
#endif
- int fd = ::open(filename.c_str(), flags, 0666);
+ 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 + "'");
}
@@ -108,7 +107,7 @@ namespace osmium {
#ifdef _WIN32
flags |= O_BINARY;
#endif
- int fd = ::open(filename.c_str(), flags);
+ 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 + "'");
}
@@ -133,7 +132,7 @@ namespace osmium {
if (write_count > max_write) {
write_count = max_write;
}
- auto length = ::write(fd, output_buffer + offset, static_cast<unsigned int>(write_count));
+ const auto length = ::write(fd, output_buffer + offset, static_cast<unsigned int>(write_count));
if (length < 0) {
throw std::system_error(errno, std::system_category(), "Write failed");
}
diff --git a/include/osmium/io/detail/string_table.hpp b/include/osmium/io/detail/string_table.hpp
index 995e2cf..f1ddc87 100644
--- a/include/osmium/io/detail/string_table.hpp
+++ b/include/osmium/io/detail/string_table.hpp
@@ -34,13 +34,14 @@ DEALINGS IN THE SOFTWARE.
*/
#include <cassert>
+#include <cstddef>
#include <cstdint>
-#include <cstdlib>
#include <cstring>
#include <iterator>
#include <list>
#include <string>
#include <unordered_map>
+#include <utility>
#include <osmium/io/detail/pbf.hpp>
@@ -94,7 +95,7 @@ namespace osmium {
* allocated.
*/
const char* add(const char* string) {
- size_t len = std::strlen(string) + 1;
+ const size_t len = std::strlen(string) + 1;
assert(len <= m_chunk_size);
@@ -134,7 +135,7 @@ namespace osmium {
const_iterator& operator++() {
assert(m_it != m_last);
- auto last_pos = m_it->c_str() + m_it->size();
+ const auto last_pos = m_it->c_str() + m_it->size();
while (m_pos != last_pos && *m_pos) ++m_pos;
if (m_pos != last_pos) ++m_pos;
if (m_pos == last_pos) {
@@ -263,7 +264,7 @@ namespace osmium {
}
uint32_t add(const char* s) {
- auto f = m_index.find(s);
+ const auto f = m_index.find(s);
if (f != m_index.end()) {
return uint32_t(f->second);
}
diff --git a/include/osmium/io/detail/string_util.hpp b/include/osmium/io/detail/string_util.hpp
index 52408ff..0334b0e 100644
--- a/include/osmium/io/detail/string_util.hpp
+++ b/include/osmium/io/detail/string_util.hpp
@@ -35,6 +35,7 @@ DEALINGS IN THE SOFTWARE.
#include <cassert>
#include <cstdint>
+#include <cstdio>
#include <cstring>
#include <string>
#include <utility>
@@ -100,24 +101,24 @@ namespace osmium {
static const size_t max_size = 0;
#endif
- size_t old_size = out.size();
+ const size_t old_size = out.size();
- int len = string_snprintf(out,
- old_size,
- max_size,
- format,
- std::forward<TArgs>(args)...);
+ const int len = string_snprintf(out,
+ old_size,
+ max_size,
+ format,
+ std::forward<TArgs>(args)...);
assert(len > 0);
if (size_t(len) >= max_size) {
#ifndef NDEBUG
- int len2 =
+ const int len2 =
#endif
- string_snprintf(out,
- old_size,
- size_t(len) + 1,
- format,
- std::forward<TArgs>(args)...);
+ string_snprintf(out,
+ old_size,
+ size_t(len) + 1,
+ format,
+ std::forward<TArgs>(args)...);
assert(len2 == len);
}
@@ -150,7 +151,7 @@ namespace osmium {
while (data != end) {
const char* last = data;
- uint32_t c = utf8::next(data, end);
+ const uint32_t c = utf8::next(data, end);
// This is a list of Unicode code points that we let
// through instead of escaping them. It is incomplete
diff --git a/include/osmium/io/detail/write_thread.hpp b/include/osmium/io/detail/write_thread.hpp
index 7960486..85ef811 100644
--- a/include/osmium/io/detail/write_thread.hpp
+++ b/include/osmium/io/detail/write_thread.hpp
@@ -36,6 +36,7 @@ DEALINGS IN THE SOFTWARE.
#include <algorithm>
#include <exception>
#include <future>
+#include <memory>
#include <string>
#include <osmium/io/compression.hpp>
diff --git a/include/osmium/io/detail/xml_input_format.hpp b/include/osmium/io/detail/xml_input_format.hpp
index be1e2e7..d8c57d8 100644
--- a/include/osmium/io/detail/xml_input_format.hpp
+++ b/include/osmium/io/detail/xml_input_format.hpp
@@ -34,10 +34,7 @@ DEALINGS IN THE SOFTWARE.
*/
#include <cassert>
-#include <cstddef>
-#include <cstdlib>
#include <cstring>
-#include <exception>
#include <future>
#include <memory>
#include <string>
@@ -53,15 +50,19 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/io/file_format.hpp>
#include <osmium/io/header.hpp>
#include <osmium/memory/buffer.hpp>
-#include <osmium/osm.hpp>
#include <osmium/osm/box.hpp>
+#include <osmium/osm/changeset.hpp>
#include <osmium/osm/entity_bits.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/relation.hpp>
+#include <osmium/osm/timestamp.hpp>
#include <osmium/osm/types.hpp>
#include <osmium/osm/types_from_string.hpp>
-#include <osmium/thread/queue.hpp>
+#include <osmium/osm/way.hpp>
#include <osmium/thread/util.hpp>
#include <osmium/util/cast.hpp>
diff --git a/include/osmium/io/detail/xml_output_format.hpp b/include/osmium/io/detail/xml_output_format.hpp
index cc0e062..3f47b0f 100644
--- a/include/osmium/io/detail/xml_output_format.hpp
+++ b/include/osmium/io/detail/xml_output_format.hpp
@@ -34,27 +34,26 @@ DEALINGS IN THE SOFTWARE.
*/
#include <algorithm>
-#include <cinttypes>
-#include <cstddef>
-#include <cstdio>
-#include <future>
#include <iterator>
#include <memory>
#include <string>
-#include <thread>
#include <utility>
+#include <osmium/handler.hpp>
#include <osmium/io/detail/output_format.hpp>
+#include <osmium/io/detail/queue_util.hpp>
+#include <osmium/io/detail/string_util.hpp>
#include <osmium/io/file.hpp>
#include <osmium/io/file_format.hpp>
#include <osmium/io/header.hpp>
#include <osmium/memory/buffer.hpp>
-#include <osmium/memory/collection.hpp>
+#include <osmium/memory/item_iterator.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/relation.hpp>
#include <osmium/osm/tag.hpp>
diff --git a/include/osmium/io/detail/zlib.hpp b/include/osmium/io/detail/zlib.hpp
index 57b456b..15ece7c 100644
--- a/include/osmium/io/detail/zlib.hpp
+++ b/include/osmium/io/detail/zlib.hpp
@@ -33,8 +33,6 @@ DEALINGS IN THE SOFTWARE.
*/
-#include <memory>
-#include <stdexcept>
#include <string>
#include <zlib.h>
@@ -64,7 +62,7 @@ namespace osmium {
std::string output(output_size, '\0');
- auto result = ::compress(
+ const auto result = ::compress(
reinterpret_cast<unsigned char*>(const_cast<char *>(output.data())),
&output_size,
reinterpret_cast<const unsigned char*>(input.data()),
@@ -94,7 +92,7 @@ namespace osmium {
inline protozero::data_view zlib_uncompress_string(const char* input, unsigned long input_size, unsigned long raw_size, std::string& output) {
output.resize(raw_size);
- auto result = ::uncompress(
+ const auto result = ::uncompress(
reinterpret_cast<unsigned char*>(&*output.begin()),
&raw_size,
reinterpret_cast<const unsigned char*>(input),
diff --git a/include/osmium/io/file.hpp b/include/osmium/io/file.hpp
index 56fc8d5..812c494 100644
--- a/include/osmium/io/file.hpp
+++ b/include/osmium/io/file.hpp
@@ -34,7 +34,6 @@ DEALINGS IN THE SOFTWARE.
*/
#include <cstddef>
-#include <stdexcept>
#include <sstream>
#include <string>
#include <vector>
@@ -43,7 +42,6 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/io/file_format.hpp>
#include <osmium/io/file_compression.hpp>
#include <osmium/util/options.hpp>
-#include <osmium/util/compatibility.hpp>
namespace osmium {
@@ -115,7 +113,7 @@ namespace osmium {
}
// if filename is a URL, default to XML format
- 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;
}
@@ -174,7 +172,7 @@ namespace osmium {
}
for (auto& option : options) {
- size_t pos = option.find_first_of('=');
+ const size_t pos = option.find_first_of('=');
if (pos == std::string::npos) {
set(option, true);
} else {
diff --git a/include/osmium/io/gzip_compression.hpp b/include/osmium/io/gzip_compression.hpp
index e6ca010..5e3e233 100644
--- a/include/osmium/io/gzip_compression.hpp
+++ b/include/osmium/io/gzip_compression.hpp
@@ -42,15 +42,20 @@ DEALINGS IN THE SOFTWARE.
* @attention If you include this file, you'll need to link with `libz`.
*/
-#include <stdexcept>
+#include <cstddef>
#include <string>
+#ifndef _MSC_VER
+# include <unistd.h>
+#endif
+
#include <errno.h>
#include <zlib.h>
#include <osmium/io/compression.hpp>
#include <osmium/io/error.hpp>
#include <osmium/io/file_compression.hpp>
+#include <osmium/io/detail/read_write.hpp>
#include <osmium/io/writer_options.hpp>
#include <osmium/util/cast.hpp>
#include <osmium/util/compatibility.hpp>
@@ -102,7 +107,7 @@ namespace osmium {
explicit GzipCompressor(int fd, fsync sync) :
Compressor(sync),
- m_fd(dup(fd)),
+ m_fd(::dup(fd)),
m_gzfile(::gzdopen(fd, "w")) {
if (!m_gzfile) {
detail::throw_gzip_error(m_gzfile, "write initialization failed");
@@ -171,6 +176,9 @@ namespace osmium {
detail::throw_gzip_error(m_gzfile, "read failed");
}
buffer.resize(static_cast<std::string::size_type>(nread));
+#if ZLIB_VERNUM >= 0x1240
+ set_offset(size_t(::gzoffset(m_gzfile)));
+#endif
return buffer;
}
diff --git a/include/osmium/io/input_iterator.hpp b/include/osmium/io/input_iterator.hpp
index a66f355..4cde92f 100644
--- a/include/osmium/io/input_iterator.hpp
+++ b/include/osmium/io/input_iterator.hpp
@@ -41,7 +41,6 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/memory/buffer.hpp>
#include <osmium/memory/item.hpp>
-#include <osmium/util/compatibility.hpp>
namespace osmium {
diff --git a/include/osmium/version.hpp b/include/osmium/io/opl_input.hpp
similarity index 83%
copy from include/osmium/version.hpp
copy to include/osmium/io/opl_input.hpp
index ac7a94f..ee9e447 100644
--- a/include/osmium/version.hpp
+++ b/include/osmium/io/opl_input.hpp
@@ -1,5 +1,5 @@
-#ifndef OSMIUM_VERSION_HPP
-#define OSMIUM_VERSION_HPP
+#ifndef OSMIUM_IO_OPL_INPUT_HPP
+#define OSMIUM_IO_OPL_INPUT_HPP
/*
@@ -33,10 +33,14 @@ DEALINGS IN THE SOFTWARE.
*/
-#define LIBOSMIUM_VERSION_MAJOR 2
-#define LIBOSMIUM_VERSION_MINOR 8
-#define LIBOSMIUM_VERSION_PATCH 0
+/**
+ * @file
+ *
+ * Include this file if you want to read OSM OPL files.
+ *
+ */
-#define LIBOSMIUM_VERSION_STRING "2.8.0"
+#include <osmium/io/reader.hpp> // IWYU pragma: export
+#include <osmium/io/detail/opl_input_format.hpp> // IWYU pragma: export
-#endif // OSMIUM_VERSION_HPP
+#endif // OSMIUM_IO_OPL_INPUT_HPP
diff --git a/include/osmium/io/output_iterator.hpp b/include/osmium/io/output_iterator.hpp
index f7025fc..cf9291d 100644
--- a/include/osmium/io/output_iterator.hpp
+++ b/include/osmium/io/output_iterator.hpp
@@ -35,10 +35,7 @@ DEALINGS IN THE SOFTWARE.
#include <cstddef>
#include <iterator>
-#include <memory>
-#include <utility>
-#include <osmium/memory/buffer.hpp>
#include <osmium/osm/diff_object.hpp>
#include <osmium/util/compatibility.hpp>
diff --git a/include/osmium/io/overwrite.hpp b/include/osmium/io/overwrite.hpp
index 5361698..bc6a503 100644
--- a/include/osmium/io/overwrite.hpp
+++ b/include/osmium/io/overwrite.hpp
@@ -34,6 +34,6 @@ DEALINGS IN THE SOFTWARE.
*/
#pragma message("Including overwrite.hpp is deprecated, #include <osmium/io/writer_options.hpp> instead.")
-#include <osmium/io/writer_options.hpp>
+#include <osmium/io/writer_options.hpp> // IWYU pragma: keep
#endif // OSMIUM_IO_OVERWRITE_HPP
diff --git a/include/osmium/io/reader.hpp b/include/osmium/io/reader.hpp
index b267db6..12f97b8 100644
--- a/include/osmium/io/reader.hpp
+++ b/include/osmium/io/reader.hpp
@@ -71,12 +71,12 @@ namespace osmium {
namespace detail {
inline size_t get_input_queue_size() noexcept {
- size_t n = osmium::config::get_max_queue_size("INPUT", 20);
+ const size_t n = osmium::config::get_max_queue_size("INPUT", 20);
return n > 2 ? n : 2;
}
inline size_t get_osmdata_queue_size() noexcept {
- size_t n = osmium::config::get_max_queue_size("OSMDATA", 20);
+ const size_t n = osmium::config::get_max_queue_size("OSMDATA", 20);
return n > 2 ? n : 2;
}
@@ -116,6 +116,8 @@ namespace osmium {
osmium::thread::thread_handler m_thread;
+ size_t m_file_size;
+
// This function will run in a separate thread.
static void parser_thread(const osmium::io::File& file,
detail::future_string_queue_type& input_queue,
@@ -123,8 +125,8 @@ namespace osmium {
std::promise<osmium::io::Header>&& header_promise,
osmium::osm_entity_bits::type read_which_entities) {
std::promise<osmium::io::Header> promise = std::move(header_promise);
- auto creator = detail::ParserFactory::instance().get_creator_function(file);
- auto parser = creator(input_queue, osmdata_queue, promise, read_which_entities);
+ const auto creator = detail::ParserFactory::instance().get_creator_function(file);
+ const auto parser = creator(input_queue, osmdata_queue, promise, read_which_entities);
parser->parse();
}
@@ -145,7 +147,7 @@ namespace osmium {
if (pipe(pipefd) < 0) {
throw std::system_error(errno, std::system_category(), "opening pipe failed");
}
- pid_t pid = fork();
+ const pid_t pid = fork();
if (pid < 0) {
throw std::system_error(errno, std::system_category(), "fork failed");
}
@@ -223,7 +225,8 @@ namespace osmium {
m_osmdata_queue_wrapper(m_osmdata_queue),
m_header_future(),
m_header(),
- m_thread() {
+ m_thread(),
+ m_file_size(m_decompressor->file_size()) {
std::promise<osmium::io::Header> header_promise;
m_header_future = header_promise.get_future();
m_thread = osmium::thread::thread_handler{parser_thread, std::ref(m_file), std::ref(m_input_queue), std::ref(m_osmdata_queue), std::move(header_promise), read_which_entities};
@@ -275,7 +278,7 @@ namespace osmium {
#ifndef _WIN32
if (m_childpid) {
int status;
- pid_t pid = ::waitpid(m_childpid, &status, 0);
+ const pid_t pid = ::waitpid(m_childpid, &status, 0);
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wold-style-cast"
if (pid < 0 || !WIFEXITED(status) || WEXITSTATUS(status) != 0) {
@@ -362,6 +365,32 @@ namespace osmium {
return m_status == status::eof || m_status == status::closed;
}
+ /**
+ * Get the size of the input file. Returns 0 if the file size
+ * is not available (for instance when reading from stdin).
+ */
+ size_t file_size() const noexcept {
+ return m_file_size;
+ }
+
+ /**
+ * Returns the current offset into the input file. Returns 0 if
+ * the offset is not available (for instance when reading from
+ * stdin).
+ *
+ * The offset can be used together with the result of file_size()
+ * to estimate how much of the file has been read. Note that due
+ * to buffering inside Osmium, this value will be larger than
+ * the amount of data actually available to the application.
+ *
+ * Do not call this function too often, certainly not for every
+ * object you are reading. Depending on the file type it might
+ * do an expensive system call.
+ */
+ size_t offset() const noexcept {
+ return m_decompressor->offset();
+ }
+
}; // class Reader
/**
diff --git a/include/osmium/io/writer.hpp b/include/osmium/io/writer.hpp
index 13ac575..c12d317 100644
--- a/include/osmium/io/writer.hpp
+++ b/include/osmium/io/writer.hpp
@@ -34,11 +34,13 @@ DEALINGS IN THE SOFTWARE.
*/
#include <cassert>
+#include <cstddef>
+#include <exception>
+#include <functional>
#include <future>
+#include <initializer_list>
#include <memory>
-#include <stdexcept>
#include <string>
-#include <thread>
#include <utility>
#include <osmium/io/compression.hpp>
@@ -56,6 +58,10 @@ DEALINGS IN THE SOFTWARE.
namespace osmium {
+ namespace memory {
+ class Item;
+ } //namespace memory
+
namespace io {
namespace detail {
@@ -314,7 +320,7 @@ namespace osmium {
}
try {
m_buffer.push_back(item);
- } catch (osmium::buffer_is_full&) {
+ } catch (const osmium::buffer_is_full&) {
do_flush();
m_buffer.push_back(item);
}
diff --git a/include/osmium/memory/item.hpp b/include/osmium/memory/item.hpp
index 0d550fb..2df33c7 100644
--- a/include/osmium/memory/item.hpp
+++ b/include/osmium/memory/item.hpp
@@ -33,8 +33,10 @@ DEALINGS IN THE SOFTWARE.
*/
+#include <cstddef>
#include <cstdint>
-#include <type_traits>
+
+#include <osmium/util/cast.hpp>
namespace osmium {
@@ -45,6 +47,13 @@ namespace osmium {
class Builder;
} // namespace builder
+ enum class diff_indicator_type {
+ none = 0,
+ left = 1,
+ right = 2,
+ both = 3
+ }; // diff_indicator_type
+
namespace memory {
using item_size_type = uint32_t;
@@ -52,9 +61,7 @@ namespace osmium {
// align datastructures to this many bytes
constexpr item_size_type align_bytes = 8;
- template <typename T>
- inline T padded_length(T length) noexcept {
- static_assert(std::is_integral<T>::value && std::is_unsigned<T>::value, "Template parameter must be unsigned integral type");
+ inline std::size_t padded_length(std::size_t length) noexcept {
return (length + align_bytes - 1) & ~(align_bytes - 1);
}
@@ -100,7 +107,8 @@ namespace osmium {
item_size_type m_size;
item_type m_type;
uint16_t m_removed : 1;
- uint16_t m_padding : 15;
+ uint16_t m_diff : 2;
+ uint16_t m_padding : 13;
template <typename TMember>
friend class CollectionIterator;
@@ -121,6 +129,7 @@ namespace osmium {
m_size(size),
m_type(type),
m_removed(false),
+ m_diff(0),
m_padding(0) {
}
@@ -150,7 +159,7 @@ namespace osmium {
}
item_size_type padded_size() const {
- return padded_length(m_size);
+ return static_cast_with_assert<item_size_type>(padded_length(m_size));
}
item_type type() const noexcept {
@@ -165,6 +174,19 @@ namespace osmium {
m_removed = removed;
}
+ diff_indicator_type diff() const noexcept {
+ return diff_indicator_type(m_diff);
+ }
+
+ char diff_as_char() const noexcept {
+ static constexpr const char* diff_chars = "*-+ ";
+ return diff_chars[m_diff];
+ }
+
+ void set_diff(diff_indicator_type diff) noexcept {
+ m_diff = uint16_t(diff);
+ }
+
}; // class Item
static_assert(sizeof(Item) == 8, "Class osmium::Item has wrong size!");
diff --git a/include/osmium/memory/item_iterator.hpp b/include/osmium/memory/item_iterator.hpp
index df72999..27ebc59 100644
--- a/include/osmium/memory/item_iterator.hpp
+++ b/include/osmium/memory/item_iterator.hpp
@@ -34,16 +34,29 @@ DEALINGS IN THE SOFTWARE.
*/
#include <cassert>
+#include <cstddef>
#include <iterator>
#include <iosfwd>
#include <type_traits>
-#include <osmium/fwd.hpp>
#include <osmium/memory/item.hpp>
#include <osmium/osm/item_type.hpp>
namespace osmium {
+ class Area;
+ class Changeset;
+ class InnerRing;
+ class Node;
+ class OSMEntity;
+ class OSMObject;
+ class OuterRing;
+ class Relation;
+ class RelationMemberList;
+ class TagList;
+ class Way;
+ class WayNodeList;
+
namespace memory {
namespace detail {
diff --git a/include/osmium/object_pointer_collection.hpp b/include/osmium/object_pointer_collection.hpp
index ce77bd2..4db1c08 100644
--- a/include/osmium/object_pointer_collection.hpp
+++ b/include/osmium/object_pointer_collection.hpp
@@ -40,11 +40,9 @@ DEALINGS IN THE SOFTWARE.
#include <boost/iterator/indirect_iterator.hpp>
#include <osmium/handler.hpp>
-#include <osmium/memory/item.hpp>
#include <osmium/osm/object.hpp>
// IWYU pragma: no_forward_declare osmium::OSMObject
-// IWYU pragma: no_forward_declare osmium::memory::Item
namespace osmium {
diff --git a/include/osmium/tags/taglist.hpp b/include/osmium/opl.hpp
similarity index 61%
copy from include/osmium/tags/taglist.hpp
copy to include/osmium/opl.hpp
index b1f346f..5666fa0 100644
--- a/include/osmium/tags/taglist.hpp
+++ b/include/osmium/opl.hpp
@@ -1,5 +1,5 @@
-#ifndef OSMIUM_TAGS_TAGLIST_HPP
-#define OSMIUM_TAGS_TAGLIST_HPP
+#ifndef OSMIUM_OPL_HPP
+#define OSMIUM_OPL_HPP
/*
@@ -33,35 +33,35 @@ DEALINGS IN THE SOFTWARE.
*/
-#include <algorithm>
-#include <utility>
-
-#include <osmium/osm/tag.hpp>
+#include <osmium/memory/buffer.hpp>
+#include <osmium/io/detail/opl_parser_functions.hpp>
namespace osmium {
/**
- * @brief Code related to working with OSM tags
+ * Parses one line in OPL format. The line must not have a newline
+ * character at the end. Buffer.commit() is called automatically if the
+ * write succeeded.
+ *
+ * @param data Line must be in this zero-delimited string.
+ * @param buffer Result will be written to this buffer.
+ *
+ * @returns true if an entity was parsed, false otherwise (for instance
+ * when the line is empty).
+ * @throws osmium::opl_error If the parsing fails.
*/
- namespace tags {
-
- template <typename TFilter>
- inline bool match_any_of(const osmium::TagList& tag_list, TFilter&& filter) {
- return std::any_of(tag_list.cbegin(), tag_list.cend(), std::forward<TFilter>(filter));
- }
-
- template <typename TFilter>
- inline bool match_all_of(const osmium::TagList& tag_list, TFilter&& filter) {
- return std::all_of(tag_list.cbegin(), tag_list.cend(), std::forward<TFilter>(filter));
+ inline bool opl_parse(const char* data, osmium::memory::Buffer& buffer) {
+ try {
+ const bool wrote_something = osmium::io::detail::opl_parse_line(0, data, buffer);
+ buffer.commit();
+ return wrote_something;
+ } catch (const osmium::opl_error&) {
+ buffer.rollback();
+ throw;
}
-
- template <typename TFilter>
- inline bool match_none_of(const osmium::TagList& tag_list, TFilter&& filter) {
- return std::none_of(tag_list.cbegin(), tag_list.cend(), std::forward<TFilter>(filter));
- }
-
- } // namespace tags
+ }
} // namespace osmium
-#endif // OSMIUM_TAGS_TAGLIST_HPP
+
+#endif // OSMIUM_OPL_HPP
diff --git a/include/osmium/osm.hpp b/include/osmium/osm.hpp
index 594db75..fa8a92d 100644
--- a/include/osmium/osm.hpp
+++ b/include/osmium/osm.hpp
@@ -33,11 +33,20 @@ DEALINGS IN THE SOFTWARE.
*/
-#include <osmium/osm/node.hpp> // IWYU pragma: export
-#include <osmium/osm/way.hpp> // IWYU pragma: export
-#include <osmium/osm/relation.hpp> // IWYU pragma: export
#include <osmium/osm/area.hpp> // IWYU pragma: export
#include <osmium/osm/changeset.hpp> // IWYU pragma: export
+#include <osmium/osm/entity.hpp> // IWYU pragma: export
+#include <osmium/osm/entity_bits.hpp> // IWYU pragma: export
+#include <osmium/osm/item_type.hpp> // IWYU pragma: export
+#include <osmium/osm/location.hpp> // IWYU pragma: export
+#include <osmium/osm/node.hpp> // IWYU pragma: export
+#include <osmium/osm/node_ref.hpp> // IWYU pragma: export
+#include <osmium/osm/node_ref_list.hpp> // IWYU pragma: export
+#include <osmium/osm/object.hpp> // IWYU pragma: export
+#include <osmium/osm/relation.hpp> // IWYU pragma: export
+#include <osmium/osm/timestamp.hpp> // IWYU pragma: export
+#include <osmium/osm/types.hpp> // IWYU pragma: export
+#include <osmium/osm/way.hpp> // IWYU pragma: export
/**
* @brief Namespace for everything in the Osmium library.
diff --git a/include/osmium/osm/area.hpp b/include/osmium/osm/area.hpp
index 858c90d..490fbe9 100644
--- a/include/osmium/osm/area.hpp
+++ b/include/osmium/osm/area.hpp
@@ -35,10 +35,12 @@ DEALINGS IN THE SOFTWARE.
#include <cassert>
#include <cstdlib>
+#include <iterator>
#include <utility>
#include <osmium/memory/collection.hpp>
#include <osmium/memory/item.hpp>
+#include <osmium/memory/item_iterator.hpp>
#include <osmium/osm/item_type.hpp>
#include <osmium/osm/object.hpp>
#include <osmium/osm/types.hpp>
diff --git a/include/osmium/osm/box.hpp b/include/osmium/osm/box.hpp
index 6fcf48d..52ca93d 100644
--- a/include/osmium/osm/box.hpp
+++ b/include/osmium/osm/box.hpp
@@ -36,7 +36,6 @@ DEALINGS IN THE SOFTWARE.
#include <cassert>
#include <iosfwd>
-#include <osmium/util/compatibility.hpp>
#include <osmium/osm/location.hpp>
namespace osmium {
diff --git a/include/osmium/osm/changeset.hpp b/include/osmium/osm/changeset.hpp
index 0ec994c..8a503ca 100644
--- a/include/osmium/osm/changeset.hpp
+++ b/include/osmium/osm/changeset.hpp
@@ -33,7 +33,9 @@ DEALINGS IN THE SOFTWARE.
*/
+#include <cstdint>
#include <cstring>
+#include <iterator>
#include <osmium/memory/collection.hpp>
#include <osmium/memory/item.hpp>
@@ -185,6 +187,11 @@ namespace osmium {
public:
+ // Dummy to avoid warning because of unused private fields. Do not use.
+ int32_t do_not_use() const noexcept {
+ return m_padding1 + m_padding2;
+ }
+
/// Get ID of this changeset
changeset_id_type id() const noexcept {
return m_id;
diff --git a/include/osmium/osm/crc.hpp b/include/osmium/osm/crc.hpp
index e7c233a..2abeac4 100644
--- a/include/osmium/osm/crc.hpp
+++ b/include/osmium/osm/crc.hpp
@@ -36,11 +36,17 @@ DEALINGS IN THE SOFTWARE.
#include <cstdint>
#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/node_ref_list.hpp>
+#include <osmium/osm/object.hpp>
#include <osmium/osm/relation.hpp>
+#include <osmium/osm/tag.hpp>
+#include <osmium/osm/timestamp.hpp>
#include <osmium/osm/way.hpp>
#include <osmium/util/endian.hpp>
@@ -71,8 +77,8 @@ namespace osmium {
# if defined(__GNUC__) || defined(__clang__)
return __builtin_bswap64(value);
# else
- uint64_t val1 = byte_swap_32(value & 0xFFFFFFFF);
- uint64_t val2 = byte_swap_32(value >> 32);
+ const uint64_t val1 = byte_swap_32(value & 0xFFFFFFFF);
+ const uint64_t val2 = byte_swap_32(value >> 32);
return (val1 << 32) | val2;
# endif
}
@@ -86,11 +92,11 @@ namespace osmium {
public:
- TCRC& operator()() {
+ TCRC& operator()() noexcept {
return m_crc;
}
- const TCRC& operator()() const {
+ const TCRC& operator()() const noexcept {
return m_crc;
}
@@ -106,7 +112,7 @@ namespace osmium {
#if __BYTE_ORDER == __LITTLE_ENDIAN
m_crc.process_bytes(&value, sizeof(uint16_t));
#else
- uint16_t v = osmium::util::byte_swap_16(value);
+ const uint16_t v = osmium::util::byte_swap_16(value);
m_crc.process_bytes(&v, sizeof(uint16_t));
#endif
}
@@ -115,7 +121,7 @@ namespace osmium {
#if __BYTE_ORDER == __LITTLE_ENDIAN
m_crc.process_bytes(&value, sizeof(uint32_t));
#else
- uint32_t v = osmium::util::byte_swap_32(value);
+ const uint32_t v = osmium::util::byte_swap_32(value);
m_crc.process_bytes(&v, sizeof(uint32_t));
#endif
}
@@ -124,7 +130,7 @@ namespace osmium {
#if __BYTE_ORDER == __LITTLE_ENDIAN
m_crc.process_bytes(&value, sizeof(uint64_t));
#else
- uint64_t v = osmium::util::byte_swap_64(value);
+ const uint64_t v = osmium::util::byte_swap_64(value);
m_crc.process_bytes(&v, sizeof(uint64_t));
#endif
}
@@ -206,10 +212,10 @@ namespace osmium {
void update(const osmium::Area& area) {
update(static_cast<const osmium::OSMObject&>(area));
- for (auto it = area.cbegin(); it != area.cend(); ++it) {
- if (it->type() == osmium::item_type::outer_ring ||
- it->type() == osmium::item_type::inner_ring) {
- update(static_cast<const osmium::NodeRefList&>(*it));
+ for (const auto& subitem : area) {
+ if (subitem.type() == osmium::item_type::outer_ring ||
+ subitem.type() == osmium::item_type::inner_ring) {
+ update(static_cast<const osmium::NodeRefList&>(subitem));
}
}
}
diff --git a/include/osmium/osm/diff_object.hpp b/include/osmium/osm/diff_object.hpp
index 609ab74..21cf139 100644
--- a/include/osmium/osm/diff_object.hpp
+++ b/include/osmium/osm/diff_object.hpp
@@ -35,7 +35,6 @@ DEALINGS IN THE SOFTWARE.
#include <cassert>
-#include <osmium/fwd.hpp>
#include <osmium/osm/item_type.hpp>
#include <osmium/osm/object.hpp>
#include <osmium/osm/timestamp.hpp>
@@ -43,6 +42,10 @@ DEALINGS IN THE SOFTWARE.
namespace osmium {
+ class Node;
+ class Way;
+ class Relation;
+
/**
* A DiffObject holds pointers to three OSMObjects, the current object,
* the previous, and the next. They always have the same type (Node, Way,
diff --git a/include/osmium/osm/location.hpp b/include/osmium/osm/location.hpp
index b8a4660..c5da620 100644
--- a/include/osmium/osm/location.hpp
+++ b/include/osmium/osm/location.hpp
@@ -35,19 +35,14 @@ DEALINGS IN THE SOFTWARE.
#include <cmath>
#include <cstdint>
+#include <cstring>
#include <functional>
-#include <iomanip>
#include <iosfwd>
-#include <locale>
-#include <sstream>
+#include <iterator>
+#include <limits>
#include <stdexcept>
#include <string>
-#include <iostream>
-
-#include <osmium/util/compatibility.hpp>
-#include <osmium/util/double.hpp>
-
namespace osmium {
/**
@@ -70,41 +65,20 @@ namespace osmium {
constexpr const int coordinate_precision = 10000000;
- // Fallback function used when a coordinate is written in scientific
- // notation. This function uses stringstream and is much more expensive
- // than the handcrafted one. But coordinates in scientific notations
- // shouldn't be used anyway.
- inline int32_t string_to_location_coordinate_fallback(const char* str) {
- double value;
- std::istringstream ss{str};
- ss.imbue(std::locale("C"));
- ss >> std::noskipws >> value;
-
- if (ss.fail() || !ss.eof() || ss.bad() || value > 215.0 || value < -215.0) {
- throw invalid_location{std::string{"wrong format for coordinate: '"} + str + "'"};
- }
-
- return std::round(value * coordinate_precision);
- }
-
// Convert string with a floating point number into integer suitable
// for use as coordinate in a Location.
- inline int32_t string_to_location_coordinate(const char* str) {
+ inline int32_t string_to_location_coordinate(const char** data) {
+ const char* str = *data;
const char* full = str;
- // call fallback if scientific notation is used
- while (*str) {
- if (*str == 'e' || *str == 'E') {
- return string_to_location_coordinate_fallback(full);
- }
- ++str;
- }
+ int64_t result = 0;
+ int sign = 1;
- str = full;
+ // one more than significant digits to allow rounding
+ int64_t scale = 8;
- int32_t result = 0;
- int sign = 1;
- int scale = 7;
+ // paranoia check for maximum number of digits
+ int max_digits = 10;
// optional minus sign
if (*str == '-') {
@@ -112,7 +86,7 @@ namespace osmium {
++str;
}
- // first digit before decimal point
+ // there has to be at least one digit
if (*str >= '0' && *str <= '9') {
result = *str - '0';
++str;
@@ -120,55 +94,91 @@ namespace osmium {
goto error;
}
- // optional second digit before decimal point
- if (*str >= '0' && *str <= '9') {
- result = result * 10 + *str - '0';
+ // optional additional digits before decimal point
+ while (*str >= '0' && *str <= '9' && max_digits > 0) {
+ result = result * 10 + (*str - '0');
++str;
+ --max_digits;
+ }
- // optional third digit before decimal point
- if (*str >= '0' && *str <= '9') {
- result = result * 10 + *str - '0';
- ++str;
- }
+ if (max_digits == 0) {
+ goto error;
}
- if (*str != '\0') {
+ // optional decimal point
+ if (*str == '.') {
+ ++str;
+
+ // read significant digits
+ for (; scale > 0 && *str >= '0' && *str <= '9'; --scale, ++str) {
+ result = result * 10 + (*str - '0');
+ }
+
+ // ignore non-significant digits
+ max_digits = 20;
+ while (*str >= '0' && *str <= '9' && max_digits > 0) {
+ ++str;
+ --max_digits;
+ }
- // decimal point
- if (*str != '.') {
+ if (max_digits == 0) {
goto error;
}
+ }
+ // optional exponent in scientific notation
+ if (*str == 'e' || *str == 'E') {
++str;
- // read significant digits
- for (; scale > 0 && *str >= '0' && *str <= '9'; --scale, ++str) {
- result = result * 10 + (*str - '0');
+ int esign = 1;
+ // optional minus sign
+ if (*str == '-') {
+ esign = -1;
+ ++str;
}
- // use 8th digit after decimal point for rounding
- if (scale == 0 && *str >= '5' && *str <= '9') {
- ++result;
+ int64_t eresult = 0;
+
+ // there has to be at least one digit in exponent
+ if (*str >= '0' && *str <= '9') {
+ eresult = *str - '0';
++str;
+ } else {
+ goto error;
}
- // ignore further digits
- while (*str >= '0' && *str <= '9') {
+ // optional additional digits in exponent
+ max_digits = 5;
+ while (*str >= '0' && *str <= '9' && max_digits > 0) {
+ eresult = eresult * 10 + (*str - '0');
++str;
+ --max_digits;
}
- // should be at the end now
- if (*str != '\0') {
+ if (max_digits == 0) {
goto error;
}
+ scale += eresult * esign;
}
- for (; scale > 0; --scale) {
- result *= 10;
+ if (scale < 0) {
+ result = 0;
+ } else {
+ for (; scale > 0; --scale) {
+ result *= 10;
+ }
+
+ result = (result + 5) / 10 * sign;
+
+ if (result > std::numeric_limits<int32_t>::max() ||
+ result < std::numeric_limits<int32_t>::min()) {
+ goto error;
+ }
}
- return result * sign;
+ *data = str;
+ return static_cast<int32_t>(result);
error:
@@ -391,12 +401,30 @@ namespace osmium {
return *this;
}
- Location& set_lon(const char* str) noexcept {
+ Location& set_lon(const char* str) {
+ const char** data = &str;
+ m_x = detail::string_to_location_coordinate(data);
+ if (**data != '\0') {
+ throw invalid_location{std::string{"characters after coordinate: '"} + *data + "'"};
+ }
+ return *this;
+ }
+
+ Location& set_lat(const char* str) {
+ const char** data = &str;
+ m_y = detail::string_to_location_coordinate(data);
+ if (**data != '\0') {
+ throw invalid_location{std::string{"characters after coordinate: '"} + *data + "'"};
+ }
+ return *this;
+ }
+
+ Location& set_lon_partial(const char** str) {
m_x = detail::string_to_location_coordinate(str);
return *this;
}
- Location& set_lat(const char* str) noexcept {
+ Location& set_lat_partial(const char** str) {
m_y = detail::string_to_location_coordinate(str);
return *this;
}
diff --git a/include/osmium/osm/node_ref_list.hpp b/include/osmium/osm/node_ref_list.hpp
index 84edc07..6cfdf22 100644
--- a/include/osmium/osm/node_ref_list.hpp
+++ b/include/osmium/osm/node_ref_list.hpp
@@ -39,6 +39,7 @@ DEALINGS IN THE SOFTWARE.
#include <osmium/memory/item.hpp>
#include <osmium/osm/item_type.hpp>
+#include <osmium/osm/location.hpp>
#include <osmium/osm/node_ref.hpp>
namespace osmium {
@@ -66,7 +67,7 @@ namespace osmium {
* Returns the number of NodeRefs in the collection.
*/
size_t size() const noexcept {
- auto size_node_refs = byte_size() - sizeof(NodeRefList);
+ const auto size_node_refs = byte_size() - sizeof(NodeRefList);
assert(size_node_refs % sizeof(NodeRef) == 0);
return size_node_refs / sizeof(NodeRef);
}
diff --git a/include/osmium/osm/object.hpp b/include/osmium/osm/object.hpp
index a373156..caa6fbc 100644
--- a/include/osmium/osm/object.hpp
+++ b/include/osmium/osm/object.hpp
@@ -33,8 +33,6 @@ DEALINGS IN THE SOFTWARE.
*/
-#include <cstddef>
-#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <stdexcept>
@@ -288,6 +286,20 @@ namespace osmium {
return *this;
}
+ /**
+ * Set the timestamp when this object last changed.
+ *
+ * @param timestamp Timestamp in ISO format.
+ * @returns Reference to object to make calls chainable.
+ */
+ OSMObject& set_timestamp(const char* timestamp) {
+ m_timestamp = detail::parse_timestamp(timestamp);
+ if (timestamp[20] != '\0') {
+ throw std::invalid_argument{"can not parse timestamp"};
+ }
+ return *this;
+ }
+
/// Get user name for this object.
const char* user() const noexcept {
return reinterpret_cast<const char*>(data() + sizeof_object());
@@ -313,8 +325,9 @@ namespace osmium {
*
* @param attr Name of the attribute (must be one of "id", "version", "changeset", "timestamp", "uid", "visible")
* @param value Value of the attribute
+ * @returns Reference to object to make calls chainable.
*/
- void set_attribute(const char* attr, const char* value) {
+ OSMObject& set_attribute(const char* attr, const char* value) {
if (!std::strcmp(attr, "id")) {
set_id(value);
} else if (!std::strcmp(attr, "version")) {
@@ -322,12 +335,14 @@ namespace osmium {
} else if (!std::strcmp(attr, "changeset")) {
set_changeset(value);
} else if (!std::strcmp(attr, "timestamp")) {
- set_timestamp(osmium::Timestamp(value));
+ set_timestamp(value);
} else if (!std::strcmp(attr, "uid")) {
set_uid(value);
} else if (!std::strcmp(attr, "visible")) {
set_visible(value);
}
+
+ return *this;
}
using iterator = osmium::memory::CollectionIterator<Item>;
diff --git a/include/osmium/osm/object_comparisons.hpp b/include/osmium/osm/object_comparisons.hpp
index a17d47d..aa0241d 100644
--- a/include/osmium/osm/object_comparisons.hpp
+++ b/include/osmium/osm/object_comparisons.hpp
@@ -33,7 +33,10 @@ DEALINGS IN THE SOFTWARE.
*/
+#include <tuple>
+
#include <osmium/osm/object.hpp>
+#include <osmium/osm/timestamp.hpp>
#include <osmium/util/misc.hpp>
namespace osmium {
diff --git a/include/osmium/osm/relation.hpp b/include/osmium/osm/relation.hpp
index 1ea0a5e..2aa9caa 100644
--- a/include/osmium/osm/relation.hpp
+++ b/include/osmium/osm/relation.hpp
@@ -33,13 +33,13 @@ DEALINGS IN THE SOFTWARE.
*/
-#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <iterator>
#include <osmium/memory/collection.hpp> // IWYU pragma: keep
#include <osmium/memory/item.hpp>
+#include <osmium/osm/entity.hpp>
#include <osmium/osm/item_type.hpp>
#include <osmium/osm/object.hpp>
#include <osmium/osm/types.hpp>
diff --git a/include/osmium/osm/segment.hpp b/include/osmium/osm/segment.hpp
index d35f970..c36533e 100644
--- a/include/osmium/osm/segment.hpp
+++ b/include/osmium/osm/segment.hpp
@@ -37,7 +37,6 @@ DEALINGS IN THE SOFTWARE.
#include <utility>
#include <osmium/osm/location.hpp>
-#include <osmium/util/compatibility.hpp>
namespace osmium {
diff --git a/include/osmium/osm/tag.hpp b/include/osmium/osm/tag.hpp
index d5415f7..cd2a913 100644
--- a/include/osmium/osm/tag.hpp
+++ b/include/osmium/osm/tag.hpp
@@ -35,7 +35,6 @@ DEALINGS IN THE SOFTWARE.
#include <algorithm>
#include <cassert>
-#include <cstddef>
#include <cstring>
#include <iosfwd>
#include <iterator>
diff --git a/include/osmium/osm/timestamp.hpp b/include/osmium/osm/timestamp.hpp
index 613752e..5f52430 100644
--- a/include/osmium/osm/timestamp.hpp
+++ b/include/osmium/osm/timestamp.hpp
@@ -40,12 +40,71 @@ DEALINGS IN THE SOFTWARE.
#include <limits>
#include <stdexcept>
#include <string>
+#include <type_traits>
#include <osmium/util/compatibility.hpp>
#include <osmium/util/minmax.hpp> // IWYU pragma: keep
namespace osmium {
+ namespace detail {
+
+ inline time_t parse_timestamp(const char* str) {
+ static const int mon_lengths[] = {
+ 31, 29, 31, 30, 31, 30,
+ 31, 31, 30, 31, 30, 31
+ };
+ if (str[ 0] >= '0' && str[ 0] <= '9' &&
+ str[ 1] >= '0' && str[ 1] <= '9' &&
+ str[ 2] >= '0' && str[ 2] <= '9' &&
+ str[ 3] >= '0' && str[ 3] <= '9' &&
+ str[ 4] == '-' &&
+ str[ 5] >= '0' && str[ 5] <= '9' &&
+ str[ 6] >= '0' && str[ 6] <= '9' &&
+ str[ 7] == '-' &&
+ str[ 8] >= '0' && str[ 8] <= '9' &&
+ str[ 9] >= '0' && str[ 9] <= '9' &&
+ str[10] == 'T' &&
+ str[11] >= '0' && str[11] <= '9' &&
+ str[12] >= '0' && str[12] <= '9' &&
+ str[13] == ':' &&
+ str[14] >= '0' && str[14] <= '9' &&
+ str[15] >= '0' && str[15] <= '9' &&
+ str[16] == ':' &&
+ str[17] >= '0' && str[17] <= '9' &&
+ str[18] >= '0' && str[18] <= '9' &&
+ str[19] == 'Z') {
+ struct tm tm;
+ tm.tm_year = (str[ 0] - '0') * 1000 +
+ (str[ 1] - '0') * 100 +
+ (str[ 2] - '0') * 10 +
+ (str[ 3] - '0') - 1900;
+ tm.tm_mon = (str[ 5] - '0') * 10 + (str[ 6] - '0') - 1;
+ tm.tm_mday = (str[ 8] - '0') * 10 + (str[ 9] - '0');
+ tm.tm_hour = (str[11] - '0') * 10 + (str[12] - '0');
+ tm.tm_min = (str[14] - '0') * 10 + (str[15] - '0');
+ tm.tm_sec = (str[17] - '0') * 10 + (str[18] - '0');
+ tm.tm_wday = 0;
+ tm.tm_yday = 0;
+ tm.tm_isdst = 0;
+ if (tm.tm_year >= 0 &&
+ tm.tm_mon >= 0 && tm.tm_mon <= 11 &&
+ tm.tm_mday >= 1 && tm.tm_mday <= mon_lengths[tm.tm_mon] &&
+ tm.tm_hour >= 0 && tm.tm_hour <= 23 &&
+ tm.tm_min >= 0 && tm.tm_min <= 59 &&
+ tm.tm_sec >= 0 && tm.tm_sec <= 60) {
+#ifndef _WIN32
+ return timegm(&tm);
+#else
+ return _mkgmtime(&tm);
+#endif
+ }
+ }
+ throw std::invalid_argument{"can not parse timestamp"};
+ }
+
+ } // namespace detail
+
/**
* A timestamp. Internal representation is an unsigned 32bit integer
* holding seconds since epoch (1970-01-01T00:00:00Z), so this will
@@ -56,7 +115,7 @@ namespace osmium {
class Timestamp {
// length of ISO timestamp string yyyy-mm-ddThh:mm:ssZ\0
- static constexpr int timestamp_length = 20 + 1;
+ static constexpr const int timestamp_length = 20 + 1;
// The timestamp format for OSM timestamps in strftime(3) format.
// This is the ISO-Format "yyyy-mm-ddThh:mm:ssZ".
@@ -97,27 +156,7 @@ namespace osmium {
* @throws std::invalid_argument if the timestamp can not be parsed.
*/
explicit Timestamp(const char* timestamp) {
-#ifndef _WIN32
- struct tm tm {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
- };
- if (strptime(timestamp, timestamp_format(), &tm) == nullptr) {
- throw std::invalid_argument("can't parse timestamp");
- }
- m_timestamp = static_cast<uint32_t>(timegm(&tm));
-#else
- struct tm tm;
- int n = sscanf(timestamp, "%4d-%2d-%2dT%2d:%2d:%2dZ", &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
- if (n != 6) {
- throw std::invalid_argument("can't parse timestamp");
- }
- tm.tm_year -= 1900;
- tm.tm_mon--;
- tm.tm_wday = 0;
- tm.tm_yday = 0;
- tm.tm_isdst = 0;
- m_timestamp = static_cast<uint32_t>(_mkgmtime(&tm));
-#endif
+ m_timestamp = static_cast<uint32_t>(detail::parse_timestamp(timestamp));
}
/**
diff --git a/include/osmium/osm/types_from_string.hpp b/include/osmium/osm/types_from_string.hpp
index d5da72b..190dd29 100644
--- a/include/osmium/osm/types_from_string.hpp
+++ b/include/osmium/osm/types_from_string.hpp
@@ -35,13 +35,14 @@ DEALINGS IN THE SOFTWARE.
#include <cassert>
#include <cctype>
-#include <cstdint>
#include <cstdlib>
#include <limits>
+#include <stdexcept>
#include <string>
#include <utility>
#include <osmium/osm/entity_bits.hpp>
+#include <osmium/osm/item_type.hpp>
#include <osmium/osm/types.hpp>
#include <osmium/util/cast.hpp>
diff --git a/include/osmium/osm/way.hpp b/include/osmium/osm/way.hpp
index 3bc30b0..f6713fe 100644
--- a/include/osmium/osm/way.hpp
+++ b/include/osmium/osm/way.hpp
@@ -33,12 +33,13 @@ DEALINGS IN THE SOFTWARE.
*/
+#include <osmium/memory/collection.hpp>
#include <osmium/memory/item.hpp>
+#include <osmium/osm/entity.hpp>
#include <osmium/osm/item_type.hpp>
-#include <osmium/osm/object.hpp>
-#include <osmium/osm/types.hpp>
#include <osmium/osm/node_ref.hpp>
#include <osmium/osm/node_ref_list.hpp>
+#include <osmium/osm/object.hpp>
namespace osmium {
diff --git a/include/osmium/relations/collector.hpp b/include/osmium/relations/collector.hpp
index 166b00d..b8455b4 100644
--- a/include/osmium/relations/collector.hpp
+++ b/include/osmium/relations/collector.hpp
@@ -39,13 +39,12 @@ DEALINGS IN THE SOFTWARE.
#include <cstdint>
#include <functional>
#include <iomanip>
-//#include <iostream>
+#include <iostream>
#include <vector>
-#include <osmium/fwd.hpp>
#include <osmium/osm/item_type.hpp>
#include <osmium/osm/object.hpp>
-#include <osmium/osm/relation.hpp> // IWYU pragma: keep
+#include <osmium/osm/relation.hpp>
#include <osmium/osm/types.hpp>
#include <osmium/handler.hpp>
#include <osmium/memory/buffer.hpp>
@@ -57,6 +56,9 @@ DEALINGS IN THE SOFTWARE.
namespace osmium {
+ class Node;
+ class Way;
+
/**
* @brief Code related to the assembly of OSM relations
*/
@@ -106,7 +108,7 @@ namespace osmium {
public:
- HandlerPass1(TCollector& collector) noexcept :
+ explicit HandlerPass1(TCollector& collector) noexcept :
m_collector(collector) {
}
@@ -129,7 +131,7 @@ namespace osmium {
public:
- HandlerPass2(TCollector& collector) noexcept :
+ explicit HandlerPass2(TCollector& collector) noexcept :
m_collector(collector) {
}
@@ -430,7 +432,7 @@ namespace osmium {
const osmium::Relation& relation = get_relation(relation_meta);
for (const auto& member : relation.members()) {
if (member.ref() != 0) {
- auto range = find_member_meta(member.type(), member.ref());
+ const auto range = find_member_meta(member.type(), member.ref());
assert(!range.empty());
// if this is the last time this object was needed
diff --git a/include/osmium/relations/detail/member_meta.hpp b/include/osmium/relations/detail/member_meta.hpp
index fb71416..b28dca1 100644
--- a/include/osmium/relations/detail/member_meta.hpp
+++ b/include/osmium/relations/detail/member_meta.hpp
@@ -33,10 +33,8 @@ DEALINGS IN THE SOFTWARE.
*/
-#include <algorithm>
#include <cstddef>
#include <iosfwd>
-#include <iterator>
#include <osmium/osm/types.hpp>
diff --git a/include/osmium/tags/filter.hpp b/include/osmium/tags/filter.hpp
index 7451737..27a8360 100644
--- a/include/osmium/tags/filter.hpp
+++ b/include/osmium/tags/filter.hpp
@@ -33,6 +33,7 @@ DEALINGS IN THE SOFTWARE.
*/
+#include <cstddef>
#include <string>
#include <type_traits>
#include <vector>
diff --git a/include/osmium/tags/taglist.hpp b/include/osmium/tags/taglist.hpp
index b1f346f..d786279 100644
--- a/include/osmium/tags/taglist.hpp
+++ b/include/osmium/tags/taglist.hpp
@@ -34,7 +34,7 @@ DEALINGS IN THE SOFTWARE.
*/
#include <algorithm>
-#include <utility>
+#include <utility> // IWYU pragma: keep
#include <osmium/osm/tag.hpp>
diff --git a/include/osmium/thread/pool.hpp b/include/osmium/thread/pool.hpp
index d1b74c1..613f227 100644
--- a/include/osmium/thread/pool.hpp
+++ b/include/osmium/thread/pool.hpp
@@ -34,9 +34,7 @@ DEALINGS IN THE SOFTWARE.
*/
#include <algorithm>
-#include <atomic>
#include <cstddef>
-#include <cstdlib>
#include <future>
#include <thread>
#include <type_traits>
@@ -79,7 +77,7 @@ namespace osmium {
}
inline size_t get_work_queue_size() noexcept {
- size_t n = osmium::config::get_max_queue_size("WORK", 10);
+ const size_t n = osmium::config::get_max_queue_size("WORK", 10);
return n > 2 ? n : 2;
}
diff --git a/include/osmium/thread/queue.hpp b/include/osmium/thread/queue.hpp
index 3124611..6f4f7b1 100644
--- a/include/osmium/thread/queue.hpp
+++ b/include/osmium/thread/queue.hpp
@@ -33,7 +33,6 @@ DEALINGS IN THE SOFTWARE.
*/
-#include <atomic>
#include <chrono>
#include <condition_variable>
#include <cstddef>
@@ -41,9 +40,10 @@ DEALINGS IN THE SOFTWARE.
#include <queue>
#include <string>
#include <thread>
-#include <utility> // IWYU pragma: keep (for std::move)
+#include <utility> // IWYU pragma: keep
#ifdef OSMIUM_DEBUG_QUEUE_SIZE
+# include <atomic>
# include <iostream>
#endif
diff --git a/include/osmium/thread/util.hpp b/include/osmium/thread/util.hpp
index 2ef331a..2eeb999 100644
--- a/include/osmium/thread/util.hpp
+++ b/include/osmium/thread/util.hpp
@@ -35,6 +35,8 @@ DEALINGS IN THE SOFTWARE.
#include <chrono>
#include <future>
+#include <thread>
+#include <utility>
#ifdef __linux__
# include <sys/prctl.h>
diff --git a/include/osmium/util/delta.hpp b/include/osmium/util/delta.hpp
index 51c5c7b..8894dd7 100644
--- a/include/osmium/util/delta.hpp
+++ b/include/osmium/util/delta.hpp
@@ -33,12 +33,11 @@ DEALINGS IN THE SOFTWARE.
*/
-#include <iterator>
+#include <cstdint>
#include <type_traits>
#include <utility>
#include <osmium/util/cast.hpp>
-#include <osmium/util/compatibility.hpp>
namespace osmium {
diff --git a/include/osmium/util/double.hpp b/include/osmium/util/double.hpp
index 1352c5f..9714bf6 100644
--- a/include/osmium/util/double.hpp
+++ b/include/osmium/util/double.hpp
@@ -35,7 +35,6 @@ DEALINGS IN THE SOFTWARE.
#include <algorithm>
#include <cassert>
-#include <cmath>
#include <cstdio>
#include <iterator>
#include <string>
@@ -44,7 +43,7 @@ namespace osmium {
namespace util {
- constexpr int max_double_length = 20; // should fit any double
+ constexpr const int max_double_length = 20; // should fit any double
/**
* Write double to iterator, removing superfluous '0' characters at
diff --git a/include/osmium/util/file.hpp b/include/osmium/util/file.hpp
index 86b93ff..4c951e7 100644
--- a/include/osmium/util/file.hpp
+++ b/include/osmium/util/file.hpp
@@ -36,6 +36,7 @@ DEALINGS IN THE SOFTWARE.
#include <cerrno>
#include <cstddef>
#include <cstdio>
+#include <string>
#include <system_error>
#include <sys/stat.h>
#include <sys/types.h>
@@ -47,9 +48,6 @@ DEALINGS IN THE SOFTWARE.
#ifndef _MSC_VER
# include <unistd.h>
-#else
-// https://msdn.microsoft.com/en-us/library/whx354w1.aspx
-# define ftruncate _chsize_s
#endif
#include <osmium/util/cast.hpp>
@@ -70,7 +68,7 @@ namespace osmium {
#ifdef _MSC_VER
// Windows implementation
// https://msdn.microsoft.com/en-us/library/dfbc2kec.aspx
- auto size = ::_filelengthi64(fd);
+ const auto size = ::_filelengthi64(fd);
if (size == -1L) {
throw std::system_error(errno, std::system_category(), "_filelengthi64 failed");
}
@@ -86,6 +84,44 @@ namespace osmium {
}
/**
+ * Get file size.
+ * This is a small wrapper around a system call.
+ *
+ * @param name File name
+ * @returns file size
+ * @throws std::system_error If system call failed
+ */
+ inline size_t file_size(const char* name) {
+#ifdef _MSC_VER
+ // Windows implementation
+ // https://msdn.microsoft.com/en-us/library/14h5k7ff.aspx
+ struct _stat64 s;
+ if (::_stati64(name, &s) != 0) {
+ throw std::system_error(errno, std::system_category(), "_stati64 failed");
+ }
+#else
+ // Unix implementation
+ struct stat s;
+ if (::stat(name, &s) != 0) {
+ throw std::system_error(errno, std::system_category(), "stat failed");
+ }
+#endif
+ return size_t(s.st_size);
+ }
+
+ /**
+ * Get file size.
+ * This is a small wrapper around a system call.
+ *
+ * @param name File name
+ * @returns file size
+ * @throws std::system_error If system call failed
+ */
+ inline size_t file_size(const std::string& name) {
+ return file_size(name.c_str());
+ }
+
+ /**
* Resize file.
* Small wrapper around ftruncate(2) system call.
*
@@ -94,8 +130,13 @@ namespace osmium {
* @throws std::system_error If ftruncate(2) call failed
*/
inline void resize_file(int fd, size_t new_size) {
+#ifdef _WIN32
+ // https://msdn.microsoft.com/en-us/library/whx354w1.aspx
+ if (::_chsize_s(fd, static_cast_with_assert<__int64>(new_size)) != 0) {
+#else
if (::ftruncate(fd, static_cast_with_assert<off_t>(new_size)) != 0) {
- throw std::system_error(errno, std::system_category(), "ftruncate failed");
+#endif
+ throw std::system_error(errno, std::system_category(), "resizing file failed");
}
}
@@ -114,6 +155,37 @@ namespace osmium {
#endif
}
+ /**
+ * Get current offset into file.
+ *
+ * @param fd Open file descriptor.
+ * @returns File offset or 0 if it is not available.
+ */
+ inline size_t file_offset(int fd) {
+#ifdef _MSC_VER
+ // https://msdn.microsoft.com/en-us/library/1yee101t.aspx
+ auto offset = _lseeki64(fd, 0, SEEK_CUR);
+#else
+ auto offset = ::lseek(fd, 0, SEEK_CUR);
+#endif
+ if (offset == -1) {
+ return 0;
+ }
+ return size_t(offset);
+ }
+
+ /**
+ * Check whether the file descriptor refers to a TTY.
+ */
+ inline bool isatty(int fd) {
+#ifdef _MSC_VER
+ // https://msdn.microsoft.com/en-us/library/f4s0ddew.aspx
+ return _isatty(fd) != 0;
+#else
+ return ::isatty(fd) != 0;
+#endif
+ }
+
} // namespace util
} // namespace osmium
diff --git a/include/osmium/util/iterator.hpp b/include/osmium/util/iterator.hpp
index 15f3f3d..42d23e8 100644
--- a/include/osmium/util/iterator.hpp
+++ b/include/osmium/util/iterator.hpp
@@ -34,6 +34,7 @@ DEALINGS IN THE SOFTWARE.
*/
#include <cstddef>
+#include <type_traits>
#include <utility>
namespace osmium {
@@ -43,7 +44,7 @@ namespace osmium {
using iterator = It;
- iterator_range(P&& p) :
+ explicit iterator_range(P&& p) :
P(std::forward<P>(p)) {
}
/*
diff --git a/include/osmium/util/memory_mapping.hpp b/include/osmium/util/memory_mapping.hpp
index cf28e6a..4fc8f01 100644
--- a/include/osmium/util/memory_mapping.hpp
+++ b/include/osmium/util/memory_mapping.hpp
@@ -35,6 +35,7 @@ DEALINGS IN THE SOFTWARE.
#include <cassert>
#include <cerrno>
+#include <cstddef>
#include <stdexcept>
#include <system_error>
@@ -214,7 +215,7 @@ private:
~MemoryMapping() noexcept {
try {
unmap();
- } catch (std::system_error&) {
+ } catch (const std::system_error&) {
// Ignore any exceptions because destructor must not throw.
}
}
@@ -302,7 +303,7 @@ private:
public:
- AnonymousMemoryMapping(size_t size) :
+ explicit AnonymousMemoryMapping(size_t size) :
MemoryMapping(size, mapping_mode::write_private) {
}
@@ -338,7 +339,7 @@ private:
* @param size Number of objects of type T to be mapped
* @throws std::system_error if the mapping fails
*/
- TypedMemoryMapping(size_t size) :
+ explicit TypedMemoryMapping(size_t size) :
m_mapping(sizeof(T) * size, MemoryMapping::mapping_mode::write_private) {
}
@@ -487,7 +488,7 @@ private:
public:
- AnonymousTypedMemoryMapping(size_t size) :
+ explicit AnonymousTypedMemoryMapping(size_t size) :
TypedMemoryMapping<T>(size) {
}
diff --git a/include/osmium/util/options.hpp b/include/osmium/util/options.hpp
index 9b00b48..79818a9 100644
--- a/include/osmium/util/options.hpp
+++ b/include/osmium/util/options.hpp
@@ -33,6 +33,7 @@ DEALINGS IN THE SOFTWARE.
*/
+#include <cstddef>
#include <initializer_list>
#include <map>
#include <string>
@@ -107,7 +108,7 @@ namespace osmium {
* be set to "true".
*/
void set(std::string data) {
- size_t pos = data.find_first_of('=');
+ const size_t pos = data.find_first_of('=');
if (pos == std::string::npos) {
m_options[data] = "true";
} else {
@@ -122,7 +123,7 @@ namespace osmium {
* empty string) is returned.
*/
std::string get(const std::string& key, const std::string& default_value="") const noexcept {
- auto it = m_options.find(key);
+ const auto it = m_options.find(key);
if (it == m_options.end()) {
return default_value;
}
@@ -134,7 +135,7 @@ namespace osmium {
* Will return false if the value is unset.
*/
bool is_true(const std::string& key) const noexcept {
- std::string value = get(key);
+ const std::string value = get(key);
return (value == "true" || value == "yes");
}
@@ -143,7 +144,7 @@ namespace osmium {
* Will return true if the value is unset.
*/
bool is_not_false(const std::string& key) const noexcept {
- std::string value = get(key);
+ const std::string value = get(key);
return !(value == "false" || value == "no");
}
diff --git a/include/osmium/util/progress_bar.hpp b/include/osmium/util/progress_bar.hpp
new file mode 100644
index 0000000..814aa2c
--- /dev/null
+++ b/include/osmium/util/progress_bar.hpp
@@ -0,0 +1,179 @@
+#ifndef OSMIUM_UTIL_PROGRESS_BAR_HPP
+#define OSMIUM_UTIL_PROGRESS_BAR_HPP
+
+/*
+
+This file is part of Osmium (http://osmcode.org/libosmium).
+
+Copyright 2013-2016 Jochen Topf <jochen at topf.org> and others (see README).
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <iostream>
+
+namespace osmium {
+
+ /**
+ * Displays a progress bar on STDERR. Can be used together with the
+ * osmium::io::Reader class for instance.
+ */
+ class ProgressBar {
+
+ static const char* bar() noexcept {
+ return "======================================================================";
+ }
+
+ static const char* spc() noexcept {
+ return " ";
+ }
+
+ static constexpr const size_t length = 70;
+
+ // The max size is the file size if there is a single file and the
+ // sum of all file sizes if there are multiple files. It corresponds
+ // to 100%.
+ size_t m_max_size;
+
+ // The sum of the file sizes already done.
+ size_t m_done_size = 0;
+
+ // The currently read size in the current file.
+ size_t m_current_size = 0;
+
+ // The percentage calculated when it was last displayed. Used to decide
+ // whether we need to update the display. Start setting is one that
+ // will always be different from any legal setting.
+ size_t m_prev_percent = 100 + 1;
+
+ // Is the progress bar enabled at all?
+ bool m_enable;
+
+ // Used to make sure we do cleanup in the destructor if it was not
+ // already done.
+ bool m_do_cleanup = true;
+
+ void display() {
+ const size_t percent = 100 * (m_done_size + m_current_size) / m_max_size;
+ if (m_prev_percent == percent) {
+ return;
+ }
+ m_prev_percent = percent;
+
+ const size_t num = size_t(percent * (length / 100.0));
+ std::cerr << '[';
+ if (num >= length) {
+ std::cerr << bar();
+ } else {
+ std::cerr << (bar() + length - num) << '>' << (spc() + num);
+ }
+ std::cerr << "] ";
+ if (percent < 10) {
+ std::cerr << ' ';
+ }
+ if (percent < 100) {
+ std::cerr << ' ';
+ }
+ std::cerr << percent << "% \r";
+ }
+
+ public:
+
+ /**
+ * Initializes the progress bar. No output yet.
+ *
+ * @param max_size Max size equivalent to 100%.
+ * @param enable Set to false to disable (for instance if stderr is
+ * not a TTY).
+ */
+ ProgressBar(size_t max_size, bool enable) noexcept :
+ m_max_size(max_size),
+ m_enable(max_size > 0 && enable) {
+ }
+
+ ~ProgressBar() {
+ if (m_do_cleanup) {
+ try {
+ done();
+ } catch (...) {
+ // Swallow any exceptions, because a destructor should
+ // not throw.
+ }
+ }
+ }
+
+ /**
+ * Call this function to update the progress bar. Actual update will
+ * only happen if the percentage changed from the last time this
+ * function was called.
+ *
+ * @param current_size Current size. Used together with the max_size
+ * from constructor to calculate the percentage.
+ */
+ void update(size_t current_size) {
+ if (!m_enable) {
+ return;
+ }
+
+ m_current_size = current_size;
+
+ display();
+ }
+
+ /**
+ * If you are reading multiple files, call this function after each
+ * file is finished.
+ *
+ * @param file_size The size of the file just finished.
+ */
+ void file_done(size_t file_size) {
+ if (m_enable) {
+ m_done_size += file_size;
+ m_current_size = 0;
+ display();
+ }
+ }
+
+ /**
+ * Call this at the end. Will update the progress bar to 100% and
+ * print a final line feed. If this is not called explicitly the
+ * destructor will also call this.
+ */
+ void done() {
+ m_do_cleanup = false;
+ if (m_enable) {
+ m_done_size = m_max_size;
+ m_current_size = 0;
+ display();
+ std::cerr << '\n';
+ }
+ }
+
+ }; // class ProgressBar
+
+} // namespace osmium
+
+#endif // OSMIUM_UTIL_PROGRESS_BAR_HPP
diff --git a/include/osmium/util/string.hpp b/include/osmium/util/string.hpp
index 1198288..2cdb983 100644
--- a/include/osmium/util/string.hpp
+++ b/include/osmium/util/string.hpp
@@ -33,9 +33,9 @@ DEALINGS IN THE SOFTWARE.
*/
+#include <cstddef>
#include <string>
#include <vector>
-#include <iostream>
namespace osmium {
diff --git a/include/osmium/util/verbose_output.hpp b/include/osmium/util/verbose_output.hpp
index c7677a4..f85d265 100644
--- a/include/osmium/util/verbose_output.hpp
+++ b/include/osmium/util/verbose_output.hpp
@@ -33,11 +33,11 @@ DEALINGS IN THE SOFTWARE.
*/
-#include <time.h>
-
+#include <ctime>
#include <iomanip>
#include <iostream>
#include <sstream>
+#include <string>
namespace osmium {
@@ -75,9 +75,9 @@ namespace osmium {
*/
void start_line() {
if (m_newline) {
- time_t elapsed = runtime();
+ const time_t elapsed = runtime();
- char old_fill = std::cerr.fill();
+ const char old_fill = std::cerr.fill();
std::cerr << '[' << std::setw(2) << (elapsed / 60) << ':' << std::setw(2) << std::setfill('0') << (elapsed % 60) << "] ";
std::cerr.fill(old_fill);
diff --git a/include/osmium/version.hpp b/include/osmium/version.hpp
index ac7a94f..6f3b0a3 100644
--- a/include/osmium/version.hpp
+++ b/include/osmium/version.hpp
@@ -34,9 +34,9 @@ DEALINGS IN THE SOFTWARE.
*/
#define LIBOSMIUM_VERSION_MAJOR 2
-#define LIBOSMIUM_VERSION_MINOR 8
+#define LIBOSMIUM_VERSION_MINOR 9
#define LIBOSMIUM_VERSION_PATCH 0
-#define LIBOSMIUM_VERSION_STRING "2.8.0"
+#define LIBOSMIUM_VERSION_STRING "2.9.0"
#endif // OSMIUM_VERSION_HPP
diff --git a/include/protozero/iterators.hpp b/include/protozero/iterators.hpp
index 813d96b..00ba919 100644
--- a/include/protozero/iterators.hpp
+++ b/include/protozero/iterators.hpp
@@ -76,12 +76,12 @@ public:
/**
* Create iterator range from two iterators.
*
- * @param first Iterator to beginning or range.
- * @param last Iterator to end or range.
+ * @param first_iterator Iterator to beginning or range.
+ * @param last_iterator Iterator to end or range.
*/
- constexpr iterator_range(iterator&& first, iterator&& last) :
- P(std::forward<iterator>(first),
- std::forward<iterator>(last)) {
+ constexpr iterator_range(iterator&& first_iterator, iterator&& last_iterator) :
+ P(std::forward<iterator>(first_iterator),
+ std::forward<iterator>(last_iterator)) {
}
/// Return iterator to beginning of range.
diff --git a/include/protozero/pbf_writer.hpp b/include/protozero/pbf_writer.hpp
index 3ce0f14..bce1c3f 100644
--- a/include/protozero/pbf_writer.hpp
+++ b/include/protozero/pbf_writer.hpp
@@ -156,12 +156,16 @@ class pbf_writer {
// The number of bytes to reserve for the varint holding the length of
// a length-delimited field. The length has to fit into pbf_length_type,
// and a varint needs 8 bit for every 7 bit.
- static constexpr const int reserve_bytes = sizeof(pbf_length_type) * 8 / 7 + 1;
+ enum constant_reserve_bytes : int {
+ reserve_bytes = sizeof(pbf_length_type) * 8 / 7 + 1
+ };
// If m_rollpack_pos is set to this special value, it means that when
// the submessage is closed, nothing needs to be done, because the length
// of the submessage has already been written correctly.
- static constexpr const std::size_t size_is_known = std::numeric_limits<std::size_t>::max();
+ enum constant_size_is_known : std::size_t {
+ size_is_known = std::numeric_limits<std::size_t>::max()
+ };
void open_submessage(pbf_tag_type tag, std::size_t size) {
protozero_assert(m_pos == 0);
diff --git a/include/protozero/version.hpp b/include/protozero/version.hpp
index d427941..127e649 100644
--- a/include/protozero/version.hpp
+++ b/include/protozero/version.hpp
@@ -23,13 +23,13 @@ documentation.
#define PROTOZERO_VERSION_MINOR 4
/// The patch number
-#define PROTOZERO_VERSION_PATCH 0
+#define PROTOZERO_VERSION_PATCH 2
/// The complete version number
#define PROTOZERO_VERSION_CODE (PROTOZERO_VERSION_MAJOR * 10000 + PROTOZERO_VERSION_MINOR * 100 + PROTOZERO_VERSION_PATCH)
/// Version number as string
-#define PROTOZERO_VERSION_STRING "1.4.0"
+#define PROTOZERO_VERSION_STRING "1.4.2"
#endif // PROTOZERO_VERSION_HPP
diff --git a/osmium.imp b/osmium.imp
index c45794d..77c5c37 100644
--- a/osmium.imp
+++ b/osmium.imp
@@ -2,10 +2,15 @@
#
# Configuration for Include-What-You-Use tool
#
-# https://code.google.com/p/include-what-you-use/
+# http://include-what-you-use.org/
#
#-----------------------------------------------------------------------------
[
{ "include": ["<bits/fcntl-linux.h>", "private", "<fcntl.h>", "public"] },
- { "include": ["<sys/types.h>", "public", "<cstdint>", "public"] }
+ { "include": ["<bits/shared_ptr.h>", "private", "<memory>", "public"] },
+ { "include": ["<sys/types.h>", "public", "<cstdint>", "public"] },
+ { "include": ['"utf8/checked.h"', "private", "<utf8.h>", "public"] },
+ { "include": ['"utf8/unchecked.h"', "private", "<utf8.h>", "public"] },
+ { "include": ["<expat_external.h>", "public", "<expat.h>", "public"] },
+ { "include": ["<zconf.h>", "public", "<zlib.h>", "public"] }
]
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index f7b35e8..6230cde 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -127,6 +127,7 @@ endif()
add_unit_test(area test_area_id)
add_unit_test(area test_node_ref_segment)
+add_unit_test(basic test_area)
add_unit_test(basic test_box)
add_unit_test(basic test_changeset)
add_unit_test(basic test_crc)
@@ -170,6 +171,7 @@ add_unit_test(io test_file_formats)
add_unit_test(io test_reader LIBS "${OSMIUM_XML_LIBRARIES};${OSMIUM_PBF_LIBRARIES}")
add_unit_test(io test_reader_with_mock_decompression ENABLE_IF ${Threads_FOUND} LIBS ${OSMIUM_XML_LIBRARIES})
add_unit_test(io test_reader_with_mock_parser ENABLE_IF ${Threads_FOUND} LIBS ${CMAKE_THREAD_LIBS_INIT})
+add_unit_test(io test_opl_parser)
add_unit_test(io test_output_utils)
add_unit_test(io test_output_iterator ENABLE_IF ${Threads_FOUND} LIBS ${CMAKE_THREAD_LIBS_INIT})
add_unit_test(io test_string_table)
diff --git a/test/data-tests/include/common.hpp b/test/data-tests/include/common.hpp
index a6fd3df..4dad07d 100644
--- a/test/data-tests/include/common.hpp
+++ b/test/data-tests/include/common.hpp
@@ -10,9 +10,9 @@
#include <osmium/io/xml_input.hpp>
#include <osmium/visitor.hpp>
-typedef osmium::index::map::Dummy<osmium::unsigned_object_id_type, osmium::Location> index_neg_type;
-typedef osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, osmium::Location> index_pos_type;
-typedef osmium::handler::NodeLocationsForWays<index_pos_type, index_neg_type> location_handler_type;
+using index_neg_type = osmium::index::map::Dummy<osmium::unsigned_object_id_type, osmium::Location>;
+using index_pos_type = osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, osmium::Location>;
+using location_handler_type = osmium::handler::NodeLocationsForWays<index_pos_type, index_neg_type>;
#include "check_basics_handler.hpp"
#include "check_wkt_handler.hpp"
diff --git a/test/data-tests/testdata-multipolygon.cpp b/test/data-tests/testdata-multipolygon.cpp
index 6a863c8..6d0328c 100644
--- a/test/data-tests/testdata-multipolygon.cpp
+++ b/test/data-tests/testdata-multipolygon.cpp
@@ -1,7 +1,9 @@
+#include <cstring>
#include <iostream>
#include <fstream>
#include <map>
+#include <string>
#include <gdalcpp.hpp>
@@ -17,21 +19,20 @@
#include <osmium/io/xml_input.hpp>
#include <osmium/visitor.hpp>
-typedef osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, osmium::Location> index_type;
-
-typedef osmium::handler::NodeLocationsForWays<index_type> location_handler_type;
+using index_type = osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, osmium::Location>;
+using location_handler_type = osmium::handler::NodeLocationsForWays<index_type>;
struct less_charptr {
- bool operator()(const char* a, const char* b) const {
+ bool operator()(const char* a, const char* b) const noexcept {
return std::strcmp(a, b) < 0;
}
}; // less_charptr
-typedef std::map<const char*, const char*, less_charptr> tagmap_type;
+using tagmap_type = std::map<const char*, const char*, less_charptr>;
-inline tagmap_type create_map(const osmium::TagList& taglist) {
+tagmap_type create_map(const osmium::TagList& taglist) {
tagmap_type map;
for (auto& tag : taglist) {
@@ -52,7 +53,7 @@ class TestHandler : public osmium::handler::Handler {
std::ofstream m_out;
- bool m_first_out {true};
+ bool m_first_out{true};
public:
@@ -77,7 +78,7 @@ public:
}
void node(const osmium::Node& node) {
- gdalcpp::Feature feature(m_layer_point, m_ogr_factory.create_point(node));
+ gdalcpp::Feature feature{m_layer_point, m_ogr_factory.create_point(node)};
feature.set_field("id", static_cast<double>(node.id()));
feature.set_field("type", node.tags().get_value_by_key("type"));
feature.add_to_layer();
@@ -85,11 +86,11 @@ public:
void way(const osmium::Way& way) {
try {
- gdalcpp::Feature feature(m_layer_lines, m_ogr_factory.create_linestring(way));
+ gdalcpp::Feature feature{m_layer_lines, m_ogr_factory.create_linestring(way)};
feature.set_field("id", static_cast<double>(way.id()));
feature.set_field("type", way.tags().get_value_by_key("type"));
feature.add_to_layer();
- } catch (osmium::geometry_error&) {
+ } catch (const osmium::geometry_error&) {
std::cerr << "Ignoring illegal geometry for way " << way.id() << ".\n";
}
}
@@ -103,10 +104,10 @@ public:
}
m_out << "{\n \"test_id\": " << (area.orig_id() / 1000) << ",\n \"area_id\": " << area.id() << ",\n \"from_id\": " << area.orig_id() << ",\n \"from_type\": \"" << (area.from_way() ? "way" : "relation") << "\",\n \"wkt\": \"";
try {
- std::string wkt = m_wkt_factory.create_multipolygon(area);
+ const std::string wkt = m_wkt_factory.create_multipolygon(area);
m_out << wkt << "\",\n \"tags\": {";
- auto tagmap = create_map(area.tags());
+ const auto tagmap = create_map(area.tags());
bool first = true;
for (auto& tag : tagmap) {
if (first) {
@@ -117,11 +118,11 @@ public:
m_out << '"' << tag.first << "\": \"" << tag.second << '"';
}
m_out << "}\n}";
- } catch (osmium::geometry_error&) {
+ } catch (const osmium::geometry_error&) {
m_out << "INVALID\"\n}";
}
try {
- gdalcpp::Feature feature(m_layer_mpoly, m_ogr_factory.create_multipolygon(area));
+ gdalcpp::Feature feature{m_layer_mpoly, m_ogr_factory.create_multipolygon(area)};
feature.set_field("id", static_cast<double>(area.orig_id()));
std::string from_type;
@@ -132,7 +133,7 @@ public:
}
feature.set_field("from_type", from_type.c_str());
feature.add_to_layer();
- } catch (osmium::geometry_error&) {
+ } catch (const osmium::geometry_error&) {
std::cerr << "Ignoring illegal geometry for area " << area.id() << " created from " << (area.from_way() ? "way" : "relation") << " with id=" << area.orig_id() << ".\n";
}
}
@@ -144,37 +145,38 @@ public:
int main(int argc, char* argv[]) {
if (argc != 2) {
std::cerr << "Usage: " << argv[0] << " INFILE\n";
- exit(1);
+ std::exit(1);
}
- std::string output_format("SQLite");
- std::string input_filename(argv[1]);
- std::string output_filename("multipolygon.db");
+ const std::string output_format{"SQLite"};
+ const std::string input_filename{argv[1]};
+ const std::string output_filename{"multipolygon.db"};
CPLSetConfigOption("OGR_SQLITE_SYNCHRONOUS", "FALSE");
- gdalcpp::Dataset dataset{output_format, output_filename, gdalcpp::SRS{}, { "SPATIALITE=TRUE" }};
+ gdalcpp::Dataset dataset{output_format, output_filename, gdalcpp::SRS{}, {"SPATIALITE=TRUE"}};
- osmium::area::ProblemReporterOGR problem_reporter(dataset);
- osmium::area::Assembler::config_type assembler_config(&problem_reporter);
+ osmium::area::ProblemReporterOGR problem_reporter{dataset};
+ osmium::area::Assembler::config_type assembler_config;
+ assembler_config.problem_reporter = &problem_reporter;
assembler_config.check_roles = true;
assembler_config.create_empty_areas = true;
assembler_config.debug_level = 2;
- osmium::area::MultipolygonCollector<osmium::area::Assembler> collector(assembler_config);
+ osmium::area::MultipolygonCollector<osmium::area::Assembler> collector{assembler_config};
std::cerr << "Pass 1...\n";
- osmium::io::Reader reader1(input_filename);
+ osmium::io::Reader reader1{input_filename};
collector.read_relations(reader1);
reader1.close();
std::cerr << "Pass 1 done\n";
index_type index;
- location_handler_type location_handler(index);
+ location_handler_type location_handler{index};
location_handler.ignore_errors();
- TestHandler test_handler(dataset);
+ TestHandler test_handler{dataset};
std::cerr << "Pass 2...\n";
- osmium::io::Reader reader2(input_filename);
+ osmium::io::Reader reader2{input_filename};
osmium::apply(reader2, location_handler, test_handler, collector.handler([&test_handler](const osmium::memory::Buffer& area_buffer) {
osmium::apply(area_buffer, test_handler);
}));
diff --git a/test/data-tests/testdata-overview.cpp b/test/data-tests/testdata-overview.cpp
index 43d672d..4994f23 100644
--- a/test/data-tests/testdata-overview.cpp
+++ b/test/data-tests/testdata-overview.cpp
@@ -1,6 +1,7 @@
/* The code in this file is released into the Public Domain. */
#include <iostream>
+#include <string>
#include <gdalcpp.hpp>
@@ -12,8 +13,8 @@
#include <osmium/io/xml_input.hpp>
#include <osmium/visitor.hpp>
-typedef osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, osmium::Location> index_type;
-typedef osmium::handler::NodeLocationsForWays<index_type> location_handler_type;
+using index_type = osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, osmium::Location>;
+using location_handler_type = osmium::handler::NodeLocationsForWays<index_type>;
class TestOverviewHandler : public osmium::handler::Handler {
@@ -64,7 +65,7 @@ public:
}
feature.add_to_layer();
- } catch (osmium::geometry_error&) {
+ } catch (const osmium::geometry_error&) {
std::cerr << "Ignoring illegal geometry for way " << way.id() << ".\n";
}
}
@@ -76,24 +77,24 @@ public:
int main(int argc, char* argv[]) {
if (argc != 2) {
std::cerr << "Usage: " << argv[0] << " INFILE\n";
- exit(1);
+ std::exit(1);
}
- std::string output_format("SQLite");
- std::string input_filename(argv[1]);
- std::string output_filename("testdata-overview.db");
+ const std::string output_format{"SQLite"};
+ const std::string input_filename{argv[1]};
+ const std::string output_filename{"testdata-overview.db"};
::unlink(output_filename.c_str());
CPLSetConfigOption("OGR_SQLITE_SYNCHRONOUS", "FALSE");
- gdalcpp::Dataset dataset(output_format, output_filename, gdalcpp::SRS{}, { "SPATIALITE=TRUE" });
+ gdalcpp::Dataset dataset{output_format, output_filename, gdalcpp::SRS{}, {"SPATIALITE=TRUE"}};
- osmium::io::Reader reader(input_filename);
+ osmium::io::Reader reader{input_filename};
index_type index;
- location_handler_type location_handler(index);
+ location_handler_type location_handler{index};
location_handler.ignore_errors();
- TestOverviewHandler handler(dataset);
+ TestOverviewHandler handler{dataset};
osmium::apply(reader, location_handler, handler);
reader.close();
diff --git a/test/data-tests/testdata-testcases.cpp b/test/data-tests/testdata-testcases.cpp
index 0ea7fc8..d05c283 100644
--- a/test/data-tests/testdata-testcases.cpp
+++ b/test/data-tests/testdata-testcases.cpp
@@ -15,11 +15,9 @@ int main(int argc, char* argv[]) {
std::cerr << "Running tests from '" << dirname << "' (from TESTCASES_DIR environment variable)\n";
} else {
std::cerr << "Please set TESTCASES_DIR environment variable.\n";
- exit(1);
+ std::exit(1);
}
- int result = Catch::Session().run(argc, argv);
-
- return result;
+ return Catch::Session().run(argc, argv);
}
diff --git a/test/data-tests/testdata-xml.cpp b/test/data-tests/testdata-xml.cpp
index 01cee29..0d2739a 100644
--- a/test/data-tests/testdata-xml.cpp
+++ b/test/data-tests/testdata-xml.cpp
@@ -5,7 +5,9 @@
#include <cassert>
#include <cstdlib>
+#include <future>
#include <iostream>
+#include <iterator>
#include <string>
#include <osmium/io/detail/queue_util.hpp>
@@ -14,14 +16,14 @@
#include <osmium/visitor.hpp>
std::string S_(const char* s) {
- return std::string(s);
+ return std::string{s};
}
std::string filename(const char* test_id, const char* suffix = "osm") {
const char* testdir = getenv("TESTDIR");
if (!testdir) {
std::cerr << "You have to set TESTDIR environment variable before running testdata-xml\n";
- exit(2);
+ std::exit(2);
}
std::string f;
@@ -47,11 +49,11 @@ struct header_buffer_type {
// file contents fit into small buffers.
std::string read_file(const char* test_id) {
- int fd = osmium::io::detail::open_for_reading(filename(test_id));
+ const int fd = osmium::io::detail::open_for_reading(filename(test_id));
assert(fd >= 0);
std::string input(10000, '\0');
- auto n = ::read(fd, reinterpret_cast<unsigned char*>(const_cast<char*>(input.data())), 10000);
+ const auto n = ::read(fd, reinterpret_cast<unsigned char*>(const_cast<char*>(input.data())), 10000);
assert(n >= 0);
input.resize(static_cast<std::string::size_type>(n));
@@ -61,10 +63,10 @@ std::string read_file(const char* test_id) {
}
std::string read_gz_file(const char* test_id, const char* suffix) {
- int fd = osmium::io::detail::open_for_reading(filename(test_id, suffix));
+ const int fd = osmium::io::detail::open_for_reading(filename(test_id, suffix));
assert(fd >= 0);
- osmium::io::GzipDecompressor gzip_decompressor(fd);
+ osmium::io::GzipDecompressor gzip_decompressor{fd};
std::string input = gzip_decompressor.read();
gzip_decompressor.close();
@@ -81,7 +83,7 @@ header_buffer_type parse_xml(std::string input) {
osmium::io::detail::add_to_queue(input_queue, std::move(input));
osmium::io::detail::add_to_queue(input_queue, std::string{});
- osmium::io::detail::XMLParser parser(input_queue, output_queue, header_promise, osmium::osm_entity_bits::all);
+ osmium::io::detail::XMLParser parser{input_queue, output_queue, header_promise, osmium::osm_entity_bits::all};
parser.parse();
header_buffer_type result;
@@ -117,9 +119,9 @@ TEST_CASE("Reading OSM XML 100") {
}
SECTION("Using Reader") {
- osmium::io::Reader reader(filename("100-correct_but_no_data"));
+ osmium::io::Reader reader{filename("100-correct_but_no_data")};
- osmium::io::Header header = reader.header();
+ const osmium::io::Header header{reader.header()};
REQUIRE(header.get("generator") == "testdata");
osmium::memory::Buffer buffer = reader.read();
@@ -129,9 +131,9 @@ TEST_CASE("Reading OSM XML 100") {
}
SECTION("Using Reader asking for header only") {
- osmium::io::Reader reader(filename("100-correct_but_no_data"), osmium::osm_entity_bits::nothing);
+ osmium::io::Reader reader{filename("100-correct_but_no_data"), osmium::osm_entity_bits::nothing};
- osmium::io::Header header = reader.header();
+ const osmium::io::Header header{reader.header()};
REQUIRE(header.get("generator") == "testdata");
reader.close();
}
@@ -146,15 +148,15 @@ TEST_CASE("Reading OSM XML 101") {
REQUIRE_THROWS_AS(read_xml("101-missing_version"), osmium::format_version_error);
try {
read_xml("101-missing_version");
- } catch (osmium::format_version_error& e) {
+ } catch (const osmium::format_version_error& e) {
REQUIRE(e.version.empty());
}
}
SECTION("Using Reader") {
REQUIRE_THROWS_AS({
- osmium::io::Reader reader(filename("101-missing_version"));
- osmium::io::Header header = reader.header();
+ osmium::io::Reader reader{filename("101-missing_version")};
+ const osmium::io::Header header{reader.header()};
osmium::memory::Buffer buffer = reader.read();
reader.close();
}, osmium::format_version_error);
@@ -170,16 +172,16 @@ TEST_CASE("Reading OSM XML 102") {
REQUIRE_THROWS_AS(read_xml("102-wrong_version"), osmium::format_version_error);
try {
read_xml("102-wrong_version");
- } catch (osmium::format_version_error& e) {
+ } catch (const osmium::format_version_error& e) {
REQUIRE(e.version == "0.1");
}
}
SECTION("Using Reader") {
REQUIRE_THROWS_AS({
- osmium::io::Reader reader(filename("102-wrong_version"));
+ osmium::io::Reader reader{filename("102-wrong_version")};
- osmium::io::Header header = reader.header();
+ const osmium::io::Header header{reader.header()};
osmium::memory::Buffer buffer = reader.read();
reader.close();
}, osmium::format_version_error);
@@ -195,15 +197,15 @@ TEST_CASE("Reading OSM XML 103") {
REQUIRE_THROWS_AS(read_xml("103-old_version"), osmium::format_version_error);
try {
read_xml("103-old_version");
- } catch (osmium::format_version_error& e) {
+ } catch (const osmium::format_version_error& e) {
REQUIRE(e.version == "0.5");
}
}
SECTION("Using Reader") {
REQUIRE_THROWS_AS({
- osmium::io::Reader reader(filename("103-old_version"));
- osmium::io::Header header = reader.header();
+ osmium::io::Reader reader{filename("103-old_version")};
+ const osmium::io::Header header{reader.header()};
osmium::memory::Buffer buffer = reader.read();
reader.close();
}, osmium::format_version_error);
@@ -219,7 +221,7 @@ TEST_CASE("Reading OSM XML 104") {
REQUIRE_THROWS_AS(read_xml("104-empty_file"), osmium::xml_error);
try {
read_xml("104-empty_file");
- } catch (osmium::xml_error& e) {
+ } catch (const osmium::xml_error& e) {
REQUIRE(e.line == 1);
REQUIRE(e.column == 0);
}
@@ -227,8 +229,8 @@ TEST_CASE("Reading OSM XML 104") {
SECTION("Using Reader") {
REQUIRE_THROWS_AS({
- osmium::io::Reader reader(filename("104-empty_file"));
- osmium::io::Header header = reader.header();
+ osmium::io::Reader reader{filename("104-empty_file")};
+ const osmium::io::Header header{reader.header()};
osmium::memory::Buffer buffer = reader.read();
reader.close();
}, osmium::xml_error);
@@ -245,8 +247,8 @@ TEST_CASE("Reading OSM XML 105") {
SECTION("Using Reader") {
REQUIRE_THROWS_AS({
- osmium::io::Reader reader(filename("105-incomplete_xml_file"));
- osmium::io::Header header = reader.header();
+ osmium::io::Reader reader{filename("105-incomplete_xml_file")};
+ const osmium::io::Header header{reader.header()};
osmium::memory::Buffer buffer = reader.read();
reader.close();
}, osmium::xml_error);
@@ -270,9 +272,9 @@ TEST_CASE("Reading OSM XML 120") {
}
SECTION("Using Reader") {
- osmium::io::Reader reader(filename("120-correct_gzip_file_without_data", "osm.gz"));
+ osmium::io::Reader reader{filename("120-correct_gzip_file_without_data", "osm.gz")};
- osmium::io::Header header = reader.header();
+ const osmium::io::Header header{reader.header()};
REQUIRE(header.get("generator") == "testdata");
osmium::memory::Buffer buffer = reader.read();
@@ -296,8 +298,8 @@ TEST_CASE("Reading OSM XML 121") {
SECTION("Using Reader") {
// can throw osmium::gzip_error or osmium::xml_error
REQUIRE_THROWS({
- osmium::io::Reader reader(filename("121-truncated_gzip_file", "osm.gz"));
- osmium::io::Header header = reader.header();
+ osmium::io::Reader reader{filename("121-truncated_gzip_file", "osm.gz")};
+ const osmium::io::Header header{reader.header()};
osmium::memory::Buffer buffer = reader.read();
reader.close();
});
@@ -317,8 +319,8 @@ TEST_CASE("Reading OSM XML 122") {
SECTION("Using Reader") {
REQUIRE_THROWS_AS({
- osmium::io::Reader reader(filename("122-no_osm_element"));
- osmium::io::Header header = reader.header();
+ osmium::io::Reader reader{filename("122-no_osm_element")};
+ const osmium::io::Header header{reader.header()};
osmium::memory::Buffer buffer = reader.read();
reader.close();
}, osmium::xml_error);
@@ -331,7 +333,7 @@ TEST_CASE("Reading OSM XML 122") {
TEST_CASE("Reading OSM XML 140") {
SECTION("Using Reader") {
- osmium::io::Reader reader(filename("140-unicode"));
+ osmium::io::Reader reader{filename("140-unicode")};
osmium::memory::Buffer buffer = reader.read();
reader.close();
@@ -343,7 +345,7 @@ TEST_CASE("Reading OSM XML 140") {
const char* uc = t["unicode_char"];
- auto len = atoi(t["unicode_utf8_length"]);
+ const auto len = atoi(t["unicode_utf8_length"]);
REQUIRE(len == strlen(uc));
REQUIRE(S_(uc) == t["unicode_xml"]);
@@ -382,7 +384,7 @@ TEST_CASE("Reading OSM XML 140") {
TEST_CASE("Reading OSM XML 141") {
SECTION("Using Reader") {
- osmium::io::Reader reader(filename("141-entities"));
+ osmium::io::Reader reader{filename("141-entities")};
osmium::memory::Buffer buffer = reader.read();
reader.close();
REQUIRE(buffer.committed() > 0);
@@ -406,7 +408,7 @@ TEST_CASE("Reading OSM XML 141") {
TEST_CASE("Reading OSM XML 142") {
SECTION("Using Reader to read nodes") {
- osmium::io::Reader reader(filename("142-whitespace"));
+ osmium::io::Reader reader{filename("142-whitespace")};
osmium::memory::Buffer buffer = reader.read();
reader.close();
@@ -451,7 +453,7 @@ TEST_CASE("Reading OSM XML 142") {
}
SECTION("Using Reader to read relation") {
- osmium::io::Reader reader(filename("142-whitespace"));
+ osmium::io::Reader reader{filename("142-whitespace")};
osmium::memory::Buffer buffer = reader.read();
reader.close();
@@ -505,9 +507,9 @@ TEST_CASE("Reading OSM XML 200") {
}
SECTION("Using Reader") {
- osmium::io::Reader reader(filename("200-nodes"));
+ osmium::io::Reader reader{filename("200-nodes")};
- osmium::io::Header header = reader.header();
+ const osmium::io::Header header{reader.header()};
REQUIRE(header.get("generator") == "testdata");
osmium::memory::Buffer buffer = reader.read();
@@ -519,9 +521,9 @@ TEST_CASE("Reading OSM XML 200") {
}
SECTION("Using Reader asking for nodes") {
- osmium::io::Reader reader(filename("200-nodes"), osmium::osm_entity_bits::node);
+ osmium::io::Reader reader{filename("200-nodes"), osmium::osm_entity_bits::node};
- osmium::io::Header header = reader.header();
+ const osmium::io::Header header{reader.header()};
REQUIRE(header.get("generator") == "testdata");
osmium::memory::Buffer buffer = reader.read();
@@ -533,9 +535,9 @@ TEST_CASE("Reading OSM XML 200") {
}
SECTION("Using Reader asking for header only") {
- osmium::io::Reader reader(filename("200-nodes"), osmium::osm_entity_bits::nothing);
+ osmium::io::Reader reader{filename("200-nodes"), osmium::osm_entity_bits::nothing};
- osmium::io::Header header = reader.header();
+ const osmium::io::Header header{reader.header()};
REQUIRE(header.get("generator") == "testdata");
REQUIRE_THROWS({
@@ -546,9 +548,9 @@ TEST_CASE("Reading OSM XML 200") {
}
SECTION("Using Reader asking for ways") {
- osmium::io::Reader reader(filename("200-nodes"), osmium::osm_entity_bits::way);
+ osmium::io::Reader reader{filename("200-nodes"), osmium::osm_entity_bits::way};
- osmium::io::Header header = reader.header();
+ const osmium::io::Header header{reader.header()};
REQUIRE(header.get("generator") == "testdata");
osmium::memory::Buffer buffer = reader.read();
diff --git a/test/t/basic/test_area.cpp b/test/t/basic/test_area.cpp
new file mode 100644
index 0000000..f2847dc
--- /dev/null
+++ b/test/t/basic/test_area.cpp
@@ -0,0 +1,78 @@
+#include "catch.hpp"
+
+#include <boost/crc.hpp>
+
+#include <osmium/builder/attr.hpp>
+#include <osmium/osm/crc.hpp>
+#include <osmium/osm/area.hpp>
+
+using namespace osmium::builder::attr;
+
+TEST_CASE("Build area") {
+ osmium::memory::Buffer buffer(10000);
+
+ osmium::builder::add_area(buffer,
+ _id(17),
+ _version(3),
+ _visible(),
+ _cid(333),
+ _uid(21),
+ _timestamp(time_t(123)),
+ _user("foo"),
+ _tag("landuse", "forest"),
+ _tag("name", "Sherwood Forest"),
+ _outer_ring({
+ {1, {3.2, 4.2}},
+ {2, {3.5, 4.7}},
+ {3, {3.6, 4.9}},
+ {1, {3.2, 4.2}}
+ }),
+ _inner_ring({
+ {5, {1.0, 1.0}},
+ {6, {8.0, 1.0}},
+ {7, {8.0, 8.0}},
+ {8, {1.0, 8.0}},
+ {5, {1.0, 1.0}}
+ })
+ );
+
+ const osmium::Area& area = buffer.get<osmium::Area>(0);
+
+ REQUIRE(17 == area.id());
+ REQUIRE(3 == area.version());
+ REQUIRE(true == area.visible());
+ REQUIRE(333 == area.changeset());
+ REQUIRE(21 == area.uid());
+ REQUIRE(std::string("foo") == area.user());
+ REQUIRE(123 == uint32_t(area.timestamp()));
+ REQUIRE(2 == area.tags().size());
+
+ int inner = 0;
+ int outer = 0;
+ for (const auto& subitem : area) {
+ switch (subitem.type()) {
+ case osmium::item_type::outer_ring: {
+ const auto& ring = static_cast<const osmium::OuterRing&>(subitem);
+ REQUIRE(ring.size() == 4);
+ ++outer;
+ }
+ break;
+ case osmium::item_type::inner_ring: {
+ const auto& ring = static_cast<const osmium::OuterRing&>(subitem);
+ REQUIRE(ring.size() == 5);
+ ++inner;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ REQUIRE(outer == 1);
+ REQUIRE(inner == 1);
+
+ osmium::CRC<boost::crc_32_type> crc32;
+ crc32.update(area);
+ REQUIRE(crc32().checksum() == 0x2b2b7fa0);
+}
+
diff --git a/test/t/basic/test_location.cpp b/test/t/basic/test_location.cpp
index e6c1b53..dc5b378 100644
--- a/test/t/basic/test_location.cpp
+++ b/test/t/basic/test_location.cpp
@@ -166,13 +166,29 @@ TEST_CASE("Location hash") {
}
}
-#define C(s, v) REQUIRE(osmium::detail::string_to_location_coordinate(s) == v); \
- REQUIRE(osmium::detail::string_to_location_coordinate("-" s) == -v); \
- REQUIRE(atof(s) == Approx( v / 10000000.0)); \
- REQUIRE(atof("-" s) == Approx(-v / 10000000.0));
-
-#define F(s) REQUIRE_THROWS_AS(osmium::detail::string_to_location_coordinate(s), osmium::invalid_location); \
- REQUIRE_THROWS_AS(osmium::detail::string_to_location_coordinate("-" s), osmium::invalid_location);
+#define CR(s, v, r) { \
+ const char* strm = "-" s; \
+ const char* strp = strm + 1; \
+ REQUIRE(std::atof(strp) == Approx( v / 10000000.0)); \
+ REQUIRE(std::atof(strm) == Approx(-v / 10000000.0)); \
+ const char** data = &strp; \
+ REQUIRE(osmium::detail::string_to_location_coordinate(data) == v); \
+ REQUIRE(std::string{*data} == r); \
+ data = &strm; \
+ REQUIRE(osmium::detail::string_to_location_coordinate(data) == -v); \
+ REQUIRE(std::string{*data} == r); \
+ }
+
+#define C(s, v) CR(s, v, "")
+
+#define F(s) { \
+ const char* strm = "-" s; \
+ const char* strp = strm + 1; \
+ const char** data = &strp; \
+ REQUIRE_THROWS_AS(osmium::detail::string_to_location_coordinate(data), osmium::invalid_location); \
+ data = &strm; \
+ REQUIRE_THROWS_AS(osmium::detail::string_to_location_coordinate(data), osmium::invalid_location); \
+ }
TEST_CASE("Parsing coordinates from strings") {
F("x");
@@ -181,11 +197,12 @@ TEST_CASE("Parsing coordinates from strings") {
F("");
F(" ");
F(" 123");
- F("123 ");
- F("123x");
- F("1.2x");
- C("0", 0);
+ CR("123 ", 1230000000, " ");
+ CR("123x", 1230000000, "x");
+ CR("1.2x", 12000000, "x");
+
+ C("0", 0);
C("1", 10000000);
C("2", 20000000);
@@ -201,10 +218,11 @@ TEST_CASE("Parsing coordinates from strings") {
C("00", 0);
C("01", 10000000);
C("001", 10000000);
+ C("0001", 10000000);
- F("0001");
F("1234");
F("1234.");
+ F("12345678901234567890");
C("0.", 0);
C("0.0", 0);
@@ -258,15 +276,32 @@ TEST_CASE("Parsing coordinates from strings") {
C("1.4e-7", 1);
C("1.5e-7", 2);
C("1.9e-7", 2);
+ C("0.5e-7", 1);
+ C("0.1e-7", 0);
+ C("0.0e-7", 0);
+ C("1.9e-8", 0);
+ C("1.9e-9", 0);
+ C("1.9e-10", 0);
F("e");
F(" e");
F(" 1.1e2");
- F("1.1e2 ");
- F("1.1e2x");
+ F("1.0e3");
+ F("5e4");
+ F("5.0e2");
+ F("3e2");
+ F("1e");
+ F("0.5e");
+ F("1e10");
+
+ CR("1e2 ", 1000000000, " ");
+ CR("1.1e2 ", 1100000000, " ");
+ CR("1.1e2x", 1100000000, "x");
+ CR("1.1e2:", 1100000000, ":");
}
#undef C
+#undef CR
#undef F
#define CW(v, s) buffer.clear(); \
@@ -305,3 +340,33 @@ TEST_CASE("Writing coordinates into string") {
#undef CW
+TEST_CASE("set lon/lat from string") {
+ osmium::Location loc;
+ loc.set_lon("1.2");
+ loc.set_lat("3.4");
+ REQUIRE(loc.lon() == Approx(1.2));
+ REQUIRE(loc.lat() == Approx(3.4));
+}
+
+TEST_CASE("set lon/lat from string with trailing characters") {
+ osmium::Location loc;
+ REQUIRE_THROWS_AS({
+ loc.set_lon("1.2x");
+ }, osmium::invalid_location);
+ REQUIRE_THROWS_AS({
+ loc.set_lat("3.4e1 ");
+ }, osmium::invalid_location);
+}
+
+TEST_CASE("set lon/lat from string with trailing characters using partial") {
+ osmium::Location loc;
+ const char* x = "1.2x";
+ const char* y = "3.4 ";
+ loc.set_lon_partial(&x);
+ loc.set_lat_partial(&y);
+ REQUIRE(loc.lon() == Approx(1.2));
+ REQUIRE(loc.lat() == Approx(3.4));
+ REQUIRE(*x == 'x');
+ REQUIRE(*y == ' ');
+}
+
diff --git a/test/t/basic/test_node.cpp b/test/t/basic/test_node.cpp
index b7f4c6c..e5dbe8a 100644
--- a/test/t/basic/test_node.cpp
+++ b/test/t/basic/test_node.cpp
@@ -9,7 +9,7 @@
using namespace osmium::builder::attr;
TEST_CASE("Build node") {
- osmium::memory::Buffer buffer(10000);
+ osmium::memory::Buffer buffer{10000};
osmium::builder::add_node(buffer,
_id(17),
@@ -36,7 +36,7 @@ TEST_CASE("Build node") {
REQUIRE(false == node.deleted());
REQUIRE(333 == node.changeset());
REQUIRE(21 == node.uid());
- REQUIRE(std::string("foo") == node.user());
+ REQUIRE(std::string{"foo"} == node.user());
REQUIRE(123 == uint32_t(node.timestamp()));
REQUIRE(osmium::Location(3.5, 4.7) == node.location());
REQUIRE(2 == node.tags().size());
@@ -51,7 +51,7 @@ TEST_CASE("Build node") {
}
TEST_CASE("default values for node attributes") {
- osmium::memory::Buffer buffer(10000);
+ osmium::memory::Buffer buffer{10000};
osmium::builder::add_node(buffer, _id(0));
@@ -62,22 +62,23 @@ TEST_CASE("default values for node attributes") {
REQUIRE(true == node.visible());
REQUIRE(0 == node.changeset());
REQUIRE(0 == node.uid());
- REQUIRE(std::string("") == node.user());
+ REQUIRE(std::string{} == node.user());
REQUIRE(0 == uint32_t(node.timestamp()));
REQUIRE(osmium::Location() == node.location());
REQUIRE(0 == node.tags().size());
}
TEST_CASE("set node attributes from strings") {
- osmium::memory::Buffer buffer(10000);
+ osmium::memory::Buffer buffer{10000};
osmium::builder::add_node(buffer, _id(0));
osmium::Node& node = buffer.get<osmium::Node>(0);
node.set_id("-17")
.set_version("3")
- .set_visible(true)
+ .set_visible("true")
.set_changeset("333")
+ .set_timestamp("2014-03-17T16:23:08Z")
.set_uid("21");
REQUIRE(-17l == node.id());
@@ -85,11 +86,52 @@ TEST_CASE("set node attributes from strings") {
REQUIRE(3 == node.version());
REQUIRE(true == node.visible());
REQUIRE(333 == node.changeset());
+ REQUIRE(std::string{"2014-03-17T16:23:08Z"} == node.timestamp().to_iso());
REQUIRE(21 == node.uid());
}
+TEST_CASE("set node attributes from strings using set_attribute()") {
+ osmium::memory::Buffer buffer{10000};
+
+ osmium::builder::add_node(buffer, _id(0));
+
+ osmium::Node& node = buffer.get<osmium::Node>(0);
+ node.set_attribute("id", "-17")
+ .set_attribute("version", "3")
+ .set_attribute("visible", "true")
+ .set_attribute("changeset", "333")
+ .set_attribute("timestamp", "2014-03-17T16:23:08Z")
+ .set_attribute("uid", "21");
+
+ REQUIRE(-17l == node.id());
+ REQUIRE(17ul == node.positive_id());
+ REQUIRE(3 == node.version());
+ REQUIRE(true == node.visible());
+ REQUIRE(333 == node.changeset());
+ REQUIRE(std::string{"2014-03-17T16:23:08Z"} == node.timestamp().to_iso());
+ REQUIRE(21 == node.uid());
+}
+
+TEST_CASE("Setting attributes from bad data on strings should fail") {
+ osmium::memory::Buffer buffer{10000};
+
+ osmium::builder::add_node(buffer, _id(0));
+
+ osmium::Node& node = buffer.get<osmium::Node>(0);
+ REQUIRE_THROWS(node.set_id("bar"));
+ REQUIRE_THROWS(node.set_id("123x"));
+ REQUIRE_THROWS(node.set_version("123x"));
+ REQUIRE_THROWS(node.set_visible("foo"));
+ REQUIRE_THROWS(node.set_changeset("123x"));
+ REQUIRE_THROWS(node.set_changeset("NULL"));
+ REQUIRE_THROWS(node.set_timestamp("2014-03-17T16:23:08Zx"));
+ REQUIRE_THROWS(node.set_timestamp("2014-03-17T16:23:99Z"));
+ REQUIRE_THROWS(node.set_uid("123x"));
+ REQUIRE_THROWS(node.set_uid("anonymous"));
+}
+
TEST_CASE("set large id") {
- osmium::memory::Buffer buffer(10000);
+ osmium::memory::Buffer buffer{10000};
int64_t id = 3000000000l;
osmium::builder::add_node(buffer, _id(id));
@@ -104,7 +146,7 @@ TEST_CASE("set large id") {
}
TEST_CASE("set tags on node") {
- osmium::memory::Buffer buffer(10000);
+ osmium::memory::Buffer buffer{10000};
osmium::builder::add_node(buffer,
_user("foo"),
@@ -114,11 +156,11 @@ TEST_CASE("set tags on node") {
const osmium::Node& node = buffer.get<osmium::Node>(0);
REQUIRE(nullptr == node.tags().get_value_by_key("fail"));
- REQUIRE(std::string("pub") == node.tags().get_value_by_key("amenity"));
- REQUIRE(std::string("pub") == node.get_value_by_key("amenity"));
+ REQUIRE(std::string{"pub"} == node.tags().get_value_by_key("amenity"));
+ REQUIRE(std::string{"pub"} == node.get_value_by_key("amenity"));
- REQUIRE(std::string("default") == node.tags().get_value_by_key("fail", "default"));
- REQUIRE(std::string("pub") == node.tags().get_value_by_key("amenity", "default"));
- REQUIRE(std::string("pub") == node.get_value_by_key("amenity", "default"));
+ REQUIRE(std::string{"default"} == node.tags().get_value_by_key("fail", "default"));
+ REQUIRE(std::string{"pub"} == node.tags().get_value_by_key("amenity", "default"));
+ REQUIRE(std::string{"pub"} == node.get_value_by_key("amenity", "default"));
}
diff --git a/test/t/basic/test_timestamp.cpp b/test/t/basic/test_timestamp.cpp
index f80ffcf..561a705 100644
--- a/test/t/basic/test_timestamp.cpp
+++ b/test/t/basic/test_timestamp.cpp
@@ -75,3 +75,47 @@ TEST_CASE("Timestamp") {
}
}
+
+TEST_CASE("Valid timestamps") {
+
+ std::vector<std::string> test_cases = {
+ "1970-01-01T00:00:01Z",
+ "2000-01-01T00:00:00Z",
+ "2006-12-31T23:59:59Z",
+ "2030-12-31T23:59:59Z",
+ "2016-02-28T23:59:59Z",
+ "2016-03-31T23:59:59Z"
+ };
+
+ for (const auto& tc : test_cases) {
+ osmium::Timestamp t{tc};
+ REQUIRE(tc == t.to_iso());
+ }
+
+}
+
+TEST_CASE("Invalid timestamps") {
+ REQUIRE_THROWS_AS(osmium::Timestamp{""}, std::invalid_argument);
+ REQUIRE_THROWS_AS(osmium::Timestamp{"x"}, std::invalid_argument);
+ REQUIRE_THROWS_AS(osmium::Timestamp{"xxxxxxxxxxxxxxxxxxxx"}, std::invalid_argument);
+
+ REQUIRE_THROWS_AS(osmium::Timestamp{"2000-01-01x00:00:00Z"}, std::invalid_argument);
+ REQUIRE_THROWS_AS(osmium::Timestamp{"2000-01-01T00:00:00x"}, std::invalid_argument);
+
+ REQUIRE_THROWS_AS(osmium::Timestamp{"2000x01-01T00:00:00Z"}, std::invalid_argument);
+ REQUIRE_THROWS_AS(osmium::Timestamp{"2000-01x01T00:00:00Z"}, std::invalid_argument);
+ REQUIRE_THROWS_AS(osmium::Timestamp{"2000-01-01T00x00:00Z"}, std::invalid_argument);
+ REQUIRE_THROWS_AS(osmium::Timestamp{"2000-01-01T00:00x00Z"}, std::invalid_argument);
+
+ REQUIRE_THROWS_AS(osmium::Timestamp{"0000-00-01T00:00:00Z"}, std::invalid_argument);
+ REQUIRE_THROWS_AS(osmium::Timestamp{"2000-00-01T00:00:00Z"}, std::invalid_argument);
+ REQUIRE_THROWS_AS(osmium::Timestamp{"2000-01-00T00:00:00Z"}, std::invalid_argument);
+ REQUIRE_THROWS_AS(osmium::Timestamp{"2000-01-01T24:00:00Z"}, std::invalid_argument);
+ REQUIRE_THROWS_AS(osmium::Timestamp{"2000-01-01T00:60:00Z"}, std::invalid_argument);
+ REQUIRE_THROWS_AS(osmium::Timestamp{"2000-01-01T00:00:61Z"}, std::invalid_argument);
+
+ REQUIRE_THROWS_AS(osmium::Timestamp{"2000-01-32T00:00:00Z"}, std::invalid_argument);
+ REQUIRE_THROWS_AS(osmium::Timestamp{"2000-02-30T00:00:00Z"}, std::invalid_argument);
+ REQUIRE_THROWS_AS(osmium::Timestamp{"2000-03-32T00:00:00Z"}, std::invalid_argument);
+}
+
diff --git a/test/t/geom/test_tile.cpp b/test/t/geom/test_tile.cpp
index e80cb96..5454fed 100644
--- a/test/t/geom/test_tile.cpp
+++ b/test/t/geom/test_tile.cpp
@@ -8,86 +8,96 @@
#include "test_tile_data.hpp"
-TEST_CASE("Tile") {
+TEST_CASE("Tile from x0.0 y0.0 at zoom 0") {
+ osmium::Location l{0.0, 0.0};
- SECTION("x0.0 y0.0 zoom 0") {
- osmium::Location l(0.0, 0.0);
+ osmium::geom::Tile t{0, l};
- osmium::geom::Tile t(0, l);
+ REQUIRE(t.x == 0);
+ REQUIRE(t.y == 0);
+ REQUIRE(t.z == 0);
+ REQUIRE(t.valid());
+}
- REQUIRE(t.x == 0);
- REQUIRE(t.y == 0);
- REQUIRE(t.z == 0);
- }
+TEST_CASE("Tile from x180.0 y90.0 at zoom 0") {
+ osmium::Location l{180.0, 90.0};
- SECTION("x180.0 y90.0 zoom 0") {
- osmium::Location l(180.0, 90.0);
+ osmium::geom::Tile t{0, l};
- osmium::geom::Tile t(0, l);
+ REQUIRE(t.x == 0);
+ REQUIRE(t.y == 0);
+ REQUIRE(t.z == 0);
+ REQUIRE(t.valid());
+}
- REQUIRE(t.x == 0);
- REQUIRE(t.y == 0);
- REQUIRE(t.z == 0);
- }
+TEST_CASE("Tile from x180.0 y90.0 at zoom 4") {
+ osmium::Location l{180.0, 90.0};
- SECTION("x180.0 y90.0 zoom 4") {
- osmium::Location l(180.0, 90.0);
+ osmium::geom::Tile t{4, l};
- osmium::geom::Tile t(4, l);
+ REQUIRE(t.x == (1 << 4) - 1);
+ REQUIRE(t.y == 0);
+ REQUIRE(t.z == 4);
+ REQUIRE(t.valid());
+}
- REQUIRE(t.x == (1 << 4) - 1);
- REQUIRE(t.y == 0);
- REQUIRE(t.z == 4);
- }
+TEST_CASE("Tile from x0.0 y0.0 at zoom 4") {
+ osmium::Location l{0.0, 0.0};
- SECTION("x0.0 y0.0 zoom 4") {
- osmium::Location l(0.0, 0.0);
+ osmium::geom::Tile t{4, l};
- osmium::geom::Tile t(4, l);
+ auto n = 1 << (4-1);
+ REQUIRE(t.x == n);
+ REQUIRE(t.y == n);
+ REQUIRE(t.z == 4);
+ REQUIRE(t.valid());
+}
- auto n = 1 << (4-1);
- REQUIRE(t.x == n);
- REQUIRE(t.y == n);
- REQUIRE(t.z == 4);
- }
+TEST_CASE("Tile from max values at zoom 4") {
+ osmium::geom::Tile t{4u, 15u, 15u};
+ REQUIRE(t.valid());
+}
- SECTION("equality") {
- osmium::geom::Tile a(4, 3, 4);
- osmium::geom::Tile b(4, 3, 4);
- osmium::geom::Tile c(4, 4, 3);
- REQUIRE(a == b);
- REQUIRE(a != c);
- REQUIRE(b != c);
- }
+TEST_CASE("Tile from max values at zoom 30") {
+ osmium::geom::Tile t{30u, (1u<<30) - 1, (1u<<30) - 1};
+ REQUIRE(t.valid());
+}
- SECTION("order") {
- osmium::geom::Tile a(2, 3, 4);
- osmium::geom::Tile b(4, 3, 4);
- osmium::geom::Tile c(4, 4, 3);
- osmium::geom::Tile d(4, 4, 2);
- REQUIRE(a < b);
- REQUIRE(a < c);
- REQUIRE(b < c);
- REQUIRE(d < c);
- }
+TEST_CASE("Tile equality") {
+ osmium::geom::Tile a{4, 3, 4};
+ osmium::geom::Tile b{4, 3, 4};
+ osmium::geom::Tile c{4, 4, 3};
+ REQUIRE(a == b);
+ REQUIRE(a != c);
+ REQUIRE(b != c);
+}
- SECTION("tilelist") {
- std::istringstream input_data(s);
- while (input_data) {
- double lon, lat;
- uint32_t x, y, zoom;
- input_data >> lon;
- input_data >> lat;
- input_data >> x;
- input_data >> y;
- input_data >> zoom;
-
- osmium::Location l(lon, lat);
- osmium::geom::Tile t(zoom, l);
- REQUIRE(t.x == x);
- REQUIRE(t.y == y);
- }
- }
+TEST_CASE("Tile order") {
+ osmium::geom::Tile a{4, 3, 4};
+ osmium::geom::Tile b{6, 3, 4};
+ osmium::geom::Tile c{6, 4, 3};
+ osmium::geom::Tile d{6, 4, 2};
+ REQUIRE(a < b);
+ REQUIRE(a < c);
+ REQUIRE(b < c);
+ REQUIRE(d < c);
+}
+TEST_CASE("Check a random list of tiles") {
+ std::istringstream input_data(s);
+ while (input_data) {
+ double lon, lat;
+ uint32_t x, y, zoom;
+ input_data >> lon;
+ input_data >> lat;
+ input_data >> x;
+ input_data >> y;
+ input_data >> zoom;
+
+ osmium::Location l{lon, lat};
+ osmium::geom::Tile t{zoom, l};
+ REQUIRE(t.x == x);
+ REQUIRE(t.y == y);
+ }
}
diff --git a/test/t/geom/test_wkb.cpp b/test/t/geom/test_wkb.cpp
index 12cd5b6..d4d9228 100644
--- a/test/t/geom/test_wkb.cpp
+++ b/test/t/geom/test_wkb.cpp
@@ -6,125 +6,130 @@
#if __BYTE_ORDER == __LITTLE_ENDIAN
-TEST_CASE("WKB_Geometry_byte_order_dependent") {
+TEST_CASE("WKB geometry factory (byte-order-dependant), points") {
+ const osmium::Location loc{3.2, 4.2};
-SECTION("point") {
- osmium::geom::WKBFactory<> factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
+ SECTION("point") {
+ osmium::geom::WKBFactory<> factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
- std::string wkb {factory.create_point(osmium::Location(3.2, 4.2))};
- REQUIRE(std::string{"01010000009A99999999990940CDCCCCCCCCCC1040"} == wkb);
-}
+ const std::string wkb{factory.create_point(loc)};
+ REQUIRE(wkb == "01010000009A99999999990940CDCCCCCCCCCC1040");
+ }
-SECTION("point in web mercator") {
- osmium::geom::WKBFactory<osmium::geom::MercatorProjection> factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
+ SECTION("point in web mercator") {
+ osmium::geom::WKBFactory<osmium::geom::MercatorProjection> factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
- std::string wkb {factory.create_point(osmium::Location(3.2, 4.2))};
- REQUIRE(std::string{"010100000028706E7BF9BD1541B03E0D93E48F1C41"} == wkb);
-}
+ const std::string wkb{factory.create_point(loc)};
+ REQUIRE(wkb == "010100000028706E7BF9BD1541B03E0D93E48F1C41");
+ }
-SECTION("point in ewkb") {
- osmium::geom::WKBFactory<> factory(osmium::geom::wkb_type::ewkb, osmium::geom::out_type::hex);
+ SECTION("point in ewkb") {
+ osmium::geom::WKBFactory<> factory(osmium::geom::wkb_type::ewkb, osmium::geom::out_type::hex);
- std::string wkb {factory.create_point(osmium::Location(3.2, 4.2))};
- REQUIRE(std::string{"0101000020E61000009A99999999990940CDCCCCCCCCCC1040"} == wkb);
-}
+ const std::string wkb{factory.create_point(loc)};
+ REQUIRE(wkb == "0101000020E61000009A99999999990940CDCCCCCCCCCC1040");
+ }
-SECTION("point in ewkb in web mercator") {
- osmium::geom::WKBFactory<osmium::geom::MercatorProjection> factory(osmium::geom::wkb_type::ewkb, osmium::geom::out_type::hex);
+ SECTION("point in ewkb in web mercator") {
+ osmium::geom::WKBFactory<osmium::geom::MercatorProjection> factory(osmium::geom::wkb_type::ewkb, osmium::geom::out_type::hex);
+
+ const std::string wkb{factory.create_point(loc)};
+ REQUIRE(wkb == "0101000020110F000028706E7BF9BD1541B03E0D93E48F1C41");
+ }
- std::string wkb {factory.create_point(osmium::Location(3.2, 4.2))};
- REQUIRE(std::string{"0101000020110F000028706E7BF9BD1541B03E0D93E48F1C41"} == wkb);
}
-SECTION("linestring") {
- osmium::geom::WKBFactory<> factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
+TEST_CASE("WKB geometry factory (byte-order-dependant)") {
- osmium::memory::Buffer buffer(10000);
- auto &wnl = create_test_wnl_okay(buffer);
+ osmium::memory::Buffer buffer{10000};
- {
- std::string wkb {factory.create_linestring(wnl)};
- REQUIRE(std::string{"0102000000030000009A99999999990940CDCCCCCCCCCC10400000000000000C40CDCCCCCCCCCC1240CDCCCCCCCCCC0C409A99999999991340"} == wkb);
- }
+ SECTION("linestring") {
+ osmium::geom::WKBFactory<> factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
+ const auto& wnl = create_test_wnl_okay(buffer);
- {
- std::string wkb {factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward)};
- REQUIRE(std::string{"010200000003000000CDCCCCCCCCCC0C409A999999999913400000000000000C40CDCCCCCCCCCC12409A99999999990940CDCCCCCCCCCC1040"} == wkb);
- }
+ {
+ const std::string wkb{factory.create_linestring(wnl)};
+ REQUIRE(wkb == "0102000000030000009A99999999990940CDCCCCCCCCCC10400000000000000C40CDCCCCCCCCCC1240CDCCCCCCCCCC0C409A99999999991340");
+ }
- {
- std::string wkb {factory.create_linestring(wnl, osmium::geom::use_nodes::all)};
- REQUIRE(std::string{"0102000000040000009A99999999990940CDCCCCCCCCCC10400000000000000C40CDCCCCCCCCCC12400000000000000C40CDCCCCCCCCCC1240CDCCCCCCCCCC0C409A99999999991340"} == wkb);
- }
+ {
+ const std::string wkb{factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward)};
+ REQUIRE(wkb == "010200000003000000CDCCCCCCCCCC0C409A999999999913400000000000000C40CDCCCCCCCCCC12409A99999999990940CDCCCCCCCCCC1040");
+ }
+
+ {
+ const std::string wkb{factory.create_linestring(wnl, osmium::geom::use_nodes::all)};
+ REQUIRE(wkb == "0102000000040000009A99999999990940CDCCCCCCCCCC10400000000000000C40CDCCCCCCCCCC12400000000000000C40CDCCCCCCCCCC1240CDCCCCCCCCCC0C409A99999999991340");
+ }
- {
- std::string wkb {factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward)};
- REQUIRE(std::string{"010200000004000000CDCCCCCCCCCC0C409A999999999913400000000000000C40CDCCCCCCCCCC12400000000000000C40CDCCCCCCCCCC12409A99999999990940CDCCCCCCCCCC1040"} == wkb);
+ {
+ const std::string wkb{factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward)};
+ REQUIRE(wkb == "010200000004000000CDCCCCCCCCCC0C409A999999999913400000000000000C40CDCCCCCCCCCC12400000000000000C40CDCCCCCCCCCC12409A99999999990940CDCCCCCCCCCC1040");
+ }
}
-}
-SECTION("linestring_ewkb") {
- osmium::geom::WKBFactory<> factory(osmium::geom::wkb_type::ewkb, osmium::geom::out_type::hex);
+ SECTION("linestring as ewkb") {
+ osmium::geom::WKBFactory<> factory(osmium::geom::wkb_type::ewkb, osmium::geom::out_type::hex);
- osmium::memory::Buffer buffer(10000);
- auto &wnl = create_test_wnl_okay(buffer);
+ const auto& wnl = create_test_wnl_okay(buffer);
- std::string ewkb {factory.create_linestring(wnl)};
- REQUIRE(std::string{"0102000020E6100000030000009A99999999990940CDCCCCCCCCCC10400000000000000C40CDCCCCCCCCCC1240CDCCCCCCCCCC0C409A99999999991340"} == ewkb);
-}
+ const std::string ewkb{factory.create_linestring(wnl)};
+ REQUIRE(ewkb == "0102000020E6100000030000009A99999999990940CDCCCCCCCCCC10400000000000000C40CDCCCCCCCCCC1240CDCCCCCCCCCC0C409A99999999991340");
+ }
-SECTION("linestring_with_two_same_locations") {
- osmium::geom::WKBFactory<> factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
+ SECTION("linestring with two same locations") {
+ osmium::geom::WKBFactory<> factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
- osmium::memory::Buffer buffer(10000);
- auto &wnl = create_test_wnl_same_location(buffer);
+ const auto& wnl = create_test_wnl_same_location(buffer);
- REQUIRE_THROWS_AS(factory.create_linestring(wnl), osmium::geometry_error);
- REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward), osmium::geometry_error);
+ SECTION("unique forwards (default)") {
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl), osmium::geometry_error);
+ }
- {
- std::string wkb {factory.create_linestring(wnl, osmium::geom::use_nodes::all)};
- REQUIRE(std::string{"0102000000020000000000000000000C40CDCCCCCCCCCC12400000000000000C40CDCCCCCCCCCC1240"} == wkb);
- }
+ SECTION("unique backwards") {
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward), osmium::geometry_error);
+ }
- {
- std::string wkb {factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward)};
- REQUIRE(std::string{"0102000000020000000000000000000C40CDCCCCCCCCCC12400000000000000C40CDCCCCCCCCCC1240"} == wkb);
+ SECTION("all forwards") {
+ const std::string wkb{factory.create_linestring(wnl, osmium::geom::use_nodes::all)};
+ REQUIRE(wkb == "0102000000020000000000000000000C40CDCCCCCCCCCC12400000000000000C40CDCCCCCCCCCC1240");
+ }
+
+ SECTION("all backwards") {
+ const std::string wkb{factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward)};
+ REQUIRE(wkb == "0102000000020000000000000000000C40CDCCCCCCCCCC12400000000000000C40CDCCCCCCCCCC1240");
+ }
}
-}
-SECTION("linestring_with_undefined_location") {
- osmium::geom::WKBFactory<> factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
+ SECTION("linestring with undefined location") {
+ osmium::geom::WKBFactory<> factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
- osmium::memory::Buffer buffer(10000);
- auto &wnl = create_test_wnl_undefined_location(buffer);
+ const auto& wnl = create_test_wnl_undefined_location(buffer);
- REQUIRE_THROWS_AS(factory.create_linestring(wnl), osmium::invalid_location);
-}
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl), osmium::invalid_location);
+ }
}
#endif
-TEST_CASE("WKB_Geometry_byte_order_independent") {
+TEST_CASE("WKB geometry (byte-order-independent)") {
-SECTION("empty_point") {
osmium::geom::WKBFactory<> factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
- REQUIRE_THROWS_AS(factory.create_point(osmium::Location()), osmium::invalid_location);
-}
-
-SECTION("empty_linestring") {
- osmium::geom::WKBFactory<> factory(osmium::geom::wkb_type::wkb, osmium::geom::out_type::hex);
+ SECTION("empty point") {
+ REQUIRE_THROWS_AS(factory.create_point(osmium::Location{}), osmium::invalid_location);
+ }
- osmium::memory::Buffer buffer(10000);
- auto &wnl = create_test_wnl_empty(buffer);
+ SECTION("empty linestring") {
+ osmium::memory::Buffer buffer{10000};
+ const auto& wnl = create_test_wnl_empty(buffer);
- REQUIRE_THROWS_AS(factory.create_linestring(wnl), osmium::geometry_error);
- REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward), osmium::geometry_error);
- REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::all), osmium::geometry_error);
- REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward), osmium::geometry_error);
-}
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl), osmium::geometry_error);
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward), osmium::geometry_error);
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::all), osmium::geometry_error);
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward), osmium::geometry_error);
+ }
}
diff --git a/test/t/geom/test_wkt.cpp b/test/t/geom/test_wkt.cpp
index 3767be3..f6913c4 100644
--- a/test/t/geom/test_wkt.cpp
+++ b/test/t/geom/test_wkt.cpp
@@ -6,146 +6,128 @@
#include "area_helper.hpp"
#include "wnl_helper.hpp"
-TEST_CASE("WKT_Geometry") {
+TEST_CASE("WKT geometry for point") {
-SECTION("point") {
osmium::geom::WKTFactory<> factory;
- std::string wkt {factory.create_point(osmium::Location(3.2, 4.2))};
- REQUIRE(std::string{"POINT(3.2 4.2)"} == wkt);
-}
-
-SECTION("point in ewkt") {
- osmium::geom::WKTFactory<> factory(7, osmium::geom::wkt_type::ewkt);
-
- std::string wkt {factory.create_point(osmium::Location(3.2, 4.2))};
- REQUIRE(std::string{"SRID=4326;POINT(3.2 4.2)"} == wkt);
-}
+ SECTION("point") {
+ const std::string wkt{factory.create_point(osmium::Location{3.2, 4.2})};
+ REQUIRE(wkt == "POINT(3.2 4.2)");
+ }
-SECTION("point in ewkt in web mercator") {
- osmium::geom::WKTFactory<osmium::geom::MercatorProjection> factory(2, osmium::geom::wkt_type::ewkt);
+ SECTION("empty point") {
+ REQUIRE_THROWS_AS(factory.create_point(osmium::Location()), osmium::invalid_location);
+ }
- std::string wkt {factory.create_point(osmium::Location(3.2, 4.2))};
- REQUIRE(std::string{"SRID=3857;POINT(356222.37 467961.14)"} == wkt);
}
-SECTION("empty_point") {
- osmium::geom::WKTFactory<> factory;
+TEST_CASE("WKT geometry for point in ekwt") {
+ osmium::geom::WKTFactory<> factory(7, osmium::geom::wkt_type::ewkt);
- REQUIRE_THROWS_AS(factory.create_point(osmium::Location()), osmium::invalid_location);
+ const std::string wkt{factory.create_point(osmium::Location{3.2, 4.2})};
+ REQUIRE(wkt == "SRID=4326;POINT(3.2 4.2)");
}
-SECTION("linestring") {
- osmium::geom::WKTFactory<> factory;
-
- osmium::memory::Buffer buffer(10000);
- auto &wnl = create_test_wnl_okay(buffer);
-
- {
- std::string wkt {factory.create_linestring(wnl)};
- REQUIRE(std::string{"LINESTRING(3.2 4.2,3.5 4.7,3.6 4.9)"} == wkt);
- }
-
- {
- std::string wkt {factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward)};
- REQUIRE(std::string{"LINESTRING(3.6 4.9,3.5 4.7,3.2 4.2)"} == wkt);
- }
-
- {
- std::string wkt {factory.create_linestring(wnl, osmium::geom::use_nodes::all)};
- REQUIRE(std::string{"LINESTRING(3.2 4.2,3.5 4.7,3.5 4.7,3.6 4.9)"} == wkt);
- }
+TEST_CASE("WKT geometry for point in ekwt in web mercator") {
+ osmium::geom::WKTFactory<osmium::geom::MercatorProjection> factory(2, osmium::geom::wkt_type::ewkt);
- {
- std::string wkt {factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward)};
- REQUIRE(std::string{"LINESTRING(3.6 4.9,3.5 4.7,3.5 4.7,3.2 4.2)"} == wkt);
- }
+ const std::string wkt{factory.create_point(osmium::Location{3.2, 4.2})};
+ REQUIRE(wkt == "SRID=3857;POINT(356222.37 467961.14)");
}
-SECTION("empty_linestring") {
+TEST_CASE("WKT geometry factory") {
osmium::geom::WKTFactory<> factory;
- osmium::memory::Buffer buffer(10000);
- auto &wnl = create_test_wnl_empty(buffer);
+ osmium::memory::Buffer buffer{10000};
- REQUIRE_THROWS_AS(factory.create_linestring(wnl), osmium::geometry_error);
- REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward), osmium::geometry_error);
- REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::all), osmium::geometry_error);
- REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward), osmium::geometry_error);
-}
+ SECTION("linestring") {
+ const auto& wnl = create_test_wnl_okay(buffer);
-SECTION("linestring_with_two_same_locations") {
- osmium::geom::WKTFactory<> factory;
+ SECTION("unique forwards (default)") {
+ const std::string wkt{factory.create_linestring(wnl)};
+ REQUIRE(wkt == "LINESTRING(3.2 4.2,3.5 4.7,3.6 4.9)");
+ }
- osmium::memory::Buffer buffer(10000);
- auto &wnl = create_test_wnl_same_location(buffer);
+ SECTION("unique backwards") {
+ const std::string wkt{factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward)};
+ REQUIRE(wkt == "LINESTRING(3.6 4.9,3.5 4.7,3.2 4.2)");
+ }
- REQUIRE_THROWS_AS(factory.create_linestring(wnl), osmium::geometry_error);
+ SECTION("all forwards") {
+ const std::string wkt{factory.create_linestring(wnl, osmium::geom::use_nodes::all)};
+ REQUIRE(wkt == "LINESTRING(3.2 4.2,3.5 4.7,3.5 4.7,3.6 4.9)");
+ }
- try {
- factory.create_linestring(wnl);
- } catch (osmium::geometry_error& e) {
- REQUIRE(e.id() == 0);
- REQUIRE(std::string(e.what()) == "need at least two points for linestring");
+ SECTION("all backwards") {
+ const std::string wkt{factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward)};
+ REQUIRE(wkt == "LINESTRING(3.6 4.9,3.5 4.7,3.5 4.7,3.2 4.2)");
+ }
}
- REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward), osmium::geometry_error);
+ SECTION("empty linestring") {
+ const auto& wnl = create_test_wnl_empty(buffer);
- {
- std::string wkt {factory.create_linestring(wnl, osmium::geom::use_nodes::all)};
- REQUIRE(std::string{"LINESTRING(3.5 4.7,3.5 4.7)"} == wkt);
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl), osmium::geometry_error);
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward), osmium::geometry_error);
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::all), osmium::geometry_error);
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward), osmium::geometry_error);
}
- {
- std::string wkt {factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward)};
- REQUIRE(std::string{"LINESTRING(3.5 4.7,3.5 4.7)"} == wkt);
+ SECTION("linestring with two same locations") {
+ const auto& wnl = create_test_wnl_same_location(buffer);
+
+ SECTION("unique forwards") {
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl), osmium::geometry_error);
+
+ try {
+ factory.create_linestring(wnl);
+ } catch (const osmium::geometry_error& e) {
+ REQUIRE(e.id() == 0);
+ REQUIRE(std::string(e.what()) == "need at least two points for linestring");
+ }
+ }
+
+ SECTION("unique backwards") {
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl, osmium::geom::use_nodes::unique, osmium::geom::direction::backward), osmium::geometry_error);
+ }
+
+ SECTION("all forwards") {
+ const std::string wkt{factory.create_linestring(wnl, osmium::geom::use_nodes::all)};
+ REQUIRE(wkt == "LINESTRING(3.5 4.7,3.5 4.7)");
+ }
+
+ SECTION("all backwards") {
+ const std::string wkt{factory.create_linestring(wnl, osmium::geom::use_nodes::all, osmium::geom::direction::backward)};
+ REQUIRE(wkt == "LINESTRING(3.5 4.7,3.5 4.7)");
+ }
}
-}
-SECTION("linestring_with_undefined_location") {
- osmium::geom::WKTFactory<> factory;
-
- osmium::memory::Buffer buffer(10000);
- auto &wnl = create_test_wnl_undefined_location(buffer);
-
- REQUIRE_THROWS_AS(factory.create_linestring(wnl), osmium::invalid_location);
-}
+ SECTION("linestring with undefined location") {
+ const auto& wnl = create_test_wnl_undefined_location(buffer);
-SECTION("area_1outer_0inner") {
- osmium::geom::WKTFactory<> factory;
+ REQUIRE_THROWS_AS(factory.create_linestring(wnl), osmium::invalid_location);
+ }
- osmium::memory::Buffer buffer(10000);
- const osmium::Area& area = create_test_area_1outer_0inner(buffer);
+ SECTION("area with one outer and no inner rings") {
+ const osmium::Area& area = create_test_area_1outer_0inner(buffer);
- {
- std::string wkt {factory.create_multipolygon(area)};
- REQUIRE(std::string{"MULTIPOLYGON(((3.2 4.2,3.5 4.7,3.6 4.9,3.2 4.2)))"} == wkt);
+ const std::string wkt{factory.create_multipolygon(area)};
+ REQUIRE(wkt == "MULTIPOLYGON(((3.2 4.2,3.5 4.7,3.6 4.9,3.2 4.2)))");
}
-}
-
-SECTION("area_1outer_1inner") {
- osmium::geom::WKTFactory<> factory;
- osmium::memory::Buffer buffer(10000);
- const osmium::Area& area = create_test_area_1outer_1inner(buffer);
+ SECTION("area with one outer and one inner ring") {
+ const osmium::Area& area = create_test_area_1outer_1inner(buffer);
- {
- std::string wkt {factory.create_multipolygon(area)};
- REQUIRE(std::string{"MULTIPOLYGON(((0.1 0.1,9.1 0.1,9.1 9.1,0.1 9.1,0.1 0.1),(1 1,8 1,8 8,1 8,1 1)))"} == wkt);
+ const std::string wkt{factory.create_multipolygon(area)};
+ REQUIRE(wkt == "MULTIPOLYGON(((0.1 0.1,9.1 0.1,9.1 9.1,0.1 9.1,0.1 0.1),(1 1,8 1,8 8,1 8,1 1)))");
}
-}
-
-SECTION("area_2outer_2inner") {
- osmium::geom::WKTFactory<> factory;
- osmium::memory::Buffer buffer(10000);
- const osmium::Area& area = create_test_area_2outer_2inner(buffer);
+ SECTION("area with two outer and two inner rings") {
+ const osmium::Area& area = create_test_area_2outer_2inner(buffer);
- {
- std::string wkt {factory.create_multipolygon(area)};
- REQUIRE(std::string{"MULTIPOLYGON(((0.1 0.1,9.1 0.1,9.1 9.1,0.1 9.1,0.1 0.1),(1 1,4 1,4 4,1 4,1 1),(5 5,5 7,7 7,5 5)),((10 10,11 10,11 11,10 11,10 10)))"} == wkt);
+ const std::string wkt{factory.create_multipolygon(area)};
+ REQUIRE(wkt == "MULTIPOLYGON(((0.1 0.1,9.1 0.1,9.1 9.1,0.1 9.1,0.1 0.1),(1 1,4 1,4 4,1 4,1 1),(5 5,5 7,7 7,5 5)),((10 10,11 10,11 11,10 11,10 10)))");
}
-}
}
diff --git a/test/t/index/test_id_to_location.cpp b/test/t/index/test_id_to_location.cpp
index 90cce3b..810ef3b 100644
--- a/test/t/index/test_id_to_location.cpp
+++ b/test/t/index/test_id_to_location.cpp
@@ -19,8 +19,8 @@ template <typename TIndex>
void test_func_all(TIndex& index) {
osmium::unsigned_object_id_type id1 = 12;
osmium::unsigned_object_id_type id2 = 3;
- osmium::Location loc1(1.2, 4.5);
- osmium::Location loc2(3.5, -7.2);
+ osmium::Location loc1{1.2, 4.5};
+ osmium::Location loc2{3.5, -7.2};
REQUIRE_THROWS_AS(index.get(id1), osmium::not_found);
@@ -39,8 +39,8 @@ template <typename TIndex>
void test_func_real(TIndex& index) {
osmium::unsigned_object_id_type id1 = 12;
osmium::unsigned_object_id_type id2 = 3;
- osmium::Location loc1(1.2, 4.5);
- osmium::Location loc2(3.5, -7.2);
+ osmium::Location loc1{1.2, 4.5};
+ osmium::Location loc2{3.5, -7.2};
index.set(id1, loc1);
index.set(id2, loc2);
@@ -69,7 +69,7 @@ void test_func_real(TIndex& index) {
TEST_CASE("IdToLocation") {
SECTION("Dummy") {
- typedef osmium::index::map::Dummy<osmium::unsigned_object_id_type, osmium::Location> index_type;
+ using index_type = osmium::index::map::Dummy<osmium::unsigned_object_id_type, osmium::Location>;
index_type index1;
@@ -83,7 +83,7 @@ TEST_CASE("IdToLocation") {
}
SECTION("DenseMemArray") {
- typedef osmium::index::map::DenseMemArray<osmium::unsigned_object_id_type, osmium::Location> index_type;
+ using index_type = osmium::index::map::DenseMemArray<osmium::unsigned_object_id_type, osmium::Location>;
index_type index1;
index1.reserve(1000);
@@ -96,7 +96,7 @@ TEST_CASE("IdToLocation") {
#ifdef __linux__
SECTION("DenseMmapArray") {
- typedef osmium::index::map::DenseMmapArray<osmium::unsigned_object_id_type, osmium::Location> index_type;
+ using index_type = osmium::index::map::DenseMmapArray<osmium::unsigned_object_id_type, osmium::Location>;
index_type index1;
test_func_all<index_type>(index1);
@@ -109,7 +109,7 @@ TEST_CASE("IdToLocation") {
#endif
SECTION("DenseFileArray") {
- typedef osmium::index::map::DenseFileArray<osmium::unsigned_object_id_type, osmium::Location> index_type;
+ using index_type = osmium::index::map::DenseFileArray<osmium::unsigned_object_id_type, osmium::Location>;
index_type index1;
test_func_all<index_type>(index1);
@@ -121,7 +121,7 @@ TEST_CASE("IdToLocation") {
#ifdef OSMIUM_WITH_SPARSEHASH
SECTION("SparseMemTable") {
- typedef osmium::index::map::SparseMemTable<osmium::unsigned_object_id_type, osmium::Location> index_type;
+ using index_type = osmium::index::map::SparseMemTable<osmium::unsigned_object_id_type, osmium::Location>;
index_type index1;
test_func_all<index_type>(index1);
@@ -133,7 +133,7 @@ TEST_CASE("IdToLocation") {
#endif
SECTION("SparseMemMap") {
- typedef osmium::index::map::SparseMemMap<osmium::unsigned_object_id_type, osmium::Location> index_type;
+ using index_type = osmium::index::map::SparseMemMap<osmium::unsigned_object_id_type, osmium::Location>;
index_type index1;
test_func_all<index_type>(index1);
@@ -143,7 +143,7 @@ TEST_CASE("IdToLocation") {
}
SECTION("SparseMemArray") {
- typedef osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, osmium::Location> index_type;
+ using index_type = osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, osmium::Location>;
index_type index1;
@@ -159,10 +159,10 @@ TEST_CASE("IdToLocation") {
}
SECTION("Dynamic map choice") {
- typedef osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location> map_type;
+ using map_type = osmium::index::map::Map<osmium::unsigned_object_id_type, osmium::Location>;
const auto& map_factory = osmium::index::MapFactory<osmium::unsigned_object_id_type, osmium::Location>::instance();
- std::vector<std::string> map_type_names = map_factory.map_types();
+ const std::vector<std::string> map_type_names = map_factory.map_types();
REQUIRE(map_type_names.size() >= 5);
for (const auto& map_type_name : map_type_names) {
diff --git a/test/t/io/test_opl_parser.cpp b/test/t/io/test_opl_parser.cpp
new file mode 100644
index 0000000..9ad6eeb
--- /dev/null
+++ b/test/t/io/test_opl_parser.cpp
@@ -0,0 +1,1075 @@
+
+#include <algorithm>
+#include <cstring>
+
+#include "catch.hpp"
+
+#include <osmium/io/detail/opl_input_format.hpp>
+#include <osmium/opl.hpp>
+
+namespace oid = osmium::io::detail;
+
+TEST_CASE("Parse OPL: base exception") {
+ osmium::opl_error e{"foo"};
+ REQUIRE(e.data == nullptr);
+ REQUIRE(e.line == 0);
+ REQUIRE(e.column == 0);
+ REQUIRE(e.msg == "OPL error: foo");
+ REQUIRE(std::string{e.what()} == "OPL error: foo");
+}
+
+TEST_CASE("Parse OPL: exception with line and column") {
+ const char* d = "data";
+ osmium::opl_error e{"bar", d};
+ e.set_pos(17, 23);
+ REQUIRE(e.data == d);
+ REQUIRE(e.line == 17);
+ REQUIRE(e.column == 23);
+ REQUIRE(e.msg == "OPL error: bar on line 17 column 23");
+ REQUIRE(std::string{e.what()} == "OPL error: bar on line 17 column 23");
+}
+
+TEST_CASE("Parse OPL: space") {
+ std::string d{"a b \t c"};
+
+ const char* s = d.data();
+ REQUIRE_THROWS_AS({
+ oid::opl_parse_space(&s);
+ }, osmium::opl_error);
+
+ s = d.data() + 1;
+ oid::opl_parse_space(&s);
+ REQUIRE(*s == 'b');
+
+ REQUIRE_THROWS_AS({
+ oid::opl_parse_space(&s);
+ }, osmium::opl_error);
+
+ ++s;
+ oid::opl_parse_space(&s);
+ REQUIRE(*s == 'c');
+}
+
+TEST_CASE("Parse OPL: check for space") {
+ REQUIRE(oid::opl_non_empty("aaa"));
+ REQUIRE(oid::opl_non_empty("a b"));
+ REQUIRE_FALSE(oid::opl_non_empty(" "));
+ REQUIRE_FALSE(oid::opl_non_empty(" x"));
+ REQUIRE_FALSE(oid::opl_non_empty("\tx"));
+ REQUIRE_FALSE(oid::opl_non_empty(""));
+}
+
+TEST_CASE("Parse OPL: skip section") {
+ std::string d{"abcd efgh"};
+ const char* skip1 = d.data() + 4;
+ const char* skip2 = d.data() + 9;
+ const char* s = d.data();
+ REQUIRE(oid::opl_skip_section(&s) == skip1);
+ REQUIRE(s == skip1);
+ ++s;
+ REQUIRE(oid::opl_skip_section(&s) == skip2);
+ REQUIRE(s == skip2);
+}
+
+TEST_CASE("Parse OPL: parse escaped") {
+ std::string result;
+
+ SECTION("Empty string") {
+ const char* s = "";
+ REQUIRE_THROWS_WITH({
+ oid::opl_parse_escaped(&s, result);
+ }, "OPL error: eol");
+ }
+
+ SECTION("Illegal character for hex") {
+ const char* s = "x";
+ REQUIRE_THROWS_WITH({
+ oid::opl_parse_escaped(&s, result);
+ }, "OPL error: not a hex char");
+ }
+
+ SECTION("Illegal character for hex after legal hex characters") {
+ const char* s = "0123x";
+ REQUIRE_THROWS_WITH({
+ oid::opl_parse_escaped(&s, result);
+ }, "OPL error: not a hex char");
+ }
+
+ SECTION("Too long") {
+ const char* s = "123456780";
+ REQUIRE_THROWS_WITH({
+ oid::opl_parse_escaped(&s, result);
+ }, "OPL error: hex escape too long");
+ }
+
+ SECTION("No data") {
+ const char* s = "%";
+ const char* e = s + std::strlen(s);
+ oid::opl_parse_escaped(&s, result);
+ REQUIRE(result.size() == 1);
+ REQUIRE(result[0] == '\0');
+ REQUIRE(s == e);
+ }
+
+ SECTION("One hex char") {
+ const char* s = "9%";
+ const char* e = s + std::strlen(s);
+ oid::opl_parse_escaped(&s, result);
+ REQUIRE(result.size() == 1);
+ REQUIRE(result == "\t");
+ REQUIRE(s == e);
+ }
+
+ SECTION("Two hex chars (lowercase)") {
+ const char* s = "3c%";
+ const char* e = s + std::strlen(s);
+ oid::opl_parse_escaped(&s, result);
+ REQUIRE(result.size() == 1);
+ REQUIRE(result == "<");
+ REQUIRE(s == e);
+ }
+
+ SECTION("Two hex char (uppercase)") {
+ const char* s = "3C%";
+ const char* e = s + std::strlen(s);
+ oid::opl_parse_escaped(&s, result);
+ REQUIRE(result.size() == 1);
+ REQUIRE(result == "<");
+ REQUIRE(s == e);
+ }
+
+ SECTION("Longer unicode characters") {
+ const char* s1 = "30dc%";
+ oid::opl_parse_escaped(&s1, result);
+ result.append("_");
+ const char* s2 = "1d11e%";
+ oid::opl_parse_escaped(&s2, result);
+ result.append("_");
+ const char* s3 = "1f6eb%";
+ oid::opl_parse_escaped(&s3, result);
+ REQUIRE(result == u8"\u30dc_\U0001d11e_\U0001f6eb");
+ }
+
+ SECTION("Data after %") {
+ const char* s = "5a%abc";
+ oid::opl_parse_escaped(&s, result);
+ REQUIRE(result.size() == 1);
+ REQUIRE(result == "Z");
+ REQUIRE(std::string{s} == "abc");
+ }
+
+}
+
+TEST_CASE("Parse OPL: parse string") {
+ std::string result;
+
+ SECTION("empty string") {
+ const char* s = "";
+ const char* e = s + std::strlen(s);
+ oid::opl_parse_string(&s, result);
+ REQUIRE(result.size() == 0);
+ REQUIRE(result == "");
+ REQUIRE(s == e);
+ }
+
+ SECTION("normal string") {
+ const char* s = "foo";
+ const char* e = s + std::strlen(s);
+ oid::opl_parse_string(&s, result);
+ REQUIRE(result.size() == 3);
+ REQUIRE(result == "foo");
+ REQUIRE(s == e);
+ }
+
+ SECTION("string with space") {
+ const char* s = "foo bar";
+ const char* e = s + 3;
+ oid::opl_parse_string(&s, result);
+ REQUIRE(result.size() == 3);
+ REQUIRE(result == "foo");
+ REQUIRE(s == e);
+ }
+
+ SECTION("string with tab") {
+ const char* s = "foo\tbar";
+ const char* e = s + 3;
+ oid::opl_parse_string(&s, result);
+ REQUIRE(result.size() == 3);
+ REQUIRE(result == "foo");
+ REQUIRE(s == e);
+ }
+
+ SECTION("string with comma") {
+ const char* s = "foo,bar";
+ const char* e = s + 3;
+ oid::opl_parse_string(&s, result);
+ REQUIRE(result.size() == 3);
+ REQUIRE(result == "foo");
+ REQUIRE(s == e);
+ }
+
+ SECTION("string with equal sign") {
+ const char* s = "foo=bar";
+ const char* e = s + 3;
+ oid::opl_parse_string(&s, result);
+ REQUIRE(result.size() == 3);
+ REQUIRE(result == "foo");
+ REQUIRE(s == e);
+ }
+
+ SECTION("string with escaped characters") {
+ const char* s = "foo%3d%bar";
+ const char* e = s + std::strlen(s);
+ oid::opl_parse_string(&s, result);
+ REQUIRE(result.size() == 7);
+ REQUIRE(result == "foo=bar");
+ REQUIRE(s == e);
+ }
+
+ SECTION("string with escaped characters at end") {
+ const char* s = "foo%3d%";
+ const char* e = s + std::strlen(s);
+ oid::opl_parse_string(&s, result);
+ REQUIRE(result.size() == 4);
+ REQUIRE(result == "foo=");
+ REQUIRE(s == e);
+ }
+
+ SECTION("string with invalid escaping") {
+ const char* s = "foo%";
+ REQUIRE_THROWS_WITH({
+ oid::opl_parse_string(&s, result);
+ }, "OPL error: eol");
+ }
+
+ SECTION("string with invalid escaped characters") {
+ const char* s = "foo%x%";
+ REQUIRE_THROWS_WITH({
+ oid::opl_parse_string(&s, result);
+ }, "OPL error: not a hex char");
+ }
+
+}
+
+template <typename T = int64_t>
+T test_parse_int(const char* s) {
+ auto r = oid::opl_parse_int<T>(&s);
+ REQUIRE(*s == 'x');
+ return r;
+}
+
+TEST_CASE("Parse OPL: integer") {
+ REQUIRE(test_parse_int("0x") == 0);
+ REQUIRE(test_parse_int("-0x") == 0);
+ REQUIRE(test_parse_int("1x") == 1);
+ REQUIRE(test_parse_int("17x") == 17);
+ REQUIRE(test_parse_int("-1x") == -1);
+ REQUIRE(test_parse_int("1234567890123x") == 1234567890123);
+ REQUIRE(test_parse_int("-1234567890123x") == -1234567890123);
+
+ REQUIRE_THROWS_WITH({
+ test_parse_int("");
+ }, "OPL error: expected integer");
+
+ REQUIRE_THROWS_WITH({
+ test_parse_int("-x");
+ }, "OPL error: expected integer");
+
+ REQUIRE_THROWS_WITH({
+ test_parse_int(" 1");
+ }, "OPL error: expected integer");
+
+ REQUIRE_THROWS_WITH({
+ test_parse_int("x");
+ }, "OPL error: expected integer");
+
+ REQUIRE_THROWS_WITH({
+ test_parse_int("99999999999999999999999x");
+ }, "OPL error: integer too long");
+}
+
+TEST_CASE("Parse OPL: int32_t") {
+ REQUIRE(test_parse_int<int32_t>("0x") == 0);
+ REQUIRE(test_parse_int<int32_t>("123x") == 123);
+ REQUIRE(test_parse_int<int32_t>("-123x") == -123);
+
+ REQUIRE_THROWS_WITH({
+ test_parse_int<int32_t>("12345678901x");
+ }, "OPL error: integer too long");
+ REQUIRE_THROWS_WITH({
+ test_parse_int<int32_t>("-12345678901x");
+ }, "OPL error: integer too long");
+}
+
+TEST_CASE("Parse OPL: uint32_t") {
+ REQUIRE(test_parse_int<uint32_t>("0x") == 0);
+ REQUIRE(test_parse_int<uint32_t>("123x") == 123);
+
+ REQUIRE_THROWS_WITH({
+ test_parse_int<uint32_t>("-123x");
+ }, "OPL error: integer too long");
+
+ REQUIRE_THROWS_WITH({
+ test_parse_int<uint32_t>("12345678901x");
+ }, "OPL error: integer too long");
+
+ REQUIRE_THROWS_WITH({
+ test_parse_int<uint32_t>("-12345678901x");
+ }, "OPL error: integer too long");
+}
+
+TEST_CASE("Parse OPL: visible flag") {
+ const char* data = "V";
+ const char* e = data + std::strlen(data);
+ REQUIRE(oid::opl_parse_visible(&data));
+ REQUIRE(e == data);
+
+}
+
+TEST_CASE("Parse OPL: deleted flag") {
+ const char* data = "D";
+ const char* e = data + std::strlen(data);
+ REQUIRE_FALSE(oid::opl_parse_visible(&data));
+ REQUIRE(e == data);
+}
+
+TEST_CASE("Parse OPL: invalid visible flag") {
+ const char* data = "x";
+ REQUIRE_THROWS_WITH({
+ oid::opl_parse_visible(&data);
+ }, "OPL error: invalid visible flag");
+}
+
+TEST_CASE("Parse OPL: timestamp (empty)") {
+ const char* data = "";
+ const char* e = data + std::strlen(data);
+ REQUIRE(oid::opl_parse_timestamp(&data) == osmium::Timestamp{});
+ REQUIRE(e == data);
+}
+
+TEST_CASE("Parse OPL: timestamp (space)") {
+ const char* data = " ";
+ const char* e = data;
+ REQUIRE(oid::opl_parse_timestamp(&data) == osmium::Timestamp{});
+ REQUIRE(e == data);
+}
+
+TEST_CASE("Parse OPL: timestamp (tab)") {
+ const char* data = "\t";
+ const char* e = data;
+ REQUIRE(oid::opl_parse_timestamp(&data) == osmium::Timestamp{});
+ REQUIRE(e == data);
+}
+
+TEST_CASE("Parse OPL: timestamp (invalid)") {
+ const char* data = "abc";
+ REQUIRE_THROWS_WITH({
+ oid::opl_parse_timestamp(&data);
+ }, "OPL error: can not parse timestamp");
+}
+
+TEST_CASE("Parse OPL: timestamp (valid)") {
+ const char* data = "2016-03-04T17:28:03Z";
+ const char* e = data + std::strlen(data);
+ REQUIRE(oid::opl_parse_timestamp(&data) == osmium::Timestamp{"2016-03-04T17:28:03Z"});
+ REQUIRE(e == data);
+}
+
+TEST_CASE("Parse OPL: valid timestamp with trailing data") {
+ const char* data = "2016-03-04T17:28:03Zxxx";
+ REQUIRE(oid::opl_parse_timestamp(&data) == osmium::Timestamp{"2016-03-04T17:28:03Z"});
+ REQUIRE(std::string{data} == "xxx");
+}
+
+TEST_CASE("Parse OPL: tags") {
+ osmium::memory::Buffer buffer{1024};
+
+ SECTION("Empty") {
+ const char* data = "";
+ REQUIRE_THROWS_WITH({
+ oid::opl_parse_tags(data, buffer);
+ }, "OPL error: expected '='");
+ }
+
+ SECTION("One tag") {
+ const char* data = "foo=bar";
+ oid::opl_parse_tags(data, buffer);
+ const auto& taglist = buffer.get<osmium::TagList>(0);
+ REQUIRE(taglist.size() == 1);
+ REQUIRE(std::string{taglist.begin()->key()} == "foo");
+ REQUIRE(std::string{taglist.begin()->value()} == "bar");
+ }
+
+ SECTION("Empty key and value are allowed") {
+ const char* data = "=";
+ oid::opl_parse_tags(data, buffer);
+ const auto& taglist = buffer.get<osmium::TagList>(0);
+ REQUIRE(taglist.size() == 1);
+ REQUIRE(std::string{taglist.begin()->key()} == "");
+ REQUIRE(std::string{taglist.begin()->value()} == "");
+ }
+
+ SECTION("Multiple tags") {
+ const char* data = "highway=residential,oneway=yes,maxspeed=30";
+ oid::opl_parse_tags(data, buffer);
+ const auto& taglist = buffer.get<osmium::TagList>(0);
+ REQUIRE(taglist.size() == 3);
+ auto it = taglist.cbegin();
+ REQUIRE(std::string{it->key()} == "highway");
+ REQUIRE(std::string{it->value()} == "residential");
+ ++it;
+ REQUIRE(std::string{it->key()} == "oneway");
+ REQUIRE(std::string{it->value()} == "yes");
+ ++it;
+ REQUIRE(std::string{it->key()} == "maxspeed");
+ REQUIRE(std::string{it->value()} == "30");
+ ++it;
+ REQUIRE(it == taglist.cend());
+ }
+
+ SECTION("No equal signs") {
+ const char* data = "a";
+ REQUIRE_THROWS_WITH({
+ oid::opl_parse_tags(data, buffer);
+ }, "OPL error: expected '='");
+ }
+
+ SECTION("Two equal signs") {
+ const char* data = "a=b=c";
+ REQUIRE_THROWS_WITH({
+ oid::opl_parse_tags(data, buffer);
+ }, "OPL error: expected ','");
+ }
+
+}
+
+TEST_CASE("Parse OPL: nodes") {
+ osmium::memory::Buffer buffer{1024};
+
+ SECTION("Empty") {
+ const char* const s = "";
+ oid::opl_parse_way_nodes(s, s + std::strlen(s), buffer);
+ REQUIRE(buffer.written() == 0);
+ }
+
+ SECTION("Invalid format, missing n") {
+ const char* const s = "xyz";
+ REQUIRE_THROWS_WITH({
+ oid::opl_parse_way_nodes(s, s + std::strlen(s), buffer);
+ }, "OPL error: expected 'n'");
+ }
+
+ SECTION("Invalid format, missing ID") {
+ const char* const s = "nx";
+ REQUIRE_THROWS_WITH({
+ oid::opl_parse_way_nodes(s, s + std::strlen(s), buffer);
+ }, "OPL error: expected integer");
+ }
+
+ SECTION("Valid format: one node") {
+ const char* const s = "n123";
+ oid::opl_parse_way_nodes(s, s + std::strlen(s), buffer);
+ REQUIRE(buffer.written() > 0);
+ const auto& wnl = buffer.get<osmium::WayNodeList>(0);
+ REQUIRE(wnl.size() == 1);
+ REQUIRE(wnl.begin()->ref() == 123);
+ }
+
+ SECTION("Valid format: two nodes") {
+ const char* const s = "n123,n456";
+ oid::opl_parse_way_nodes(s, s + std::strlen(s), buffer);
+ REQUIRE(buffer.written() > 0);
+ const auto& wnl = buffer.get<osmium::WayNodeList>(0);
+ REQUIRE(wnl.size() == 2);
+ auto it = wnl.begin();
+ REQUIRE(it->ref() == 123);
+ ++it;
+ REQUIRE(it->ref() == 456);
+ ++it;
+ REQUIRE(it == wnl.end());
+ }
+
+ SECTION("Trailing comma") {
+ const char* const s = "n123,n456,";
+ oid::opl_parse_way_nodes(s, s + std::strlen(s), buffer);
+ REQUIRE(buffer.written() > 0);
+ const auto& wnl = buffer.get<osmium::WayNodeList>(0);
+ REQUIRE(wnl.size() == 2);
+ auto it = wnl.begin();
+ REQUIRE(it->ref() == 123);
+ ++it;
+ REQUIRE(it->ref() == 456);
+ ++it;
+ REQUIRE(it == wnl.end());
+ }
+
+ SECTION("Way nodes with coordinates") {
+ const char* const s = "n123x1.2y3.4,n456x33y0.1";
+ oid::opl_parse_way_nodes(s, s + std::strlen(s), buffer);
+ REQUIRE(buffer.written() > 0);
+ const auto& wnl = buffer.get<osmium::WayNodeList>(0);
+ REQUIRE(wnl.size() == 2);
+ auto it = wnl.begin();
+ REQUIRE(it->ref() == 123);
+ const osmium::Location loc1{1.2, 3.4};
+ REQUIRE(it->location() == loc1);
+ ++it;
+ REQUIRE(it->ref() == 456);
+ const osmium::Location loc2{33.0, 0.1};
+ REQUIRE(it->location() == loc2);
+ ++it;
+ REQUIRE(it == wnl.end());
+ }
+
+}
+
+TEST_CASE("Parse OPL: members") {
+ osmium::memory::Buffer buffer{1024};
+
+ SECTION("Empty") {
+ const char* const s = "";
+ oid::opl_parse_relation_members(s, s + std::strlen(s), buffer);
+ REQUIRE(buffer.written() == 0);
+ }
+
+ SECTION("Invalid: unknown object type") {
+ const char* const s = "x123 at foo";
+ REQUIRE_THROWS_WITH({
+ oid::opl_parse_relation_members(s, s + std::strlen(s), buffer);
+ }, "OPL error: unknown object type");
+ }
+
+ SECTION("Invalid: illegal ref") {
+ const char* const s = "wx";
+ REQUIRE_THROWS_WITH({
+ oid::opl_parse_relation_members(s, s + std::strlen(s), buffer);
+ }, "OPL error: expected integer");
+ }
+
+ SECTION("Invalid: missing @") {
+ const char* const s = "n123foo";
+ REQUIRE_THROWS_WITH({
+ oid::opl_parse_relation_members(s, s + std::strlen(s), buffer);
+ }, "OPL error: expected '@'");
+ }
+
+ SECTION("Valid format: one member") {
+ const char* const s = "n123 at foo";
+ oid::opl_parse_relation_members(s, s + std::strlen(s), buffer);
+ REQUIRE(buffer.written() > 0);
+ const auto& rml = buffer.get<osmium::RelationMemberList>(0);
+ REQUIRE(rml.size() == 1);
+ auto it = rml.begin();
+ REQUIRE(it->type() == osmium::item_type::node);
+ REQUIRE(it->ref() == 123);
+ REQUIRE(std::string{it->role()} == "foo");
+ ++it;
+ REQUIRE(it == rml.end());
+ }
+
+ SECTION("Valid format: one member without role") {
+ const char* const s = "n123@";
+ oid::opl_parse_relation_members(s, s + std::strlen(s), buffer);
+ REQUIRE(buffer.written() > 0);
+ const auto& rml = buffer.get<osmium::RelationMemberList>(0);
+ REQUIRE(rml.size() == 1);
+ auto it = rml.begin();
+ REQUIRE(it->type() == osmium::item_type::node);
+ REQUIRE(it->ref() == 123);
+ REQUIRE(std::string{it->role()} == "");
+ ++it;
+ REQUIRE(it == rml.end());
+ }
+
+ SECTION("Valid format: three members") {
+ const char* const s = "n123@,w456 at abc,r78 at type";
+ oid::opl_parse_relation_members(s, s + std::strlen(s), buffer);
+ REQUIRE(buffer.written() > 0);
+ const auto& rml = buffer.get<osmium::RelationMemberList>(0);
+ REQUIRE(rml.size() == 3);
+ auto it = rml.begin();
+ REQUIRE(it->type() == osmium::item_type::node);
+ REQUIRE(it->ref() == 123);
+ REQUIRE(std::string{it->role()} == "");
+ ++it;
+ REQUIRE(it->type() == osmium::item_type::way);
+ REQUIRE(it->ref() == 456);
+ REQUIRE(std::string{it->role()} == "abc");
+ ++it;
+ REQUIRE(it->type() == osmium::item_type::relation);
+ REQUIRE(it->ref() == 78);
+ REQUIRE(std::string{it->role()} == "type");
+ ++it;
+ REQUIRE(it == rml.end());
+ }
+
+ SECTION("Trailing comma") {
+ const char* const s = "n123@,w456 at abc,r78 at type,";
+ oid::opl_parse_relation_members(s, s + std::strlen(s), buffer);
+ REQUIRE(buffer.written() > 0);
+ const auto& rml = buffer.get<osmium::RelationMemberList>(0);
+ REQUIRE(rml.size() == 3);
+ auto it = rml.begin();
+ REQUIRE(it->type() == osmium::item_type::node);
+ REQUIRE(it->ref() == 123);
+ REQUIRE(std::string{it->role()} == "");
+ ++it;
+ REQUIRE(it->type() == osmium::item_type::way);
+ REQUIRE(it->ref() == 456);
+ REQUIRE(std::string{it->role()} == "abc");
+ ++it;
+ REQUIRE(it->type() == osmium::item_type::relation);
+ REQUIRE(it->ref() == 78);
+ REQUIRE(std::string{it->role()} == "type");
+ ++it;
+ REQUIRE(it == rml.end());
+ }
+
+
+}
+
+TEST_CASE("Parse node") {
+ osmium::memory::Buffer buffer{1024};
+
+ SECTION("Node with id only") {
+ const char* s = "17";
+ const char* e = s + std::strlen(s);
+ oid::opl_parse_node(&s, buffer);
+ REQUIRE(s == e);
+ REQUIRE(buffer.written() > 0);
+ const osmium::Node& node = buffer.get<osmium::Node>(0);
+ REQUIRE(node.id() == 17);
+ }
+
+ SECTION("Node with trailing space") {
+ const char* s = "17 ";
+ const char* e = s + std::strlen(s);
+ oid::opl_parse_node(&s, buffer);
+ REQUIRE(s == e);
+ REQUIRE(buffer.written() > 0);
+ const osmium::Node& node = buffer.get<osmium::Node>(0);
+ REQUIRE(node.id() == 17);
+ }
+
+ SECTION("Node with id and version") {
+ const char* s = "17 v23";
+ const char* e = s + std::strlen(s);
+ oid::opl_parse_node(&s, buffer);
+ REQUIRE(s == e);
+ REQUIRE(buffer.written() > 0);
+ const osmium::Node& node = buffer.get<osmium::Node>(0);
+ REQUIRE(node.id() == 17);
+ REQUIRE(node.version() == 23);
+ }
+
+ SECTION("Node with multiple spaces") {
+ const char* s = "17 v23";
+ const char* e = s + std::strlen(s);
+ oid::opl_parse_node(&s, buffer);
+ REQUIRE(s == e);
+ REQUIRE(buffer.written() > 0);
+ const osmium::Node& node = buffer.get<osmium::Node>(0);
+ REQUIRE(node.id() == 17);
+ REQUIRE(node.version() == 23);
+ }
+
+ SECTION("Node with tab instead of space") {
+ const char* s = "17\tv23";
+ const char* e = s + std::strlen(s);
+ oid::opl_parse_node(&s, buffer);
+ REQUIRE(s == e);
+ REQUIRE(buffer.written() > 0);
+ const osmium::Node& node = buffer.get<osmium::Node>(0);
+ REQUIRE(node.id() == 17);
+ REQUIRE(node.version() == 23);
+ }
+
+ SECTION("Full node (no tags)") {
+ const char* s = "125799 v6 dV c7711393 t2011-03-29T21:43:10Z i45445 uUScha T x8.7868047 y53.0749415";
+ const char* e = s + std::strlen(s);
+ oid::opl_parse_node(&s, buffer);
+ REQUIRE(s == e);
+ REQUIRE(buffer.written() > 0);
+ const osmium::Node& node = buffer.get<osmium::Node>(0);
+ REQUIRE(node.id() == 125799);
+ REQUIRE(node.version() == 6);
+ REQUIRE(node.visible());
+ REQUIRE(node.changeset() == 7711393);
+ REQUIRE(node.timestamp() == osmium::Timestamp{"2011-03-29T21:43:10Z"});
+ REQUIRE(node.uid() == 45445);
+ REQUIRE(std::string{node.user()} == "UScha");
+ osmium::Location loc{8.7868047, 53.0749415};
+ REQUIRE(node.location() == loc);
+ REQUIRE(node.tags().empty());
+ }
+
+ SECTION("Node with tags)") {
+ const char* s = "123 v1 c456 Thighway=residential,oneway=true,name=High%20%Street";
+ const char* e = s + std::strlen(s);
+ oid::opl_parse_node(&s, buffer);
+ REQUIRE(s == e);
+ REQUIRE(buffer.written() > 0);
+ const osmium::Node& node = buffer.get<osmium::Node>(0);
+ REQUIRE(node.id() == 123);
+ REQUIRE(node.version() == 1);
+ REQUIRE(node.changeset() == 456);
+ REQUIRE(node.tags().size() == 3);
+
+ auto it = node.tags().cbegin();
+ REQUIRE(std::string{it->key()} == "highway");
+ REQUIRE(std::string{it->value()} == "residential");
+ ++it;
+ REQUIRE(std::string{it->key()} == "oneway");
+ REQUIRE(std::string{it->value()} == "true");
+ ++it;
+ REQUIRE(std::string{it->key()} == "name");
+ REQUIRE(std::string{it->value()} == "High Street");
+ ++it;
+ REQUIRE(it == node.tags().cend());
+ }
+
+ SECTION("Order does not matter") {
+ const char* s = "125799 c7711393 dV v6 i45445 uUScha T t2011-03-29T21:43:10Z y53.0749415 x8.7868047";
+ const char* e = s + std::strlen(s);
+ oid::opl_parse_node(&s, buffer);
+ REQUIRE(s == e);
+ REQUIRE(buffer.written() > 0);
+ const osmium::Node& node = buffer.get<osmium::Node>(0);
+ REQUIRE(node.id() == 125799);
+ REQUIRE(node.version() == 6);
+ REQUIRE(node.visible());
+ REQUIRE(node.changeset() == 7711393);
+ REQUIRE(node.timestamp() == osmium::Timestamp{"2011-03-29T21:43:10Z"});
+ REQUIRE(node.uid() == 45445);
+ REQUIRE(std::string{node.user()} == "UScha");
+ osmium::Location loc{8.7868047, 53.0749415};
+ REQUIRE(node.location() == loc);
+ REQUIRE(node.tags().empty());
+ }
+
+}
+
+TEST_CASE("Parse way") {
+
+ osmium::memory::Buffer buffer{1024};
+
+ SECTION("Way with id only") {
+ const char* s = "17";
+ const char* e = s + std::strlen(s);
+ oid::opl_parse_way(&s, buffer);
+ REQUIRE(s == e);
+ REQUIRE(buffer.written() > 0);
+ const osmium::Way& way = buffer.get<osmium::Way>(0);
+ REQUIRE(way.id() == 17);
+ }
+
+ SECTION("Complete way") {
+ const char* s = "78216 v12 dV c35895909 t2015-12-11T22:01:57Z i7412 umjulius Tdestination=Interlaken;%20%Kandersteg;%20%Zweisimmen,highway=motorway_link,name=Thun%20%Süd,oneway=yes,ref=17,surface=asphalt Nn1011242,n2569390773,n2569390769,n255308687,n2569390761,n255308689,n255308691,n1407526499,n255308692,n3888362655,n255308693,n255308694,n255308695,n255308686";
+ const char* e = s + std::strlen(s);
+ oid::opl_parse_way(&s, buffer);
+ REQUIRE(s == e);
+ REQUIRE(buffer.written() > 0);
+ const osmium::Way& way = buffer.get<osmium::Way>(0);
+ REQUIRE(way.id() == 78216);
+ REQUIRE(way.version() == 12);
+ REQUIRE(way.visible());
+ REQUIRE(way.changeset() == 35895909);
+ REQUIRE(way.timestamp() == osmium::Timestamp{"2015-12-11T22:01:57Z"});
+ REQUIRE(way.uid() == 7412);
+ REQUIRE(std::string{way.user()} == "mjulius");
+ REQUIRE(way.tags().size() == 6);
+
+ auto it = way.tags().cbegin();
+ REQUIRE(std::string{it->key()} == "destination");
+ REQUIRE(std::string{it->value()} == "Interlaken; Kandersteg; Zweisimmen");
+ ++it;
+ REQUIRE(std::string{it->key()} == "highway");
+ REQUIRE(std::string{it->value()} == "motorway_link");
+ ++it;
+ REQUIRE(std::string{it->key()} == "name");
+ REQUIRE(std::string{it->value()} == "Thun Süd");
+ ++it;
+ REQUIRE(std::string{it->key()} == "oneway");
+ REQUIRE(std::string{it->value()} == "yes");
+ ++it;
+ REQUIRE(std::string{it->key()} == "ref");
+ REQUIRE(std::string{it->value()} == "17");
+ ++it;
+ REQUIRE(std::string{it->key()} == "surface");
+ REQUIRE(std::string{it->value()} == "asphalt");
+ ++it;
+ REQUIRE(it == way.tags().cend());
+
+ REQUIRE(way.nodes().size() == 14);
+ std::vector<osmium::object_id_type> ids = {
+ 1011242, 2569390773, 2569390769, 255308687, 2569390761, 255308689,
+ 255308691, 1407526499, 255308692, 3888362655, 255308693, 255308694,
+ 255308695, 255308686
+ };
+ REQUIRE(std::equal(way.nodes().cbegin(), way.nodes().cend(), ids.cbegin()));
+ }
+
+}
+
+TEST_CASE("Parse relation") {
+
+ osmium::memory::Buffer buffer{1024};
+
+ SECTION("Relation with id only") {
+ const char* s = "17";
+ const char* e = s + std::strlen(s);
+ oid::opl_parse_relation(&s, buffer);
+ REQUIRE(s == e);
+ REQUIRE(buffer.written() > 0);
+ const osmium::Relation& relation = buffer.get<osmium::Relation>(0);
+ REQUIRE(relation.id() == 17);
+ }
+
+ SECTION("Complete relation") {
+ const char* s = "1074 v45 dV c20048094 t2014-01-17T10:27:04Z i86566 uwisieb Ttype=multipolygon,landuse=forest Mw255722275 at inner,w256126142 at outer,w24402792 at inner,w256950103 at outer,w255722279 at outer";
+ const char* e = s + std::strlen(s);
+ oid::opl_parse_relation(&s, buffer);
+ REQUIRE(s == e);
+ REQUIRE(buffer.written() > 0);
+ const osmium::Relation& relation = buffer.get<osmium::Relation>(0);
+ REQUIRE(relation.id() == 1074);
+ REQUIRE(relation.version() == 45);
+ REQUIRE(relation.visible());
+ REQUIRE(relation.changeset() == 20048094);
+ REQUIRE(relation.timestamp() == osmium::Timestamp{"2014-01-17T10:27:04Z"});
+ REQUIRE(relation.uid() == 86566);
+ REQUIRE(std::string{relation.user()} == "wisieb");
+ REQUIRE(relation.tags().size() == 2);
+
+ auto it = relation.tags().cbegin();
+ REQUIRE(std::string{it->key()} == "type");
+ REQUIRE(std::string{it->value()} == "multipolygon");
+ ++it;
+ REQUIRE(std::string{it->key()} == "landuse");
+ REQUIRE(std::string{it->value()} == "forest");
+ ++it;
+ REQUIRE(it == relation.tags().cend());
+
+ REQUIRE(relation.members().size() == 5);
+ auto mit = relation.members().cbegin();
+ REQUIRE(mit->type() == osmium::item_type::way);
+ REQUIRE(mit->ref() == 255722275);
+ REQUIRE(std::string{mit->role()} == "inner");
+ ++mit;
+ REQUIRE(mit->type() == osmium::item_type::way);
+ REQUIRE(mit->ref() == 256126142);
+ REQUIRE(std::string{mit->role()} == "outer");
+ ++mit;
+ ++mit;
+ ++mit;
+ ++mit;
+ REQUIRE(mit == relation.members().cend());
+ }
+
+}
+
+TEST_CASE("Parse changeset") {
+
+ osmium::memory::Buffer buffer{1024};
+
+ SECTION("Changeset with id only") {
+ const char* s = "17";
+ const char* e = s + std::strlen(s);
+ oid::opl_parse_changeset(&s, buffer);
+ REQUIRE(s == e);
+ REQUIRE(buffer.written() > 0);
+ const osmium::Changeset& changeset = buffer.get<osmium::Changeset>(0);
+ REQUIRE(changeset.id() == 17);
+ }
+
+ SECTION("Complete changeset") {
+ const char* s = "873494 k1 s2009-04-21T08:52:49Z e2009-04-21T09:52:49Z d0 i13093 uTiberiusNero x13.923302 y50.957069 X14.0337519 Y50.9824084 Tcreated_by=Potlatch%20%0.11";
+ const char* e = s + std::strlen(s);
+ oid::opl_parse_changeset(&s, buffer);
+ REQUIRE(s == e);
+ REQUIRE(buffer.written() > 0);
+ const osmium::Changeset& changeset = buffer.get<osmium::Changeset>(0);
+ REQUIRE(changeset.id() == 873494);
+ REQUIRE(changeset.created_at() == osmium::Timestamp{"2009-04-21T08:52:49Z"});
+ REQUIRE(changeset.closed_at() == osmium::Timestamp{"2009-04-21T09:52:49Z"});
+ REQUIRE(changeset.num_changes() == 1);
+ REQUIRE(changeset.num_comments() == 0);
+ REQUIRE(changeset.uid() == 13093);
+ REQUIRE(std::string{changeset.user()} == "TiberiusNero");
+ REQUIRE(changeset.tags().size() == 1);
+
+ auto it = changeset.tags().cbegin();
+ REQUIRE(std::string{it->key()} == "created_by");
+ REQUIRE(std::string{it->value()} == "Potlatch 0.11");
+ ++it;
+ REQUIRE(it == changeset.tags().cend());
+
+ osmium::Box box{13.923302, 50.957069, 14.0337519, 50.9824084};
+ REQUIRE(box == changeset.bounds());
+ }
+
+}
+
+TEST_CASE("Parse line") {
+
+ osmium::memory::Buffer buffer{1024};
+
+ SECTION("Empty line") {
+ const char* s = "";
+ REQUIRE_FALSE(oid::opl_parse_line(0, "", buffer));
+ REQUIRE(buffer.written() == 0);
+ }
+
+ SECTION("Comment line") {
+ REQUIRE_FALSE(oid::opl_parse_line(0, "# abc", buffer));
+ REQUIRE(buffer.written() == 0);
+ }
+
+ SECTION("Fail") {
+ REQUIRE_THROWS_WITH({
+ oid::opl_parse_line(0, "X", buffer);
+ }, "OPL error: unknown type on line 0 column 0");
+ REQUIRE(buffer.written() == 0);
+ }
+
+ SECTION("New line at end not allowed") {
+ REQUIRE_THROWS_WITH({
+ oid::opl_parse_line(0, "n12 v3\n", buffer);
+ }, "OPL error: expected space or tab character on line 0 column 6");
+ }
+
+ SECTION("Node, but not asking for nodes") {
+ REQUIRE_FALSE(oid::opl_parse_line(0, "n12 v1", buffer, osmium::osm_entity_bits::way));
+ REQUIRE(buffer.written() == 0);
+ }
+
+ SECTION("Node") {
+ REQUIRE(oid::opl_parse_line(0, "n12 v3", buffer));
+ REQUIRE(buffer.written() > 0);
+ auto& item = buffer.get<osmium::memory::Item>(0);
+ REQUIRE(item.type() == osmium::item_type::node);
+ }
+
+ SECTION("Way") {
+ REQUIRE(oid::opl_parse_line(0, "w12 v3", buffer));
+ REQUIRE(buffer.written() > 0);
+ auto& item = buffer.get<osmium::memory::Item>(0);
+ REQUIRE(item.type() == osmium::item_type::way);
+ }
+
+ SECTION("Relation") {
+ REQUIRE(oid::opl_parse_line(0, "r12 v3", buffer));
+ REQUIRE(buffer.written() > 0);
+ auto& item = buffer.get<osmium::memory::Item>(0);
+ REQUIRE(item.type() == osmium::item_type::relation);
+ }
+
+ SECTION("Changeset") {
+ REQUIRE(oid::opl_parse_line(0, "c12", buffer));
+ REQUIRE(buffer.written() > 0);
+ auto& item = buffer.get<osmium::memory::Item>(0);
+ REQUIRE(item.type() == osmium::item_type::changeset);
+ }
+
+}
+
+TEST_CASE("Get context for errors") {
+
+ osmium::memory::Buffer buffer{1024};
+
+ SECTION("Unknown object type") {
+ bool error = false;
+ try {
+ oid::opl_parse_line(0, "~~~", buffer);
+ } catch (const osmium::opl_error& e) {
+ error = true;
+ REQUIRE(e.line == 0);
+ REQUIRE(e.column == 0);
+ REQUIRE(std::string{e.data} == "~~~");
+ }
+ REQUIRE(error);
+ }
+
+ SECTION("Node id") {
+ bool error = false;
+ try {
+ oid::opl_parse_line(0, "n~~~", buffer);
+ } catch (const osmium::opl_error& e) {
+ error = true;
+ REQUIRE(e.line == 0);
+ REQUIRE(e.column == 1);
+ REQUIRE(std::string{e.data} == "~~~");
+ }
+ REQUIRE(error);
+ }
+
+ SECTION("Node expect space") {
+ bool error = false;
+ try {
+ oid::opl_parse_line(1, "n123~~~", buffer);
+ } catch (const osmium::opl_error& e) {
+ error = true;
+ REQUIRE(e.line == 1);
+ REQUIRE(e.column == 4);
+ REQUIRE(std::string{e.data} == "~~~");
+ }
+ REQUIRE(error);
+ }
+
+ SECTION("Node unknown attribute") {
+ bool error = false;
+ try {
+ oid::opl_parse_line(2, "n123 ~~~", buffer);
+ } catch (const osmium::opl_error& e) {
+ error = true;
+ REQUIRE(e.line == 2);
+ REQUIRE(e.column == 5);
+ REQUIRE(std::string{e.data} == "~~~");
+ }
+ REQUIRE(error);
+ }
+
+ SECTION("Node version not an int") {
+ bool error = false;
+ try {
+ oid::opl_parse_line(3, "n123 v~~~", buffer);
+ } catch (const osmium::opl_error& e) {
+ error = true;
+ REQUIRE(e.line == 3);
+ REQUIRE(e.column == 6);
+ REQUIRE(std::string{e.data} == "~~~");
+ }
+ REQUIRE(error);
+ }
+
+}
+
+TEST_CASE("Parse line with external interface") {
+
+ osmium::memory::Buffer buffer{1024};
+
+ SECTION("Node") {
+ REQUIRE(osmium::opl_parse("n12 v3", buffer));
+ REQUIRE(buffer.committed() > 0);
+ REQUIRE(buffer.written() == buffer.committed());
+ const auto& item = buffer.get<osmium::memory::Item>(0);
+ REQUIRE(item.type() == osmium::item_type::node);
+ REQUIRE(static_cast<const osmium::Node&>(item).id() == 12);
+ }
+
+ SECTION("Empty line") {
+ REQUIRE_FALSE(osmium::opl_parse("", buffer));
+ REQUIRE(buffer.written() == 0);
+ REQUIRE(buffer.committed() == 0);
+ }
+
+ SECTION("Failure") {
+ REQUIRE_THROWS_WITH({
+ osmium::opl_parse("x", buffer);
+ }, "OPL error: unknown type on line 0 column 0");
+ REQUIRE(buffer.written() == 0);
+ REQUIRE(buffer.committed() == 0);
+ }
+
+}
+
diff --git a/test/t/io/test_reader_with_mock_decompression.cpp b/test/t/io/test_reader_with_mock_decompression.cpp
index 566295a..63b8bd2 100644
--- a/test/t/io/test_reader_with_mock_decompression.cpp
+++ b/test/t/io/test_reader_with_mock_decompression.cpp
@@ -19,7 +19,7 @@ class MockDecompressor : public osmium::io::Decompressor {
public:
- MockDecompressor(const std::string& fail_in) :
+ explicit MockDecompressor(const std::string& fail_in) :
Decompressor(),
m_fail_in(fail_in) {
if (m_fail_in == "constructor") {
@@ -87,7 +87,7 @@ TEST_CASE("Test Reader using MockDecompressor") {
try {
osmium::io::Reader reader(with_data_dir("t/io/data.osm.gz"));
REQUIRE(false);
- } catch (std::runtime_error& e) {
+ } catch (const std::runtime_error& e) {
REQUIRE(std::string{e.what()} == "error constructor");
}
}
@@ -99,7 +99,7 @@ TEST_CASE("Test Reader using MockDecompressor") {
osmium::io::Reader reader(with_data_dir("t/io/data.osm.gz"));
reader.read();
REQUIRE(false);
- } catch (std::runtime_error& e) {
+ } catch (const std::runtime_error& e) {
REQUIRE(std::string{e.what()} == "error first read");
}
}
@@ -112,7 +112,7 @@ TEST_CASE("Test Reader using MockDecompressor") {
reader.read();
reader.read();
REQUIRE(false);
- } catch (std::runtime_error& e) {
+ } catch (const std::runtime_error& e) {
REQUIRE(std::string{e.what()} == "error second read");
}
}
@@ -127,7 +127,7 @@ TEST_CASE("Test Reader using MockDecompressor") {
reader.read();
reader.close();
REQUIRE(false);
- } catch (std::runtime_error& e) {
+ } catch (const std::runtime_error& e) {
REQUIRE(std::string{e.what()} == "error close");
}
}
diff --git a/test/t/io/test_reader_with_mock_parser.cpp b/test/t/io/test_reader_with_mock_parser.cpp
index c71847c..c5c9975 100644
--- a/test/t/io/test_reader_with_mock_parser.cpp
+++ b/test/t/io/test_reader_with_mock_parser.cpp
@@ -78,7 +78,7 @@ TEST_CASE("Test Reader using MockParser") {
try {
osmium::io::Reader reader(with_data_dir("t/io/data.osm"));
reader.header();
- } catch (std::runtime_error& e) {
+ } catch (const std::runtime_error& e) {
REQUIRE(std::string{e.what()} == "error in header");
}
}
@@ -89,7 +89,7 @@ TEST_CASE("Test Reader using MockParser") {
reader.header();
try {
reader.read();
- } catch (std::runtime_error& e) {
+ } catch (const std::runtime_error& e) {
REQUIRE(std::string{e.what()} == "error in read");
}
reader.close();
@@ -101,7 +101,7 @@ TEST_CASE("Test Reader using MockParser") {
reader.header();
try {
throw std::runtime_error("error in user code");
- } catch (std::runtime_error& e) {
+ } catch (const std::runtime_error& e) {
REQUIRE(std::string{e.what()} == "error in user code");
}
REQUIRE(reader.read());
diff --git a/test/t/io/test_writer_with_mock_compression.cpp b/test/t/io/test_writer_with_mock_compression.cpp
index 10c19c4..a28d537 100644
--- a/test/t/io/test_writer_with_mock_compression.cpp
+++ b/test/t/io/test_writer_with_mock_compression.cpp
@@ -15,7 +15,7 @@ class MockCompressor : public osmium::io::Compressor {
public:
- MockCompressor(const std::string& fail_in) :
+ explicit MockCompressor(const std::string& fail_in) :
Compressor(osmium::io::fsync::no),
m_fail_in(fail_in) {
if (m_fail_in == "constructor") {
diff --git a/test/t/tags/test_filter.cpp b/test/t/tags/test_filter.cpp
index fa21de1..260a4ba 100644
--- a/test/t/tags/test_filter.cpp
+++ b/test/t/tags/test_filter.cpp
@@ -24,7 +24,7 @@ void check_filter(const osmium::TagList& tag_list, const TFilter filter, const s
}
const osmium::TagList& make_tag_list(osmium::memory::Buffer& buffer, std::initializer_list<std::pair<const char*, const char*>> tags) {
- auto pos = osmium::builder::add_tag_list(buffer, osmium::builder::attr::_tags(tags));
+ const auto pos = osmium::builder::add_tag_list(buffer, osmium::builder::attr::_tags(tags));
return buffer.get<osmium::TagList>(pos);
}
@@ -42,7 +42,7 @@ TEST_CASE("Filter") {
{ "source", "GPS" } // no match
});
- std::vector<bool> results = { true, false, false };
+ const std::vector<bool> results = { true, false, false };
check_filter(tag_list, filter, results);
}
@@ -84,7 +84,7 @@ TEST_CASE("Filter") {
{ "source", "GPS" }
});
- std::vector<bool> results = {true, true, false};
+ const std::vector<bool> results = {true, true, false};
check_filter(tag_list, filter, results);
}
diff --git a/test/t/util/test_cast_with_assert.cpp b/test/t/util/test_cast_with_assert.cpp
index 0231f30..044176e 100644
--- a/test/t/util/test_cast_with_assert.cpp
+++ b/test/t/util/test_cast_with_assert.cpp
@@ -3,7 +3,7 @@
// Define assert() to throw this error. This enables the tests to check that
// the assert() fails.
struct assert_error : public std::runtime_error {
- assert_error(const char* what_arg) : std::runtime_error(what_arg) {
+ explicit assert_error(const char* what_arg) : std::runtime_error(what_arg) {
}
};
#define assert(x) if (!(x)) { throw(assert_error(#x)); }
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/libosmium.git
More information about the Pkg-grass-devel
mailing list