[libosmium] 02/06: Imported Upstream version 2.5.4

Sebastiaan Couwenberg sebastic at moszumanska.debian.org
Thu Dec 3 21:15:35 UTC 2015


This is an automated email from the git hooks/post-receive script.

sebastic pushed a commit to branch master
in repository libosmium.

commit c7d7c005bdbc3f0d84604013d78a3d4a7631ce2d
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date:   Thu Dec 3 21:51:46 2015 +0100

    Imported Upstream version 2.5.4
---
 CHANGELOG.md                                       |  31 +++-
 CMakeLists.txt                                     |  97 +++++++++++-
 include/gdalcpp.hpp                                | 164 +++++++++++++++++----
 include/osmium/area/detail/node_ref_segment.hpp    |  62 ++++----
 include/osmium/area/multipolygon_collector.hpp     |   2 +-
 include/osmium/area/problem_reporter_exception.hpp |   2 +-
 include/osmium/area/problem_reporter_ogr.hpp       |   2 +-
 include/osmium/area/problem_reporter_stream.hpp    |   2 +-
 include/osmium/builder/osm_object_builder.hpp      |  29 +++-
 include/osmium/dynamic_handler.hpp                 |  14 +-
 include/osmium/geom/factory.hpp                    |   8 +-
 include/osmium/handler.hpp                         |   2 +-
 include/osmium/index/detail/create_map_with_fd.hpp |  15 +-
 include/osmium/index/detail/vector_map.hpp         |  34 ++---
 include/osmium/index/detail/vector_multimap.hpp    |  14 +-
 include/osmium/index/index.hpp                     |   2 +-
 include/osmium/index/map/dummy.hpp                 |  12 +-
 include/osmium/index/map/sparse_mem_map.hpp        |  14 +-
 include/osmium/index/map/sparse_mem_table.hpp      |  14 +-
 include/osmium/index/multimap.hpp                  |   2 +-
 include/osmium/index/multimap/hybrid.hpp           |  12 +-
 .../osmium/index/multimap/sparse_mem_multimap.hpp  |  12 +-
 include/osmium/io/bzip2_compression.hpp            |  20 +--
 include/osmium/io/compression.hpp                  |  14 +-
 include/osmium/io/detail/debug_output_format.hpp   |   6 +-
 include/osmium/io/detail/o5m_input_format.hpp      |   9 +-
 include/osmium/io/detail/opl_output_format.hpp     |   4 +-
 include/osmium/io/detail/output_format.hpp         |   2 +-
 include/osmium/io/detail/pbf.hpp                   |   8 +-
 include/osmium/io/detail/pbf_input_format.hpp      |   4 +-
 include/osmium/io/detail/pbf_output_format.hpp     |  18 +--
 include/osmium/io/detail/queue_util.hpp            |   2 +-
 include/osmium/io/detail/read_write.hpp            |  40 ++---
 include/osmium/io/detail/string_table.hpp          |   2 +-
 include/osmium/io/detail/xml_input_format.hpp      |   6 +-
 include/osmium/io/detail/xml_output_format.hpp     |  10 +-
 include/osmium/io/error.hpp                        |   8 +-
 include/osmium/io/gzip_compression.hpp             |  18 +--
 include/osmium/io/reader.hpp                       |   2 +-
 include/osmium/memory/buffer.hpp                   |   5 +-
 include/osmium/memory/collection.hpp               |   2 +-
 include/osmium/memory/item.hpp                     |   2 +-
 include/osmium/memory/item_iterator.hpp            |   2 +-
 include/osmium/osm/area.hpp                        |   2 +-
 include/osmium/osm/box.hpp                         |   8 +-
 include/osmium/osm/changeset.hpp                   |   2 +-
 include/osmium/osm/crc.hpp                         |   2 +-
 include/osmium/osm/location.hpp                    |  18 +--
 include/osmium/osm/node.hpp                        |   2 +-
 include/osmium/osm/node_ref.hpp                    |  26 ++--
 include/osmium/osm/node_ref_list.hpp               |   2 +-
 include/osmium/osm/relation.hpp                    |   8 +-
 include/osmium/osm/segment.hpp                     |   8 +-
 include/osmium/osm/tag.hpp                         |   3 +-
 include/osmium/osm/timestamp.hpp                   |  72 +++++++--
 include/osmium/osm/way.hpp                         |   2 +-
 include/osmium/thread/function_wrapper.hpp         |   2 +-
 include/osmium/thread/pool.hpp                     |  36 +++--
 include/osmium/thread/queue.hpp                    |   2 +-
 include/osmium/thread/util.hpp                     |   2 +-
 include/osmium/util/compatibility.hpp              |   3 -
 include/osmium/util/config.hpp                     |   2 +-
 include/osmium/util/delta.hpp                      |   2 +-
 include/osmium/util/double.hpp                     |   8 +-
 include/osmium/util/memory_mapping.hpp             |   4 +-
 include/osmium/visitor.hpp                         |   2 +-
 include/protozero/byteswap.hpp                     |  10 +-
 include/protozero/config.hpp                       |  57 +++++++
 include/protozero/pbf_reader.hpp                   |  34 +++--
 include/protozero/pbf_writer.hpp                   |  13 +-
 include/protozero/version.hpp                      |   4 +-
 test/data-tests/CMakeLists.txt                     |   6 +-
 test/data-tests/testdata-multipolygon.cpp          |   4 +-
 test/data-tests/testdata-overview.cpp              |   4 +-
 test/t/area/test_node_ref_segment.cpp              |  14 ++
 test/t/basic/test_node.cpp                         |   4 +-
 test/t/basic/test_relation.cpp                     |   2 +-
 test/t/basic/test_timestamp.cpp                    |  10 +-
 test/t/basic/test_way.cpp                          |   2 +-
 test/t/buffer/test_buffer_node.cpp                 |  36 ++++-
 test/t/io/test_reader_with_mock_decompression.cpp  |   6 +-
 test/t/io/test_reader_with_mock_parser.cpp         |   2 +-
 test/t/io/test_writer_with_mock_compression.cpp    |   6 +-
 test/t/io/test_writer_with_mock_encoder.cpp        |   6 +-
 test/t/thread/test_pool.cpp                        |  29 ++++
 85 files changed, 823 insertions(+), 374 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 70d77bc..e9377b6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,17 +13,37 @@ This project adheres to [Semantic Versioning](http://semver.org/).
 ### Fixed
 
 
+## [2.5.4] - 2015-12-03
+
+### Changed
+
+- Included gdalcpp.hpp header was updated to version 1.1.1.
+- Included protozero library was updated to version 1.2.3.
+- Workarounds for missing constexpr support in Visual Studio removed. All
+  constexpr features we need are supported now.
+- Some code cleanup after running clang-tidy on the code.
+- Re-added `Buffer::value_type` typedef. Turns out it is needed when using
+  `std::back_inserter` on the Buffer.
+
+### Fixed
+
+- Bugs with Timestamp code on 32 bit platforms. This necessitated
+  some changes in Timestamp which might lead to changes in user
+  code.
+- Bug in segment intersection code (which appeared on i686 platform).
+
+
 ## [2.5.3] - 2015-11-17
 
 ### Added
 
-- osmium::make_diff_iterator() helper function.
+- `osmium::make_diff_iterator()` helper function.
 
 ### Changed
 
-- Deprecated osmium::Buffer::set_full_callback().
+- Deprecated `osmium::Buffer::set_full_callback()`.
 - Removed DataFile class which was never used anywhere.
-- Removed unused and obscure Buffer::value_type typedef.
+- Removed unused and obscure `Buffer::value_type` typedef.
 
 ### Fixed
 
@@ -214,8 +234,9 @@ 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.5.3...HEAD
-[2.5.3]: https://github.com/osmcode/libosmium/compare/v2.5.1...v2.5.3
+[unreleased]: https://github.com/osmcode/libosmium/compare/v2.5.4...HEAD
+[2.5.4]: https://github.com/osmcode/libosmium/compare/v2.5.3...v2.5.4
+[2.5.3]: https://github.com/osmcode/libosmium/compare/v2.5.2...v2.5.3
 [2.5.2]: https://github.com/osmcode/libosmium/compare/v2.5.1...v2.5.2
 [2.5.1]: https://github.com/osmcode/libosmium/compare/v2.5.0...v2.5.1
 [2.5.0]: https://github.com/osmcode/libosmium/compare/v2.4.1...v2.5.0
diff --git a/CMakeLists.txt b/CMakeLists.txt
index fc3e97e..0764915 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -9,8 +9,6 @@
 cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
 list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
 
-set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
-
 
 #-----------------------------------------------------------------------------
 #
@@ -27,11 +25,13 @@ project(libosmium)
 
 set(LIBOSMIUM_VERSION_MAJOR 2)
 set(LIBOSMIUM_VERSION_MINOR 5)
-set(LIBOSMIUM_VERSION_PATCH 3)
+set(LIBOSMIUM_VERSION_PATCH 4)
 
 set(LIBOSMIUM_VERSION
     "${LIBOSMIUM_VERSION_MAJOR}.${LIBOSMIUM_VERSION_MINOR}.${LIBOSMIUM_VERSION_PATCH}")
 
+set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
+
 
 #-----------------------------------------------------------------------------
 #
@@ -276,12 +276,14 @@ if(CPPCHECK)
 
     file(GLOB_RECURSE ALL_INCLUDES   include/osmium/*.hpp)
     file(GLOB         ALL_EXAMPLES   examples/*.cpp)
+    file(GLOB         ALL_BENCHMARKS benchmarks/*.cpp)
     file(GLOB         ALL_UNIT_TESTS test/t/*/test_*.cpp)
     file(GLOB         ALL_DATA_TESTS test/data-tests/*.cpp)
 
     if(Osmium_DEBUG)
         message(STATUS "Checking includes      : ${ALL_INCLUDES}")
         message(STATUS "Checking example code  : ${ALL_EXAMPLES}")
+        message(STATUS "Checking benchmarks    : ${ALL_BENCHMARKS}")
         message(STATUS "Checking unit test code: ${ALL_UNIT_TESTS}")
         message(STATUS "Checking data test code: ${ALL_DATA_TESTS}")
     endif()
@@ -289,6 +291,7 @@ if(CPPCHECK)
     set(CPPCHECK_FILES
         ${ALL_INCLUDES}
         ${ALL_EXAMPLES}
+        ${ALL_BENCHMARKS}
         ${ALL_UNIT_TESTS}
         ${ALL_DATA_TESTS})
 
@@ -301,7 +304,7 @@ if(CPPCHECK)
 else()
     message(STATUS "Looking for cppcheck - not found")
     message(STATUS "  Build target 'cppcheck' will not be available.")
-endif(CPPCHECK)
+endif()
 
 
 #-----------------------------------------------------------------------------
@@ -361,6 +364,92 @@ endif()
 
 #-----------------------------------------------------------------------------
 #
+#  Optional "clang-tidy" target
+#
+#-----------------------------------------------------------------------------
+message(STATUS "Looking for clang-tidy")
+find_program(CLANG_TIDY NAMES clang-tidy clang-tidy-3.9 clang-tidy-3.8 clang-tidy-3.7 clang-tidy-3.6 clang-tidy-3.5)
+
+if(CLANG_TIDY)
+    message(STATUS "Looking for clang-tidy - found")
+
+    if(BUILD_EXAMPLES)
+        file(GLOB CT_ALL_EXAMPLES examples/*.cpp)
+    endif()
+
+    if(BUILD_TESTING)
+        file(GLOB CT_ALL_UNIT_TESTS test/t/*/test_*.cpp)
+    endif()
+
+    if(BUILD_HEADERS)
+        file(GLOB_RECURSE CT_ALL_INCLUDES ${CMAKE_BINARY_DIR}/header_check/osmium__*.cpp)
+    endif()
+
+    if(BUILD_BENCHMARKS)
+        file(GLOB CT_ALL_BENCHMARKS benchmarks/*.cpp)
+    endif()
+
+    if(BUILD_DATA_TESTS)
+        file(GLOB CT_ALL_DATA_TESTS test/data-tests/*.cpp)
+    endif()
+
+    if(Osmium_DEBUG)
+        message(STATUS "Checking example code  : ${CT_ALL_EXAMPLES}")
+        message(STATUS "Checking unit test code: ${CT_ALL_UNIT_TESTS}")
+        message(STATUS "Checking includes      : ${CT_ALL_INCLUDES}")
+        message(STATUS "Checking benchmarks    : ${CT_ALL_BENCHMARKS}")
+        message(STATUS "Checking data test code: ${CT_ALL_DATA_TESTS}")
+    endif()
+
+    set(CT_CHECK_FILES
+        ${CT_ALL_EXAMPLES}
+        ${CT_ALL_UNIT_TESTS}
+        ${CT_ALL_INCLUDES}
+        ${CT_ALL_BENCHMARKS}
+        ${CT_ALL_DATA_TESTS})
+
+    # For a list of check options, see:
+    # http://clang.llvm.org/extra/clang-tidy/checks/list.html
+
+    list(APPEND CT_CHECKS "cert-*"
+                         "-cert-err60-cpp") # even the std lib doesn't do this
+
+    # disabled, because it is slow
+#    list(APPEND CT_CHECKS "clang-analyzer-*")
+
+    list(APPEND CT_CHECKS "google-*"
+                         "-google-explicit-constructor"
+                         "-google-readability-casting"
+                         "-google-readability-function")
+
+    list(APPEND CT_CHECKS "llvm-*"
+                         "-llvm-include-order")
+
+    list(APPEND CT_CHECKS "misc-*"
+                         "-misc-argument-comment")
+
+    list(APPEND CT_CHECKS "modernize-*")
+
+    list(APPEND CT_CHECKS "readability-*"
+                         "-readability-identifier-naming"
+                         "-readability-named-parameter")
+
+    string(REPLACE ";" "," ALL_CHECKS "${CT_CHECKS}")
+
+    add_custom_target(clang-tidy
+        ${CLANG_TIDY}
+        -p ${CMAKE_BINARY_DIR}
+        -header-filter='include/osmium/.*'
+        -checks="${ALL_CHECKS}"
+        ${CT_CHECK_FILES}
+    )
+else()
+    message(STATUS "Looking for clang-tidy - not found")
+    message(STATUS "  Build target 'clang-tidy' will not be available.")
+endif()
+
+#-----------------------------------------------------------------------------
+#
 #  Installation
 #
 #  External libraries are only installed if the options are set in case they
diff --git a/include/gdalcpp.hpp b/include/gdalcpp.hpp
index a66e1ea..1502f2f 100644
--- a/include/gdalcpp.hpp
+++ b/include/gdalcpp.hpp
@@ -5,7 +5,7 @@
 
 C++11 wrapper classes for GDAL/OGR.
 
-Version 1.0.0
+Version 1.1.1
 
 https://github.com/joto/gdalcpp
 
@@ -51,23 +51,28 @@ DEALINGS IN THE SOFTWARE.
 namespace gdalcpp {
 
 #if GDAL_VERSION_MAJOR >= 2
-    typedef GDALDriver gdal_driver_type;
-    typedef GDALDataset gdal_dataset_type;
+    using gdal_driver_type = GDALDriver;
+    using gdal_dataset_type = GDALDataset;
 #else
-    typedef OGRSFDriver gdal_driver_type;
-    typedef OGRDataSource gdal_dataset_type;
+    using gdal_driver_type = OGRSFDriver;
+    using gdal_dataset_type = OGRDataSource;
 #endif
 
+    /**
+     * Exception thrown for all errors in this class.
+     */
     class gdal_error : public std::runtime_error {
 
         std::string m_driver;
         std::string m_dataset;
         std::string m_layer;
         std::string m_field;
+        OGRErr m_error;
 
     public:
 
         gdal_error(const std::string& message,
+                   OGRErr error,
                    const std::string& driver = "",
                    const std::string& dataset = "",
                    const std::string& layer = "",
@@ -76,7 +81,8 @@ namespace gdalcpp {
             m_driver(driver),
             m_dataset(dataset),
             m_layer(layer),
-            m_field(field) {
+            m_field(field),
+            m_error(error) {
         }
 
         const std::string& driver() const {
@@ -95,6 +101,10 @@ namespace gdalcpp {
             return m_field;
         }
 
+        OGRErr error() const {
+            return m_error;
+        }
+
     }; // class gdal_error
 
     namespace detail {
@@ -118,9 +128,13 @@ namespace gdalcpp {
 
             Driver(const std::string& driver_name) :
                 init_library(),
+#if GDAL_VERSION_MAJOR >= 2
+                m_driver(GetGDALDriverManager()->GetDriverByName(driver_name.c_str())) {
+#else
                 m_driver(OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName(driver_name.c_str())) {
+#endif
                 if (!m_driver) {
-                    throw gdal_error(std::string("unknown driver: '") + driver_name + "'", driver_name);
+                    throw gdal_error(std::string("unknown driver: '") + driver_name + "'", OGRERR_NONE, driver_name);
                 }
             }
 
@@ -152,6 +166,58 @@ namespace gdalcpp {
 
     } // namespace detail
 
+    class SRS {
+
+        OGRSpatialReference m_spatial_reference;
+
+    public:
+
+        SRS() :
+            m_spatial_reference() {
+            auto result = m_spatial_reference.SetWellKnownGeogCS("WGS84");
+            if (result != OGRERR_NONE) {
+                throw gdal_error(std::string("can not initialize spatial reference system WGS84"), result);
+            }
+        }
+
+        explicit SRS(int epsg) :
+            m_spatial_reference() {
+            auto result = m_spatial_reference.importFromEPSG(epsg);
+            if (result != OGRERR_NONE) {
+                throw gdal_error(std::string("can not initialize spatial reference system for EPSG:") + std::to_string(epsg), result);
+            }
+        }
+
+        explicit SRS(const char* name) :
+            m_spatial_reference() {
+            auto result = m_spatial_reference.importFromProj4(name);
+            if (result != OGRERR_NONE) {
+                throw gdal_error(std::string("can not initialize spatial reference system '") + name + "'", result);
+            }
+        }
+
+        explicit SRS(const std::string& name) :
+            m_spatial_reference() {
+            auto result = m_spatial_reference.importFromProj4(name.c_str());
+            if (result != OGRERR_NONE) {
+                throw gdal_error(std::string("can not initialize spatial reference system '") + name + "'", result);
+            }
+        }
+
+        explicit SRS(const OGRSpatialReference& spatial_reference) :
+            m_spatial_reference(spatial_reference) {
+        }
+
+        OGRSpatialReference& get() {
+            return m_spatial_reference;
+        }
+
+        const OGRSpatialReference& get() const {
+            return m_spatial_reference;
+        }
+
+    }; // class SRS
+
     class Dataset {
 
         struct gdal_dataset_deleter {
@@ -169,27 +235,23 @@ namespace gdalcpp {
         std::string m_driver_name;
         std::string m_dataset_name;
         detail::Options m_options;
+        SRS m_srs;
         std::unique_ptr<gdal_dataset_type, gdal_dataset_deleter> m_dataset;
-        OGRSpatialReference m_spatial_reference;
 
     public:
 
-        Dataset(const std::string& driver_name, const std::string& dataset_name, const std::string& proj = "", const std::vector<std::string>& options = {}) :
+        Dataset(const std::string& driver_name, const std::string& dataset_name, const SRS& srs = SRS{}, const std::vector<std::string>& options = {}) :
             m_driver_name(driver_name),
             m_dataset_name(dataset_name),
             m_options(options),
+            m_srs(srs),
 #if GDAL_VERSION_MAJOR >= 2
             m_dataset(detail::Driver(driver_name).get().Create(dataset_name.c_str(), 0, 0, 0, GDT_Unknown, m_options.get())) {
 #else
             m_dataset(detail::Driver(driver_name).get().CreateDataSource(dataset_name.c_str(), m_options.get())) {
 #endif
             if (!m_dataset) {
-                throw gdal_error(std::string("failed to create dataset '") + dataset_name + "'", driver_name, dataset_name);
-            }
-            if (proj.empty()) {
-                m_spatial_reference.SetWellKnownGeogCS("WGS84");
-            } else {
-                m_spatial_reference.importFromProj4(proj.c_str());
+                throw gdal_error(std::string("failed to create dataset '") + dataset_name + "'", OGRERR_NONE, driver_name, dataset_name);
             }
         }
 
@@ -205,10 +267,22 @@ namespace gdalcpp {
             return *m_dataset;
         }
 
-        OGRSpatialReference* spatial_reference() {
-            return &m_spatial_reference;
+        SRS& srs() {
+            return m_srs;
+        }
+
+        void exec(const char* sql) {
+            auto result = m_dataset->ExecuteSQL(sql, nullptr, nullptr);
+            if (result) {
+                m_dataset->ReleaseResultSet(result);
+            }
+        }
+
+        void exec(const std::string& sql) {
+            exec(sql.c_str());
         }
 
+
         Dataset& start_transaction() {
 #if GDAL_VERSION_MAJOR >= 2
             m_dataset->StartTransaction();
@@ -227,25 +301,35 @@ namespace gdalcpp {
 
     class Layer {
 
+        detail::Options m_options;
         Dataset& m_dataset;
         OGRLayer* m_layer;
 
     public:
 
-        Layer(Dataset& dataset, const std::string& layer_name, OGRwkbGeometryType type) :
+        Layer(Dataset& dataset, const std::string& layer_name, OGRwkbGeometryType type, const std::vector<std::string>& options = {}) :
+            m_options(options),
             m_dataset(dataset),
-            m_layer(dataset.get().CreateLayer(layer_name.c_str(), dataset.spatial_reference(), type)) {
+            m_layer(dataset.get().CreateLayer(layer_name.c_str(), &dataset.srs().get(), type, m_options.get())) {
             if (!m_layer) {
-                throw gdal_error(std::string("failed to create layer '") + layer_name + "'",
+                throw gdal_error(std::string("failed to create layer '") + layer_name + "'", OGRERR_NONE,
                     dataset.driver_name(), dataset.dataset_name(), layer_name);
             }
         }
 
-        OGRLayer* get() const {
-            return m_layer;
+        OGRLayer& get() {
+            return *m_layer;
+        }
+
+        const OGRLayer& get() const {
+            return *m_layer;
         }
 
-        const char* name() {
+        Dataset& dataset() const {
+            return m_dataset;
+        }
+
+        const char* name() const {
             return m_layer->GetName();
         }
 
@@ -255,31 +339,51 @@ namespace gdalcpp {
             field.SetPrecision(precision);
 
             if (m_layer->CreateField(&field) != OGRERR_NONE) {
-                throw gdal_error(std::string("failed to create field '") + field_name + "' in layer '" + name() + "'",
+                throw gdal_error(std::string("failed to create field '") + field_name + "' in layer '" + name() + "'", OGRERR_NONE,
                     m_dataset.driver_name(), m_dataset.dataset_name(), name(), field_name);
             }
 
             return *this;
         }
 
+        Layer& start_transaction() {
+            OGRErr result = m_layer->StartTransaction();
+            if (result != OGRERR_NONE) {
+                throw gdal_error(std::string("starting transaction on layer '") + name() + "' failed", result, m_dataset.driver_name(), m_dataset.dataset_name(), name());
+            }
+            return *this;
+        }
+
+        Layer& commit_transaction() {
+            OGRErr result = m_layer->CommitTransaction();
+            if (result != OGRERR_NONE) {
+                throw gdal_error(std::string("committing transaction on layer '") + name() + "' failed", result, m_dataset.driver_name(), m_dataset.dataset_name(), name());
+            }
+            return *this;
+         }
+
     }; // class Layer
 
     class Feature {
 
-        OGRLayer* m_layer;
+        Layer& m_layer;
         OGRFeature m_feature;
 
     public:
 
         Feature(Layer& layer, std::unique_ptr<OGRGeometry>&& geometry) :
-            m_layer(layer.get()),
-            m_feature(m_layer->GetLayerDefn()) {
-            m_feature.SetGeometry(geometry.get());
+            m_layer(layer),
+            m_feature(m_layer.get().GetLayerDefn()) {
+            OGRErr result = m_feature.SetGeometryDirectly(geometry.release());
+            if (result != OGRERR_NONE) {
+                throw gdal_error(std::string("setting feature geometry in layer '") + m_layer.name() + "' failed", result, m_layer.dataset().driver_name(), m_layer.dataset().dataset_name());
+            }
         }
 
         void add_to_layer() {
-            if (m_layer->CreateFeature(&m_feature) != OGRERR_NONE) {
-                std::runtime_error("feature creation failed");
+            OGRErr result = m_layer.get().CreateFeature(&m_feature);
+            if (result != OGRERR_NONE) {
+                throw gdal_error(std::string("creating feature in layer '") + m_layer.name() + "' failed", result, m_layer.dataset().driver_name(), m_layer.dataset().dataset_name());
             }
         }
 
diff --git a/include/osmium/area/detail/node_ref_segment.hpp b/include/osmium/area/detail/node_ref_segment.hpp
index ec7b035..aab5b8f 100644
--- a/include/osmium/area/detail/node_ref_segment.hpp
+++ b/include/osmium/area/detail/node_ref_segment.hpp
@@ -204,19 +204,25 @@ namespace osmium {
             }
 
             /**
-             * Calculate the intersection between to NodeRefSegments. The result is returned
-             * as a Location. Note that because the Location uses integers with limited
-             * precision internally, the result might be slightly different than the
-             * numerically correct location.
+             * Calculate the intersection between two NodeRefSegments. The
+             * result is returned as a Location. Note that because the Location
+             * uses integers with limited precision internally, the result
+             * might be slightly different than the numerically correct
+             * location.
              *
-             * If the segments touch in one of their endpoints, it doesn't count as an
-             * intersection.
+             * This function uses integer arithmentic as much as possible and
+             * will not work if the segments are longer than about half the
+             * planet. This shouldn't happen with real data, so it isn't a big
+             * problem.
              *
-             * If the segments intersect not in a single point but in multiple points, ie
-             * if they overlap, this is NOT detected.
+             * If the segments touch in one of their endpoints, it doesn't
+             * count as an intersection.
              *
-             * @returns Undefined osmium::Location if there is no intersection or a defined
-             *          Location if the segments intersect.
+             * If the segments intersect not in a single point but in multiple
+             * points, ie if they overlap, this is NOT detected.
+             *
+             * @returns Undefined osmium::Location if there is no intersection
+             *          or a defined Location if the segments intersect.
              */
             inline osmium::Location calculate_intersection(const NodeRefSegment& s1, const NodeRefSegment& s2) {
                 if (s1.first().location()  == s2.first().location()  ||
@@ -226,26 +232,32 @@ namespace osmium {
                     return osmium::Location();
                 }
 
-                auto d = (static_cast<int64_t>(s2.second().y()) - static_cast<int64_t>(s2.first().y())) *
-                         (static_cast<int64_t>(s1.second().x()) - static_cast<int64_t>(s1.first().x())) -
-                         (static_cast<int64_t>(s2.second().x()) - static_cast<int64_t>(s2.first().x())) *
-                         (static_cast<int64_t>(s1.second().y()) - static_cast<int64_t>(s1.first().y()));
+                int64_t s1ax = s1.first().x();
+                int64_t s1ay = s1.first().y();
+                int64_t s1bx = s1.second().x();
+                int64_t s1by = s1.second().y();
+                int64_t s2ax = s2.first().x();
+                int64_t s2ay = s2.first().y();
+                int64_t s2bx = s2.second().x();
+                int64_t s2by = s2.second().y();
+
+                int64_t d = (s2by - s2ay) * (s1bx - s1ax) -
+                            (s2bx - s2ax) * (s1by - s1ay);
 
                 if (d != 0) {
-                    double denom  = ((s2.second().lat() - s2.first().lat())*(s1.second().lon() - s1.first().lon())) -
-                                    ((s2.second().lon() - s2.first().lon())*(s1.second().lat() - s1.first().lat()));
+                    int64_t na = (s2bx - s2ax) * (s1ay - s2ay) -
+                                 (s2by - s2ay) * (s1ax - s2ax);
+
+                    int64_t nb = (s1bx - s1ax) * (s1ay - s2ay) -
+                                 (s1by - s1ay) * (s1ax - s2ax);
 
-                    double nume_a = ((s2.second().lon() - s2.first().lon())*(s1.first().lat() - s2.first().lat())) -
-                                    ((s2.second().lat() - s2.first().lat())*(s1.first().lon() - s2.first().lon()));
+                    if ((d > 0 && na >= 0 && na <= d && nb >= 0 && nb <= d) ||
+                        (d < 0 && na <= 0 && na >= d && nb <= 0 && nb >= d)) {
 
-                    double nume_b = ((s1.second().lon() - s1.first().lon())*(s1.first().lat() - s2.first().lat())) -
-                                    ((s1.second().lat() - s1.first().lat())*(s1.first().lon() - s2.first().lon()));
+                        double ua = double(na) / d;
+                        int32_t ix = int32_t(s1ax + ua*(s1bx - s1ax));
+                        int32_t iy = int32_t(s1ay + ua*(s1by - s1ay));
 
-                    if ((denom > 0 && nume_a >= 0 && nume_a <= denom && nume_b >= 0 && nume_b <= denom) ||
-                        (denom < 0 && nume_a <= 0 && nume_a >= denom && nume_b <= 0 && nume_b >= denom)) {
-                        double ua = nume_a / denom;
-                        double ix = s1.first().lon() + ua*(s1.second().lon() - s1.first().lon());
-                        double iy = s1.first().lat() + ua*(s1.second().lat() - s1.first().lat());
                         return osmium::Location(ix, iy);
                     }
                 }
diff --git a/include/osmium/area/multipolygon_collector.hpp b/include/osmium/area/multipolygon_collector.hpp
index d3ca10f..2881597 100644
--- a/include/osmium/area/multipolygon_collector.hpp
+++ b/include/osmium/area/multipolygon_collector.hpp
@@ -53,7 +53,7 @@ namespace osmium {
 
     namespace relations {
         class RelationMeta;
-    }
+    } // namespace relations
 
     /**
      * @brief Code related to the building of areas (multipolygons) from relations.
diff --git a/include/osmium/area/problem_reporter_exception.hpp b/include/osmium/area/problem_reporter_exception.hpp
index 5e743c6..7c9a5e3 100644
--- a/include/osmium/area/problem_reporter_exception.hpp
+++ b/include/osmium/area/problem_reporter_exception.hpp
@@ -54,7 +54,7 @@ namespace osmium {
                 ProblemReporterStream(m_sstream) {
             }
 
-            virtual ~ProblemReporterException() = default;
+            ~ProblemReporterException() override = default;
 
             void report_duplicate_node(osmium::object_id_type node_id1, osmium::object_id_type node_id2, osmium::Location location) override {
                 m_sstream.str();
diff --git a/include/osmium/area/problem_reporter_ogr.hpp b/include/osmium/area/problem_reporter_ogr.hpp
index 5332997..68fae3b 100644
--- a/include/osmium/area/problem_reporter_ogr.hpp
+++ b/include/osmium/area/problem_reporter_ogr.hpp
@@ -104,7 +104,7 @@ namespace osmium {
                 m_layer_lerror.add_field("problem_type", OFTString, 30);
             }
 
-            virtual ~ProblemReporterOGR() = default;
+            ~ProblemReporterOGR() override = default;
 
             void report_duplicate_node(osmium::object_id_type node_id1, osmium::object_id_type node_id2, osmium::Location location) override {
                 write_point("duplicate_node", node_id1, node_id2, location);
diff --git a/include/osmium/area/problem_reporter_stream.hpp b/include/osmium/area/problem_reporter_stream.hpp
index ddcb343..b6a004c 100644
--- a/include/osmium/area/problem_reporter_stream.hpp
+++ b/include/osmium/area/problem_reporter_stream.hpp
@@ -54,7 +54,7 @@ namespace osmium {
                 m_out(&out) {
             }
 
-            virtual ~ProblemReporterStream() = default;
+            ~ProblemReporterStream() override = default;
 
             void header(const char* msg) {
                 *m_out << "DATA PROBLEM: " << msg << " on " << item_type_to_char(m_object_type) << m_object_id << ": ";
diff --git a/include/osmium/builder/osm_object_builder.hpp b/include/osmium/builder/osm_object_builder.hpp
index 6aa43ac..82b4b23 100644
--- a/include/osmium/builder/osm_object_builder.hpp
+++ b/include/osmium/builder/osm_object_builder.hpp
@@ -55,7 +55,7 @@ namespace osmium {
 
     namespace memory {
         class Buffer;
-    }
+    } // namespace memory
 
     namespace builder {
 
@@ -123,6 +123,33 @@ namespace osmium {
                          append(value.data(), osmium::memory::item_size_type(value.size()) + 1));
             }
 
+            /**
+             * Add tag to buffer.
+             *
+             * @param tag Tag.
+             */
+            void add_tag(const osmium::Tag& tag) {
+                add_size(append(tag.key()) + append(tag.value()));
+            }
+
+            /**
+             * Add tag to buffer.
+             *
+             * @param tag Pair of key/value 0-terminated strings.
+             */
+            void add_tag(const std::pair<const char*, const char*>& tag) {
+                add_tag(tag.first, tag.second);
+            }
+
+            /**
+             * Add tag to buffer.
+             *
+             * @param tag Pair of std::string references.
+             */
+            void add_tag(const std::pair<const std::string&, const std::string&>& tag) {
+                add_tag(tag.first, tag.second);
+            }
+
         }; // class TagListBuilder
 
         template <typename T>
diff --git a/include/osmium/dynamic_handler.hpp b/include/osmium/dynamic_handler.hpp
index 39baba5..7077554 100644
--- a/include/osmium/dynamic_handler.hpp
+++ b/include/osmium/dynamic_handler.hpp
@@ -113,27 +113,27 @@ auto _name_##_dispatch(THandler& handler, const osmium::_type_& object, long) ->
                     m_handler(std::forward<TArgs>(args)...) {
                 }
 
-                void node(const osmium::Node& node) override final {
+                void node(const osmium::Node& node) final {
                     node_dispatch(m_handler, node, 0);
                 }
 
-                void way(const osmium::Way& way) override final {
+                void way(const osmium::Way& way) final {
                     way_dispatch(m_handler, way, 0);
                 }
 
-                void relation(const osmium::Relation& relation) override final {
+                void relation(const osmium::Relation& relation) final {
                     relation_dispatch(m_handler, relation, 0);
                 }
 
-                void area(const osmium::Area& area) override final {
+                void area(const osmium::Area& area) final {
                     area_dispatch(m_handler, area, 0);
                 }
 
-                void changeset(const osmium::Changeset& changeset) override final {
+                void changeset(const osmium::Changeset& changeset) final {
                     changeset_dispatch(m_handler, changeset, 0);
                 }
 
-                void flush() override final {
+                void flush() final {
                     flush_dispatch(m_handler, 0);
                 }
 
@@ -183,7 +183,7 @@ auto _name_##_dispatch(THandler& handler, const osmium::_type_& object, long) ->
 
         }; // class DynamicHandler
 
-    } // namspace handler
+    } // namespace handler
 
 } // namespace osmium
 
diff --git a/include/osmium/geom/factory.hpp b/include/osmium/geom/factory.hpp
index 49dc78c..1937580 100644
--- a/include/osmium/geom/factory.hpp
+++ b/include/osmium/geom/factory.hpp
@@ -61,7 +61,7 @@ namespace osmium {
 
     public:
 
-        geometry_error(const std::string& message, const char* object_type = "", osmium::object_id_type id = 0) :
+        explicit geometry_error(const std::string& message, const char* object_type = "", osmium::object_id_type id = 0) :
             std::runtime_error(message),
             m_message(message),
             m_id(id) {
@@ -89,7 +89,7 @@ namespace osmium {
             return m_id;
         }
 
-        virtual const char* what() const noexcept override {
+        const char* what() const noexcept override {
             return m_message.c_str();
         }
 
@@ -167,7 +167,7 @@ namespace osmium {
              * Constructor for default initialized projection.
              */
             template <typename... TArgs>
-            GeometryFactory<TGeomImpl, TProjection>(TArgs&&... args) :
+            explicit GeometryFactory<TGeomImpl, TProjection>(TArgs&&... args) :
                 m_projection(),
                 m_impl(std::forward<TArgs>(args)...) {
             }
@@ -177,7 +177,7 @@ namespace osmium {
              * projection is moved into the GeometryFactory.
              */
             template <typename... TArgs>
-            GeometryFactory<TGeomImpl, TProjection>(TProjection&& projection, TArgs&&... args) :
+            explicit GeometryFactory<TGeomImpl, TProjection>(TProjection&& projection, TArgs&&... args) :
                 m_projection(std::move(projection)),
                 m_impl(std::forward<TArgs>(args)...) {
             }
diff --git a/include/osmium/handler.hpp b/include/osmium/handler.hpp
index f366197..47e997e 100644
--- a/include/osmium/handler.hpp
+++ b/include/osmium/handler.hpp
@@ -87,7 +87,7 @@ namespace osmium {
 
         }; // class Handler
 
-    } // namspace handler
+    } // namespace handler
 
 } // namespace osmium
 
diff --git a/include/osmium/index/detail/create_map_with_fd.hpp b/include/osmium/index/detail/create_map_with_fd.hpp
index 5eb6cd0..a2e6b76 100644
--- a/include/osmium/index/detail/create_map_with_fd.hpp
+++ b/include/osmium/index/detail/create_map_with_fd.hpp
@@ -51,15 +51,14 @@ namespace osmium {
             inline T* create_map_with_fd(const std::vector<std::string>& config) {
                 if (config.size() == 1) {
                     return new T();
-                } else {
-                    assert(config.size() > 1);
-                    const std::string& filename = config[1];
-                    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));
-                    }
-                    return new T(fd);
                 }
+                assert(config.size() > 1);
+                const std::string& filename = config[1];
+                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));
+                }
+                return new T(fd);
             }
 
         } // namespace detail
diff --git a/include/osmium/index/detail/vector_map.hpp b/include/osmium/index/detail/vector_map.hpp
index 48b0f62..2a13061 100644
--- a/include/osmium/index/detail/vector_map.hpp
+++ b/include/osmium/index/detail/vector_map.hpp
@@ -68,20 +68,20 @@ namespace osmium {
                     m_vector(fd) {
                 }
 
-                ~VectorBasedDenseMap() noexcept = default;
+                ~VectorBasedDenseMap() noexcept final = default;
 
-                void reserve(const size_t size) override final {
+                void reserve(const size_t size) final {
                     m_vector.reserve(size);
                 }
 
-                void set(const TId id, const TValue value) override final {
+                void set(const TId id, const TValue value) final {
                     if (size() <= id) {
                         m_vector.resize(id+1);
                     }
                     m_vector[id] = value;
                 }
 
-                const TValue get(const TId id) const override final {
+                const TValue get(const TId id) const final {
                     try {
                         const TValue& value = m_vector.at(id);
                         if (value == osmium::index::empty_value<TValue>()) {
@@ -93,7 +93,7 @@ namespace osmium {
                     }
                 }
 
-                size_t size() const override final {
+                size_t size() const final {
                     return m_vector.size();
                 }
 
@@ -101,16 +101,16 @@ namespace osmium {
                     return m_vector.size() * sizeof(element_type);
                 }
 
-                size_t used_memory() const override final {
+                size_t used_memory() const final {
                     return sizeof(TValue) * size();
                 }
 
-                void clear() override final {
+                void clear() final {
                     m_vector.clear();
                     m_vector.shrink_to_fit();
                 }
 
-                void dump_as_array(const int fd) override final {
+                void dump_as_array(const int fd) final {
                     osmium::io::detail::reliable_write(fd, reinterpret_cast<const char*>(m_vector.data()), byte_size());
                 }
 
@@ -161,17 +161,17 @@ namespace osmium {
                     m_vector() {
                 }
 
-                VectorBasedSparseMap(int fd) :
+                explicit VectorBasedSparseMap(int fd) :
                     m_vector(fd) {
                 }
 
-                ~VectorBasedSparseMap() override final = default;
+                ~VectorBasedSparseMap() final = default;
 
-                void set(const TId id, const TValue value) override final {
+                void set(const TId id, const TValue value) final {
                     m_vector.push_back(element_type(id, value));
                 }
 
-                const TValue get(const TId id) const override final {
+                const TValue get(const TId id) const final {
                     const element_type element {
                         id,
                         osmium::index::empty_value<TValue>()
@@ -186,7 +186,7 @@ namespace osmium {
                     }
                 }
 
-                size_t size() const override final {
+                size_t size() const final {
                     return m_vector.size();
                 }
 
@@ -194,20 +194,20 @@ namespace osmium {
                     return m_vector.size() * sizeof(element_type);
                 }
 
-                size_t used_memory() const override final {
+                size_t used_memory() const final {
                     return sizeof(element_type) * size();
                 }
 
-                void clear() override final {
+                void clear() final {
                     m_vector.clear();
                     m_vector.shrink_to_fit();
                 }
 
-                void sort() override final {
+                void sort() final {
                     std::sort(m_vector.begin(), m_vector.end());
                 }
 
-                void dump_as_list(const int fd) override final {
+                void dump_as_list(const int fd) final {
                     osmium::io::detail::reliable_write(fd, reinterpret_cast<const char*>(m_vector.data()), byte_size());
                 }
 
diff --git a/include/osmium/index/detail/vector_multimap.hpp b/include/osmium/index/detail/vector_multimap.hpp
index dc2e15a..789fc94 100644
--- a/include/osmium/index/detail/vector_multimap.hpp
+++ b/include/osmium/index/detail/vector_multimap.hpp
@@ -75,9 +75,9 @@ namespace osmium {
                     m_vector(fd) {
                 }
 
-                ~VectorBasedSparseMultimap() noexcept = default;
+                ~VectorBasedSparseMultimap() noexcept final = default;
 
-                void set(const TId id, const TValue value) override final {
+                void set(const TId id, const TValue value) final {
                     m_vector.push_back(element_type(id, value));
                 }
 
@@ -105,7 +105,7 @@ namespace osmium {
                     });
                 }
 
-                size_t size() const override final {
+                size_t size() const final {
                     return m_vector.size();
                 }
 
@@ -113,16 +113,16 @@ namespace osmium {
                     return m_vector.size() * sizeof(element_type);
                 }
 
-                size_t used_memory() const override final {
+                size_t used_memory() const final {
                     return sizeof(element_type) * size();
                 }
 
-                void clear() override final {
+                void clear() final {
                     m_vector.clear();
                     m_vector.shrink_to_fit();
                 }
 
-                void sort() override final {
+                void sort() final {
                     std::sort(m_vector.begin(), m_vector.end());
                 }
 
@@ -147,7 +147,7 @@ namespace osmium {
                     );
                 }
 
-                void dump_as_list(const int fd) override final {
+                void dump_as_list(const int fd) final {
                     osmium::io::detail::reliable_write(fd, reinterpret_cast<const char*>(m_vector.data()), byte_size());
                 }
 
diff --git a/include/osmium/index/index.hpp b/include/osmium/index/index.hpp
index f415192..78c142d 100644
--- a/include/osmium/index/index.hpp
+++ b/include/osmium/index/index.hpp
@@ -89,7 +89,7 @@ namespace osmium {
          * the full range, so the max value is a good "empty" value.
          */
         template <>
-        inline OSMIUM_CONSTEXPR size_t empty_value<size_t>() {
+        inline constexpr size_t empty_value<size_t>() {
             return std::numeric_limits<size_t>::max();
         }
 
diff --git a/include/osmium/index/map/dummy.hpp b/include/osmium/index/map/dummy.hpp
index 5b471df..d6a360e 100644
--- a/include/osmium/index/map/dummy.hpp
+++ b/include/osmium/index/map/dummy.hpp
@@ -56,25 +56,25 @@ namespace osmium {
 
                 Dummy() = default;
 
-                ~Dummy() noexcept override final = default;
+                ~Dummy() noexcept final = default;
 
-                void set(const TId, const TValue) override final {
+                void set(const TId, const TValue) final {
                     // intentionally left blank
                 }
 
-                const TValue get(const TId id) const override final {
+                const TValue get(const TId id) const final {
                     not_found_error(id);
                 }
 
-                size_t size() const override final {
+                size_t size() const final {
                     return 0;
                 }
 
-                size_t used_memory() const override final {
+                size_t used_memory() const final {
                     return 0;
                 }
 
-                void clear() override final {
+                void clear() final {
                 }
 
             }; // class Dummy
diff --git a/include/osmium/index/map/sparse_mem_map.hpp b/include/osmium/index/map/sparse_mem_map.hpp
index 9bad07e..d001b67 100644
--- a/include/osmium/index/map/sparse_mem_map.hpp
+++ b/include/osmium/index/map/sparse_mem_map.hpp
@@ -71,13 +71,13 @@ namespace osmium {
 
                 SparseMemMap() = default;
 
-                ~SparseMemMap() noexcept override final = default;
+                ~SparseMemMap() noexcept final = default;
 
-                void set(const TId id, const TValue value) override final {
+                void set(const TId id, const TValue value) final {
                     m_elements[id] = value;
                 }
 
-                const TValue get(const TId id) const override final {
+                const TValue get(const TId id) const final {
                     auto it = m_elements.find(id);
                     if (it == m_elements.end()) {
                         not_found_error(id);
@@ -85,19 +85,19 @@ namespace osmium {
                     return it->second;
                 }
 
-                size_t size() const noexcept override final {
+                size_t size() const noexcept final {
                     return m_elements.size();
                 }
 
-                size_t used_memory() const noexcept override final {
+                size_t used_memory() const noexcept final {
                     return element_size * m_elements.size();
                 }
 
-                void clear() override final {
+                void clear() final {
                     m_elements.clear();
                 }
 
-                void dump_as_list(const int fd) override final {
+                void dump_as_list(const int fd) final {
                     typedef typename std::map<TId, TValue>::value_type t;
                     std::vector<t> v;
                     v.reserve(m_elements.size());
diff --git a/include/osmium/index/map/sparse_mem_table.hpp b/include/osmium/index/map/sparse_mem_table.hpp
index 032400e..797a926 100644
--- a/include/osmium/index/map/sparse_mem_table.hpp
+++ b/include/osmium/index/map/sparse_mem_table.hpp
@@ -88,16 +88,16 @@ namespace osmium {
                     m_elements(grow_size) {
                 }
 
-                ~SparseMemTable() noexcept override final = default;
+                ~SparseMemTable() noexcept final = default;
 
-                void set(const TId id, const TValue value) override final {
+                void set(const TId id, const TValue value) final {
                     if (id >= m_elements.size()) {
                         m_elements.resize(id + m_grow_size);
                     }
                     m_elements[id] = value;
                 }
 
-                const TValue get(const TId id) const override final {
+                const TValue get(const TId id) const final {
                     if (id >= m_elements.size()) {
                         not_found_error(id);
                     }
@@ -107,21 +107,21 @@ namespace osmium {
                     return m_elements[id];
                 }
 
-                size_t size() const override final {
+                size_t size() const final {
                     return m_elements.size();
                 }
 
-                size_t used_memory() const override final {
+                size_t used_memory() const final {
                     // unused elements use 1 bit, used elements sizeof(TValue) bytes
                     // http://google-sparsehash.googlecode.com/svn/trunk/doc/sparsetable.html
                     return (m_elements.size() / 8) + (m_elements.num_nonempty() * sizeof(TValue));
                 }
 
-                void clear() override final {
+                void clear() final {
                     m_elements.clear();
                 }
 
-                void dump_as_list(const int fd) override final {
+                void dump_as_list(const int fd) final {
                     std::vector<std::pair<TId, TValue>> v;
                     v.reserve(m_elements.size());
                     int n = 0;
diff --git a/include/osmium/index/multimap.hpp b/include/osmium/index/multimap.hpp
index c817b6f..a7e1aad 100644
--- a/include/osmium/index/multimap.hpp
+++ b/include/osmium/index/multimap.hpp
@@ -118,7 +118,7 @@ namespace osmium {
 
             }; // class Multimap
 
-        } // namespace map
+        } // namespace multimap
 
     } // namespace index
 
diff --git a/include/osmium/index/multimap/hybrid.hpp b/include/osmium/index/multimap/hybrid.hpp
index cdf14a3..e13ee68 100644
--- a/include/osmium/index/multimap/hybrid.hpp
+++ b/include/osmium/index/multimap/hybrid.hpp
@@ -138,11 +138,11 @@ namespace osmium {
 
                 ~Hybrid() noexcept = default;
 
-                size_t size() const override final {
+                size_t size() const final {
                     return m_main.size() + m_extra.size();
                 }
 
-                size_t used_memory() const override final {
+                size_t used_memory() const final {
                     return m_main.used_memory() + m_extra.used_memory();
                 }
 
@@ -154,7 +154,7 @@ namespace osmium {
                     m_main.set(id, value);
                 }
 
-                void set(const TId id, const TValue value) override final {
+                void set(const TId id, const TValue value) final {
                     m_extra.set(id, value);
                 }
 
@@ -179,17 +179,17 @@ namespace osmium {
                     m_main.sort();
                 }
 
-                void dump_as_list(const int fd) override final {
+                void dump_as_list(const int fd) final {
                     consolidate();
                     m_main.dump_as_list(fd);
                 }
 
-                void clear() override final {
+                void clear() final {
                     m_main.clear();
                     m_extra.clear();
                 }
 
-                void sort() override final {
+                void sort() final {
                     m_main.sort();
                 }
 
diff --git a/include/osmium/index/multimap/sparse_mem_multimap.hpp b/include/osmium/index/multimap/sparse_mem_multimap.hpp
index 353e357..84cb640 100644
--- a/include/osmium/index/multimap/sparse_mem_multimap.hpp
+++ b/include/osmium/index/multimap/sparse_mem_multimap.hpp
@@ -78,13 +78,13 @@ namespace osmium {
 
                 SparseMemMultimap() = default;
 
-                ~SparseMemMultimap() noexcept override final = default;
+                ~SparseMemMultimap() noexcept final = default;
 
                 void unsorted_set(const TId id, const TValue value) {
                     m_elements.emplace(id, value);
                 }
 
-                void set(const TId id, const TValue value) override final {
+                void set(const TId id, const TValue value) final {
                     m_elements.emplace(id, value);
                 }
 
@@ -114,15 +114,15 @@ namespace osmium {
                     return m_elements.end();
                 }
 
-                size_t size() const override final {
+                size_t size() const final {
                     return m_elements.size();
                 }
 
-                size_t used_memory() const override final {
+                size_t used_memory() const final {
                     return element_size * m_elements.size();
                 }
 
-                void clear() override final {
+                void clear() final {
                     m_elements.clear();
                 }
 
@@ -130,7 +130,7 @@ namespace osmium {
                     // intentionally left blank
                 }
 
-                void dump_as_list(const int fd) override final {
+                void dump_as_list(const int fd) final {
                     std::vector<element_type> v;
                     v.reserve(m_elements.size());
                     for (const auto& element : m_elements) {
diff --git a/include/osmium/io/bzip2_compression.hpp b/include/osmium/io/bzip2_compression.hpp
index ad4b877..fc0e33c 100644
--- a/include/osmium/io/bzip2_compression.hpp
+++ b/include/osmium/io/bzip2_compression.hpp
@@ -117,7 +117,7 @@ namespace osmium {
                 }
             }
 
-            ~Bzip2Compressor() noexcept override final {
+            ~Bzip2Compressor() noexcept final {
                 try {
                     close();
                 } catch (...) {
@@ -125,7 +125,7 @@ namespace osmium {
                 }
             }
 
-            void write(const std::string& data) override final {
+            void write(const std::string& data) final {
                 int error;
                 ::BZ2_bzWrite(&error, m_bzfile, const_cast<char*>(data.data()), static_cast_with_assert<int>(data.size()));
                 if (error != BZ_OK && error != BZ_STREAM_END) {
@@ -133,7 +133,7 @@ namespace osmium {
                 }
             }
 
-            void close() override final {
+            void close() final {
                 if (m_bzfile) {
                     int error;
                     ::BZ2_bzWriteClose(&error, m_bzfile, 0, nullptr, nullptr);
@@ -163,7 +163,7 @@ namespace osmium {
 
         public:
 
-            Bzip2Decompressor(int fd) :
+            explicit Bzip2Decompressor(int fd) :
                 Decompressor(),
                 m_file(fdopen(dup(fd), "rb")),
                 m_bzerror(BZ_OK),
@@ -173,7 +173,7 @@ namespace osmium {
                 }
             }
 
-            ~Bzip2Decompressor() noexcept override final {
+            ~Bzip2Decompressor() noexcept final {
                 try {
                     close();
                 } catch (...) {
@@ -181,7 +181,7 @@ namespace osmium {
                 }
             }
 
-            std::string read() override final {
+            std::string read() final {
                 std::string buffer;
 
                 if (!m_stream_end) {
@@ -218,7 +218,7 @@ namespace osmium {
                 return buffer;
             }
 
-            void close() override final {
+            void close() final {
                 if (m_bzfile) {
                     int error;
                     ::BZ2_bzReadClose(&error, m_bzfile);
@@ -257,7 +257,7 @@ namespace osmium {
                 }
             }
 
-            ~Bzip2BufferDecompressor() noexcept override final {
+            ~Bzip2BufferDecompressor() noexcept final {
                 try {
                     close();
                 } catch (...) {
@@ -265,7 +265,7 @@ namespace osmium {
                 }
             }
 
-            std::string read() override final {
+            std::string read() final {
                 std::string output;
 
                 if (m_buffer) {
@@ -291,7 +291,7 @@ namespace osmium {
                 return output;
             }
 
-            void close() override final {
+            void close() final {
                 BZ2_bzDecompressEnd(&m_bzstream);
             }
 
diff --git a/include/osmium/io/compression.hpp b/include/osmium/io/compression.hpp
index 4a69be7..b337503 100644
--- a/include/osmium/io/compression.hpp
+++ b/include/osmium/io/compression.hpp
@@ -211,7 +211,7 @@ namespace osmium {
                 m_fd(fd) {
             }
 
-            ~NoCompressor() noexcept override final {
+            ~NoCompressor() noexcept final {
                 try {
                     close();
                 } catch (...) {
@@ -219,11 +219,11 @@ namespace osmium {
                 }
             }
 
-            void write(const std::string& data) override final {
+            void write(const std::string& data) final {
                 osmium::io::detail::reliable_write(m_fd, data.data(), data.size());
             }
 
-            void close() override final {
+            void close() final {
                 if (m_fd >= 0) {
                     int fd = m_fd;
                     m_fd = -1;
@@ -244,7 +244,7 @@ namespace osmium {
 
         public:
 
-            NoDecompressor(int fd) :
+            explicit NoDecompressor(int fd) :
                 Decompressor(),
                 m_fd(fd),
                 m_buffer(nullptr),
@@ -258,7 +258,7 @@ namespace osmium {
                 m_buffer_size(size) {
             }
 
-            ~NoDecompressor() noexcept override final {
+            ~NoDecompressor() noexcept final {
                 try {
                     close();
                 } catch (...) {
@@ -266,7 +266,7 @@ namespace osmium {
                 }
             }
 
-            std::string read() override final {
+            std::string read() final {
                 std::string buffer;
 
                 if (m_buffer) {
@@ -287,7 +287,7 @@ namespace osmium {
                 return buffer;
             }
 
-            void close() override final {
+            void close() final {
                 if (m_fd >= 0) {
                     int fd = m_fd;
                     m_fd = -1;
diff --git a/include/osmium/io/detail/debug_output_format.hpp b/include/osmium/io/detail/debug_output_format.hpp
index 90ec199..f1766de 100644
--- a/include/osmium/io/detail/debug_output_format.hpp
+++ b/include/osmium/io/detail/debug_output_format.hpp
@@ -419,9 +419,9 @@ namespace osmium {
                 DebugOutputFormat(const DebugOutputFormat&) = delete;
                 DebugOutputFormat& operator=(const DebugOutputFormat&) = delete;
 
-                ~DebugOutputFormat() noexcept = default;
+                ~DebugOutputFormat() noexcept final = default;
 
-                void write_header(const osmium::io::Header& header) override final {
+                void write_header(const osmium::io::Header& header) final {
                     std::string out;
 
                     if (m_options.use_color) {
@@ -458,7 +458,7 @@ namespace osmium {
                     send_to_output_queue(std::move(out));
                 }
 
-                void write_buffer(osmium::memory::Buffer&& buffer) override final {
+                void write_buffer(osmium::memory::Buffer&& buffer) final {
                     m_output_queue.push(osmium::thread::Pool::instance().submit(DebugOutputBlock{std::move(buffer), m_options}));
                 }
 
diff --git a/include/osmium/io/detail/o5m_input_format.hpp b/include/osmium/io/detail/o5m_input_format.hpp
index b5b5c71..0318432 100644
--- a/include/osmium/io/detail/o5m_input_format.hpp
+++ b/include/osmium/io/detail/o5m_input_format.hpp
@@ -59,6 +59,7 @@ DEALINGS IN THE SOFTWARE.
 #include <osmium/osm/location.hpp>
 #include <osmium/osm/object.hpp>
 #include <osmium/osm/types.hpp>
+#include <osmium/thread/util.hpp>
 #include <osmium/util/cast.hpp>
 #include <osmium/util/delta.hpp>
 
@@ -71,7 +72,7 @@ namespace osmium {
      */
     struct o5m_error : public io_error {
 
-        o5m_error(const char* what) :
+        explicit o5m_error(const char* what) :
             io_error(std::string("o5m format error: ") + what) {
         }
 
@@ -599,9 +600,11 @@ namespace osmium {
                     m_end(m_data) {
                 }
 
-                ~O5mParser() noexcept = default;
+                ~O5mParser() noexcept final = default;
+
+                void run() final {
+                    osmium::thread::set_thread_name("_osmium_o5m_in");
 
-                void run() override final {
                     decode_header();
                     decode_data();
                 }
diff --git a/include/osmium/io/detail/opl_output_format.hpp b/include/osmium/io/detail/opl_output_format.hpp
index 5c40bf2..2d863ea 100644
--- a/include/osmium/io/detail/opl_output_format.hpp
+++ b/include/osmium/io/detail/opl_output_format.hpp
@@ -232,9 +232,9 @@ namespace osmium {
                 OPLOutputFormat(const OPLOutputFormat&) = delete;
                 OPLOutputFormat& operator=(const OPLOutputFormat&) = delete;
 
-                ~OPLOutputFormat() noexcept = default;
+                ~OPLOutputFormat() noexcept final = default;
 
-                void write_buffer(osmium::memory::Buffer&& buffer) override final {
+                void write_buffer(osmium::memory::Buffer&& buffer) final {
                     m_output_queue.push(osmium::thread::Pool::instance().submit(OPLOutputBlock{std::move(buffer), m_options}));
                 }
 
diff --git a/include/osmium/io/detail/output_format.hpp b/include/osmium/io/detail/output_format.hpp
index ba1fb41..4c38c4d 100644
--- a/include/osmium/io/detail/output_format.hpp
+++ b/include/osmium/io/detail/output_format.hpp
@@ -51,7 +51,7 @@ namespace osmium {
 
     namespace io {
         class Header;
-    }
+    } // namespace io
 
     namespace io {
 
diff --git a/include/osmium/io/detail/pbf.hpp b/include/osmium/io/detail/pbf.hpp
index 4a32a63..13d5529 100644
--- a/include/osmium/io/detail/pbf.hpp
+++ b/include/osmium/io/detail/pbf.hpp
@@ -54,11 +54,11 @@ namespace osmium {
      */
     struct pbf_error : public io_error {
 
-        pbf_error(const std::string& what) :
+        explicit pbf_error(const std::string& what) :
             io_error(std::string("PBF error: ") + what) {
         }
 
-        pbf_error(const char* what) :
+        explicit pbf_error(const char* what) :
             io_error(std::string("PBF error: ") + what) {
         }
 
@@ -80,9 +80,9 @@ namespace osmium {
 
             const int64_t resolution_convert = lonlat_resolution / osmium::Location::coordinate_precision;
 
-        }
+        } // namespace detail
 
-    }
+    } // namespace io
 
 } // namespace osmium
 
diff --git a/include/osmium/io/detail/pbf_input_format.hpp b/include/osmium/io/detail/pbf_input_format.hpp
index 4464fd7..e9d0e71 100644
--- a/include/osmium/io/detail/pbf_input_format.hpp
+++ b/include/osmium/io/detail/pbf_input_format.hpp
@@ -203,9 +203,9 @@ namespace osmium {
                     m_input_buffer() {
                 }
 
-                ~PBFParser() noexcept = default;
+                ~PBFParser() noexcept final = default;
 
-                void run() override final {
+                void run() final {
                     osmium::thread::set_thread_name("_osmium_pbf_in");
 
                     parse_header_blob();
diff --git a/include/osmium/io/detail/pbf_output_format.hpp b/include/osmium/io/detail/pbf_output_format.hpp
index 97b143b..88c1cf4 100644
--- a/include/osmium/io/detail/pbf_output_format.hpp
+++ b/include/osmium/io/detail/pbf_output_format.hpp
@@ -224,7 +224,7 @@ namespace osmium {
 
                 osmium::util::DeltaEncode<object_id_type, int64_t> m_delta_id;
 
-                osmium::util::DeltaEncode<time_t, int64_t> m_delta_timestamp;
+                osmium::util::DeltaEncode<uint32_t, int64_t> m_delta_timestamp;
                 osmium::util::DeltaEncode<changeset_id_type, int64_t> m_delta_changeset;
                 osmium::util::DeltaEncode<user_id_type, int32_t> m_delta_uid;
                 osmium::util::DeltaEncode<uint32_t, int32_t> m_delta_user_sid;
@@ -276,7 +276,7 @@ namespace osmium {
 
                     if (m_options.add_metadata) {
                         m_versions.push_back(static_cast_with_assert<int32_t>(node.version()));
-                        m_timestamps.push_back(m_delta_timestamp.update(node.timestamp()));
+                        m_timestamps.push_back(m_delta_timestamp.update(uint32_t(node.timestamp())));
                         m_changesets.push_back(m_delta_changeset.update(node.changeset()));
                         m_uids.push_back(m_delta_uid.update(node.uid()));
                         m_user_sids.push_back(m_delta_user_sid.update(m_stringtable.add(node.user())));
@@ -335,7 +335,7 @@ namespace osmium {
 
             public:
 
-                PrimitiveBlock(const pbf_output_options& options) :
+                explicit PrimitiveBlock(const pbf_output_options& options) :
                     m_pbf_primitive_group_data(),
                     m_pbf_primitive_group(m_pbf_primitive_group_data),
                     m_stringtable(),
@@ -462,7 +462,7 @@ namespace osmium {
                         protozero::pbf_builder<OSMFormat::Info> pbf_info(pbf_object, T::enum_type::optional_Info_info);
 
                         pbf_info.add_int32(OSMFormat::Info::optional_int32_version, static_cast_with_assert<int32_t>(object.version()));
-                        pbf_info.add_int64(OSMFormat::Info::optional_int64_timestamp, object.timestamp());
+                        pbf_info.add_int64(OSMFormat::Info::optional_int64_timestamp, uint32_t(object.timestamp()));
                         pbf_info.add_int64(OSMFormat::Info::optional_int64_changeset, object.changeset());
                         pbf_info.add_int32(OSMFormat::Info::optional_int32_uid, static_cast_with_assert<int32_t>(object.uid()));
                         pbf_info.add_uint32(OSMFormat::Info::optional_uint32_user_sid, m_primitive_block.store_in_stringtable(object.user()));
@@ -495,9 +495,9 @@ namespace osmium {
                 PBFOutputFormat(const PBFOutputFormat&) = delete;
                 PBFOutputFormat& operator=(const PBFOutputFormat&) = delete;
 
-                ~PBFOutputFormat() noexcept = default;
+                ~PBFOutputFormat() noexcept final = default;
 
-                void write_header(const osmium::io::Header& header) override final {
+                void write_header(const osmium::io::Header& header) final {
                     std::string data;
                     protozero::pbf_builder<OSMFormat::HeaderBlock> pbf_header_block(data);
 
@@ -526,7 +526,7 @@ namespace osmium {
                     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, ts);
+                        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");
@@ -546,11 +546,11 @@ namespace osmium {
                         ));
                 }
 
-                void write_buffer(osmium::memory::Buffer&& buffer) override final {
+                void write_buffer(osmium::memory::Buffer&& buffer) final {
                     osmium::apply(buffer.cbegin(), buffer.cend(), *this);
                 }
 
-                void write_end() override final {
+                void write_end() final {
                     store_primitive_block();
                 }
 
diff --git a/include/osmium/io/detail/queue_util.hpp b/include/osmium/io/detail/queue_util.hpp
index d410df1..6c9f071 100644
--- a/include/osmium/io/detail/queue_util.hpp
+++ b/include/osmium/io/detail/queue_util.hpp
@@ -110,7 +110,7 @@ namespace osmium {
 
             public:
 
-                queue_wrapper(queue_type& queue) :
+                explicit queue_wrapper(queue_type& queue) :
                     m_queue(queue),
                     m_has_reached_end_of_data(false) {
                 }
diff --git a/include/osmium/io/detail/read_write.hpp b/include/osmium/io/detail/read_write.hpp
index 5d1fa26..6db6d8a 100644
--- a/include/osmium/io/detail/read_write.hpp
+++ b/include/osmium/io/detail/read_write.hpp
@@ -73,22 +73,22 @@ namespace osmium {
                     _setmode(1, _O_BINARY);
 #endif
                     return 1; // stdout
+                }
+
+                int flags = O_WRONLY | O_CREAT;
+                if (allow_overwrite == osmium::io::overwrite::allow) {
+                    flags |= O_TRUNC;
                 } else {
-                    int flags = O_WRONLY | O_CREAT;
-                    if (allow_overwrite == osmium::io::overwrite::allow) {
-                        flags |= O_TRUNC;
-                    } else {
-                        flags |= O_EXCL;
-                    }
+                    flags |= O_EXCL;
+                }
 #ifdef _WIN32
-                    flags |= O_BINARY;
+                flags |= O_BINARY;
 #endif
-                    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 + "'");
-                    }
-                    return fd;
+                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 + "'");
                 }
+                return fd;
             }
 
             /**
@@ -102,17 +102,17 @@ namespace osmium {
             inline int open_for_reading(const std::string& filename) {
                 if (filename == "" || filename == "-") {
                     return 0; // stdin
-                } else {
-                    int flags = O_RDONLY;
+                }
+
+                int flags = O_RDONLY;
 #ifdef _WIN32
-                    flags |= O_BINARY;
+                flags |= O_BINARY;
 #endif
-                    int fd = ::open(filename.c_str(), flags);
-                    if (fd < 0) {
-                        throw std::system_error(errno, std::system_category(), std::string("Open failed for '") + filename + "'");
-                    }
-                    return fd;
+                int fd = ::open(filename.c_str(), flags);
+                if (fd < 0) {
+                    throw std::system_error(errno, std::system_category(), std::string("Open failed for '") + filename + "'");
                 }
+                return fd;
             }
 
             /**
diff --git a/include/osmium/io/detail/string_table.hpp b/include/osmium/io/detail/string_table.hpp
index a23035d..1cb142d 100644
--- a/include/osmium/io/detail/string_table.hpp
+++ b/include/osmium/io/detail/string_table.hpp
@@ -75,7 +75,7 @@ namespace osmium {
 
             public:
 
-                StringStore(size_t chunk_size) :
+                explicit StringStore(size_t chunk_size) :
                     m_chunk_size(chunk_size),
                     m_chunks() {
                     add_chunk();
diff --git a/include/osmium/io/detail/xml_input_format.hpp b/include/osmium/io/detail/xml_input_format.hpp
index 45dbde0..11d3cba 100644
--- a/include/osmium/io/detail/xml_input_format.hpp
+++ b/include/osmium/io/detail/xml_input_format.hpp
@@ -194,7 +194,7 @@ namespace osmium {
 
                 public:
 
-                    ExpatXMLParser(T* callback_object) :
+                    explicit ExpatXMLParser(T* callback_object) :
                         m_parser(XML_ParserCreate(nullptr)) {
                         if (!m_parser) {
                             throw osmium::io_error("Internal error: Can not create parser");
@@ -630,9 +630,9 @@ namespace osmium {
                     m_rml_builder() {
                 }
 
-                ~XMLParser() noexcept = default;
+                ~XMLParser() noexcept final = default;
 
-                void run() override final {
+                void run() final {
                     osmium::thread::set_thread_name("_osmium_xml_in");
 
                     ExpatXMLParser<XMLParser> parser(this);
diff --git a/include/osmium/io/detail/xml_output_format.hpp b/include/osmium/io/detail/xml_output_format.hpp
index b91b051..3d7878c 100644
--- a/include/osmium/io/detail/xml_output_format.hpp
+++ b/include/osmium/io/detail/xml_output_format.hpp
@@ -402,9 +402,9 @@ namespace osmium {
                 XMLOutputFormat(const XMLOutputFormat&) = delete;
                 XMLOutputFormat& operator=(const XMLOutputFormat&) = delete;
 
-                ~XMLOutputFormat() noexcept = default;
+                ~XMLOutputFormat() noexcept final = default;
 
-                void write_header(const osmium::io::Header& header) override final {
+                void write_header(const osmium::io::Header& header) final {
                     std::string out = "<?xml version='1.0' encoding='UTF-8'?>\n";
 
                     if (m_options.use_change_ops) {
@@ -434,11 +434,11 @@ namespace osmium {
                     send_to_output_queue(std::move(out));
                 }
 
-                void write_buffer(osmium::memory::Buffer&& buffer) override final {
+                void write_buffer(osmium::memory::Buffer&& buffer) final {
                     m_output_queue.push(osmium::thread::Pool::instance().submit(XMLOutputBlock{std::move(buffer), m_options}));
                 }
 
-                void write_end() override final {
+                void write_end() final {
                     std::string out;
 
                     if (m_options.use_change_ops) {
@@ -466,7 +466,7 @@ namespace osmium {
 
         } // namespace detail
 
-    } // namespace output
+    } // namespace io
 
 } // namespace osmium
 
diff --git a/include/osmium/io/error.hpp b/include/osmium/io/error.hpp
index 0b5393f..6b5c677 100644
--- a/include/osmium/io/error.hpp
+++ b/include/osmium/io/error.hpp
@@ -43,11 +43,11 @@ namespace osmium {
      */
     struct io_error : public std::runtime_error {
 
-        io_error(const std::string& what) :
+        explicit io_error(const std::string& what) :
             std::runtime_error(what) {
         }
 
-        io_error(const char* what) :
+        explicit io_error(const char* what) :
             std::runtime_error(what) {
         }
 
@@ -55,11 +55,11 @@ namespace osmium {
 
     struct unsupported_file_format_error : public io_error {
 
-        unsupported_file_format_error(const std::string& what) :
+        explicit unsupported_file_format_error(const std::string& what) :
             io_error(what) {
         }
 
-        unsupported_file_format_error(const char* what) :
+        explicit unsupported_file_format_error(const char* what) :
             io_error(what) {
         }
 
diff --git a/include/osmium/io/gzip_compression.hpp b/include/osmium/io/gzip_compression.hpp
index 705f416..1847875 100644
--- a/include/osmium/io/gzip_compression.hpp
+++ b/include/osmium/io/gzip_compression.hpp
@@ -109,7 +109,7 @@ namespace osmium {
                 }
             }
 
-            ~GzipCompressor() noexcept override final {
+            ~GzipCompressor() noexcept final {
                 try {
                     close();
                 } catch (...) {
@@ -117,7 +117,7 @@ namespace osmium {
                 }
             }
 
-            void write(const std::string& data) override final {
+            void write(const std::string& data) final {
                 if (!data.empty()) {
                     int nwrite = ::gzwrite(m_gzfile, data.data(), static_cast_with_assert<unsigned int>(data.size()));
                     if (nwrite == 0) {
@@ -126,7 +126,7 @@ namespace osmium {
                 }
             }
 
-            void close() override final {
+            void close() final {
                 if (m_gzfile) {
                     int result = ::gzclose(m_gzfile);
                     m_gzfile = nullptr;
@@ -156,7 +156,7 @@ namespace osmium {
                 }
             }
 
-            ~GzipDecompressor() noexcept override final {
+            ~GzipDecompressor() noexcept final {
                 try {
                     close();
                 } catch (...) {
@@ -164,7 +164,7 @@ namespace osmium {
                 }
             }
 
-            std::string read() override final {
+            std::string read() final {
                 std::string buffer(osmium::io::Decompressor::input_buffer_size, '\0');
                 int nread = ::gzread(m_gzfile, const_cast<char*>(buffer.data()), static_cast_with_assert<unsigned int>(buffer.size()));
                 if (nread < 0) {
@@ -174,7 +174,7 @@ namespace osmium {
                 return buffer;
             }
 
-            void close() override final {
+            void close() final {
                 if (m_gzfile) {
                     int result = ::gzclose(m_gzfile);
                     m_gzfile = nullptr;
@@ -210,7 +210,7 @@ namespace osmium {
                 }
             }
 
-            ~GzipBufferDecompressor() noexcept override final {
+            ~GzipBufferDecompressor() noexcept final {
                 try {
                     close();
                 } catch (...) {
@@ -218,7 +218,7 @@ namespace osmium {
                 }
             }
 
-            std::string read() override final {
+            std::string read() final {
                 std::string output;
 
                 if (m_buffer) {
@@ -247,7 +247,7 @@ namespace osmium {
                 return output;
             }
 
-            void close() override final {
+            void close() final {
                 inflateEnd(&m_zstream);
             }
 
diff --git a/include/osmium/io/reader.hpp b/include/osmium/io/reader.hpp
index 54c518e..fd2a6d2 100644
--- a/include/osmium/io/reader.hpp
+++ b/include/osmium/io/reader.hpp
@@ -206,7 +206,7 @@ namespace osmium {
                 m_decompressor(m_file.buffer() ?
                     osmium::io::CompressionFactory::instance().create_decompressor(file.compression(), m_file.buffer(), m_file.buffer_size()) :
                     osmium::io::CompressionFactory::instance().create_decompressor(file.compression(), open_input_file_or_url(m_file.filename(), &m_childpid))),
-                m_read_thread_manager(*m_decompressor.get(), m_input_queue),
+                m_read_thread_manager(*m_decompressor, m_input_queue),
                 m_osmdata_queue(max_osmdata_queue_size, "parser_results"),
                 m_osmdata_queue_wrapper(m_osmdata_queue),
                 m_header_future(),
diff --git a/include/osmium/memory/buffer.hpp b/include/osmium/memory/buffer.hpp
index ce8c587..bc6e9f8 100644
--- a/include/osmium/memory/buffer.hpp
+++ b/include/osmium/memory/buffer.hpp
@@ -98,6 +98,9 @@ namespace osmium {
 
         public:
 
+            // This is needed so we can call std::back_inserter() on a Buffer.
+            using value_type = Item;
+
             enum class auto_grow : bool {
                 yes = true,
                 no  = false
@@ -647,7 +650,7 @@ namespace osmium {
             /**
              * In a bool context any valid buffer is true.
              */
-            explicit operator bool() const {
+            explicit operator bool() const noexcept {
                 return m_data != nullptr;
             }
 
diff --git a/include/osmium/memory/collection.hpp b/include/osmium/memory/collection.hpp
index 54a97f5..3878b9a 100644
--- a/include/osmium/memory/collection.hpp
+++ b/include/osmium/memory/collection.hpp
@@ -59,7 +59,7 @@ namespace osmium {
                 m_data(nullptr) {
             }
 
-            CollectionIterator(data_type data) noexcept :
+            explicit CollectionIterator(data_type data) noexcept :
                 m_data(data) {
             }
 
diff --git a/include/osmium/memory/item.hpp b/include/osmium/memory/item.hpp
index 30c5377..f95ce88 100644
--- a/include/osmium/memory/item.hpp
+++ b/include/osmium/memory/item.hpp
@@ -43,7 +43,7 @@ namespace osmium {
 
     namespace builder {
         class Builder;
-    }
+    } // namespace builder
 
     namespace memory {
 
diff --git a/include/osmium/memory/item_iterator.hpp b/include/osmium/memory/item_iterator.hpp
index 5751698..87af568 100644
--- a/include/osmium/memory/item_iterator.hpp
+++ b/include/osmium/memory/item_iterator.hpp
@@ -205,7 +205,7 @@ namespace osmium {
             }
 
             explicit operator bool() const {
-                return bool(m_data) && (m_data != m_end);
+                return (m_data != nullptr) && (m_data != m_end);
             }
 
             template <typename TChar, typename TTraits>
diff --git a/include/osmium/osm/area.hpp b/include/osmium/osm/area.hpp
index 4e11c8b..7fb2a79 100644
--- a/include/osmium/osm/area.hpp
+++ b/include/osmium/osm/area.hpp
@@ -48,7 +48,7 @@ namespace osmium {
 
     namespace builder {
         template <class T> class ObjectBuilder;
-    }
+    } // namespace builder
 
     /**
      * An outer ring of an Area.
diff --git a/include/osmium/osm/box.hpp b/include/osmium/osm/box.hpp
index 631f919..155f5e9 100644
--- a/include/osmium/osm/box.hpp
+++ b/include/osmium/osm/box.hpp
@@ -154,14 +154,14 @@ namespace osmium {
          * Box is valid, ie. defined and inside usual bounds
          * (-180<=lon<=180, -90<=lat<=90).
          */
-        OSMIUM_CONSTEXPR bool valid() const noexcept {
+        constexpr bool valid() const noexcept {
             return bottom_left().valid() && top_right().valid();
         }
 
         /**
          * Access bottom-left location.
          */
-        OSMIUM_CONSTEXPR Location bottom_left() const noexcept {
+        constexpr Location bottom_left() const noexcept {
             return m_bottom_left;
         }
 
@@ -175,7 +175,7 @@ namespace osmium {
         /**
          * Access top-right location.
          */
-        OSMIUM_CONSTEXPR Location top_right() const noexcept {
+        constexpr Location top_right() const noexcept {
             return m_top_right;
         }
 
@@ -216,7 +216,7 @@ namespace osmium {
      * Boxes are equal if both locations are equal. Undefined boxes will
      * compare equal.
      */
-    inline OSMIUM_CONSTEXPR bool operator==(const Box& lhs, const Box& rhs) noexcept {
+    inline constexpr bool operator==(const Box& lhs, const Box& rhs) noexcept {
         return lhs.bottom_left() == rhs.bottom_left() &&
                lhs.top_right() == rhs.top_right();
     }
diff --git a/include/osmium/osm/changeset.hpp b/include/osmium/osm/changeset.hpp
index 051b525..db3f717 100644
--- a/include/osmium/osm/changeset.hpp
+++ b/include/osmium/osm/changeset.hpp
@@ -50,7 +50,7 @@ namespace osmium {
     namespace builder {
         class ChangesetDiscussionBuilder;
         template <typename T> class ObjectBuilder;
-    }
+    } // namespace builder
 
     class Changeset;
 
diff --git a/include/osmium/osm/crc.hpp b/include/osmium/osm/crc.hpp
index 309f50a..f5e01e4 100644
--- a/include/osmium/osm/crc.hpp
+++ b/include/osmium/osm/crc.hpp
@@ -77,7 +77,7 @@ namespace osmium {
 # endif
         }
 
-    }
+    } // namespace util
 
     template <typename TCRC>
     class CRC {
diff --git a/include/osmium/osm/location.hpp b/include/osmium/osm/location.hpp
index 0d4fdc1..f79117e 100644
--- a/include/osmium/osm/location.hpp
+++ b/include/osmium/osm/location.hpp
@@ -52,11 +52,11 @@ namespace osmium {
      */
     struct invalid_location : public std::range_error {
 
-        invalid_location(const std::string& what) :
+        explicit invalid_location(const std::string& what) :
             std::range_error(what) {
         }
 
-        invalid_location(const char* what) :
+        explicit invalid_location(const char* what) :
             std::range_error(what) {
         }
 
@@ -95,7 +95,7 @@ namespace osmium {
             return static_cast<int32_t>(std::round(c * coordinate_precision));
         }
 
-        static OSMIUM_CONSTEXPR double fix_to_double(const int32_t c) noexcept {
+        static constexpr double fix_to_double(const int32_t c) noexcept {
             return static_cast<double>(c) / coordinate_precision;
         }
 
@@ -238,11 +238,11 @@ namespace osmium {
     /**
      * Locations are equal if both coordinates are equal.
      */
-    inline OSMIUM_CONSTEXPR bool operator==(const Location& lhs, const Location& rhs) noexcept {
+    inline constexpr bool operator==(const Location& lhs, const Location& rhs) noexcept {
         return lhs.x() == rhs.x() && lhs.y() == rhs.y();
     }
 
-    inline OSMIUM_CONSTEXPR bool operator!=(const Location& lhs, const Location& rhs) noexcept {
+    inline constexpr bool operator!=(const Location& lhs, const Location& rhs) noexcept {
         return ! (lhs == rhs);
     }
 
@@ -251,19 +251,19 @@ namespace osmium {
      * the y coordinate. If either of the locations is
      * undefined the result is undefined.
      */
-    inline OSMIUM_CONSTEXPR bool operator<(const Location& lhs, const Location& rhs) noexcept {
+    inline constexpr bool operator<(const Location& lhs, const Location& rhs) noexcept {
         return (lhs.x() == rhs.x() && lhs.y() < rhs.y()) || lhs.x() < rhs.x();
     }
 
-    inline OSMIUM_CONSTEXPR bool operator>(const Location& lhs, const Location& rhs) noexcept {
+    inline constexpr bool operator>(const Location& lhs, const Location& rhs) noexcept {
         return rhs < lhs;
     }
 
-    inline OSMIUM_CONSTEXPR bool operator<=(const Location& lhs, const Location& rhs) noexcept {
+    inline constexpr bool operator<=(const Location& lhs, const Location& rhs) noexcept {
         return ! (rhs < lhs);
     }
 
-    inline OSMIUM_CONSTEXPR bool operator>=(const Location& lhs, const Location& rhs) noexcept {
+    inline constexpr bool operator>=(const Location& lhs, const Location& rhs) noexcept {
         return ! (lhs < rhs);
     }
 
diff --git a/include/osmium/osm/node.hpp b/include/osmium/osm/node.hpp
index e9facef..1ff7d1c 100644
--- a/include/osmium/osm/node.hpp
+++ b/include/osmium/osm/node.hpp
@@ -42,7 +42,7 @@ namespace osmium {
 
     namespace builder {
         template <typename T> class ObjectBuilder;
-    }
+    } // namespace builder
 
     class Node : public OSMObject {
 
diff --git a/include/osmium/osm/node_ref.hpp b/include/osmium/osm/node_ref.hpp
index def63b2..e1c9c12 100644
--- a/include/osmium/osm/node_ref.hpp
+++ b/include/osmium/osm/node_ref.hpp
@@ -54,7 +54,7 @@ namespace osmium {
 
     public:
 
-        NodeRef(const osmium::object_id_type ref = 0, const osmium::Location& location = Location()) noexcept :
+        constexpr NodeRef(const osmium::object_id_type ref = 0, const osmium::Location& location = Location()) noexcept :
             m_ref(ref),
             m_location(location) {
         }
@@ -62,7 +62,7 @@ namespace osmium {
         /**
          * Get reference ID of this NodeRef.
          */
-        osmium::object_id_type ref() const noexcept {
+        constexpr osmium::object_id_type ref() const noexcept {
             return m_ref;
         }
 
@@ -83,7 +83,7 @@ namespace osmium {
         /**
          * Get location of this NodeRef.
          */
-        osmium::Location location() const noexcept {
+        constexpr osmium::Location location() const noexcept {
             return m_location;
         }
 
@@ -108,14 +108,14 @@ namespace osmium {
         /**
          * Get internal x value of the location in this NodeRef.
          */
-        int32_t x() const noexcept {
+        constexpr int32_t x() const noexcept {
             return m_location.x();
         }
 
         /**
          * Get internal y value of the location in this NodeRef.
          */
-        int32_t y() const noexcept {
+        constexpr int32_t y() const noexcept {
             return m_location.y();
         }
 
@@ -144,7 +144,7 @@ namespace osmium {
     /**
      * Compare two NodeRefs. They are equal if they reference the same Node ID.
      */
-    inline bool operator==(const NodeRef& lhs, const NodeRef& rhs) noexcept {
+    inline constexpr bool operator==(const NodeRef& lhs, const NodeRef& rhs) noexcept {
         return lhs.ref() == rhs.ref();
     }
 
@@ -152,7 +152,7 @@ namespace osmium {
      * Compare two NodeRefs. They are not equal if they reference different
      * Node IDs.
      */
-    inline bool operator!=(const NodeRef& lhs, const NodeRef& rhs) noexcept {
+    inline constexpr bool operator!=(const NodeRef& lhs, const NodeRef& rhs) noexcept {
         return ! (lhs == rhs);
     }
 
@@ -160,7 +160,7 @@ namespace osmium {
      * Compare two NodeRefs. NodeRefs are ordered according to the Node ID
      * they reference.
      */
-    inline bool operator<(const NodeRef& lhs, const NodeRef& rhs) noexcept {
+    inline constexpr bool operator<(const NodeRef& lhs, const NodeRef& rhs) noexcept {
         return lhs.ref() < rhs.ref();
     }
 
@@ -168,7 +168,7 @@ namespace osmium {
      * Compare two NodeRefs. NodeRefs are ordered according to the Node ID
      * they reference.
      */
-    inline bool operator>(const NodeRef& lhs, const NodeRef& rhs) noexcept {
+    inline constexpr bool operator>(const NodeRef& lhs, const NodeRef& rhs) noexcept {
         return rhs < lhs;
     }
 
@@ -176,7 +176,7 @@ namespace osmium {
      * Compare two NodeRefs. NodeRefs are ordered according to the Node ID
      * they reference.
      */
-    inline bool operator<=(const NodeRef& lhs, const NodeRef& rhs) noexcept {
+    inline constexpr bool operator<=(const NodeRef& lhs, const NodeRef& rhs) noexcept {
         return ! (rhs < lhs);
     }
 
@@ -184,7 +184,7 @@ namespace osmium {
      * Compare two NodeRefs. NodeRefs are ordered according to the Node ID
      * they reference.
      */
-    inline bool operator>=(const NodeRef& lhs, const NodeRef& rhs) noexcept {
+    inline constexpr bool operator>=(const NodeRef& lhs, const NodeRef& rhs) noexcept {
         return ! (lhs < rhs);
     }
 
@@ -201,7 +201,7 @@ namespace osmium {
      */
     struct location_equal {
 
-        bool operator()(const NodeRef& lhs, const NodeRef& rhs) const noexcept {
+        constexpr bool operator()(const NodeRef& lhs, const NodeRef& rhs) const noexcept {
             return lhs.location() == rhs.location();
         }
 
@@ -216,7 +216,7 @@ namespace osmium {
      */
     struct location_less {
 
-        bool operator()(const NodeRef& lhs, const NodeRef& rhs) const noexcept {
+        constexpr bool operator()(const NodeRef& lhs, const NodeRef& rhs) const noexcept {
             return lhs.location() < rhs.location();
         }
 
diff --git a/include/osmium/osm/node_ref_list.hpp b/include/osmium/osm/node_ref_list.hpp
index e46a66d..f990b88 100644
--- a/include/osmium/osm/node_ref_list.hpp
+++ b/include/osmium/osm/node_ref_list.hpp
@@ -51,7 +51,7 @@ namespace osmium {
 
     public:
 
-        NodeRefList(osmium::item_type itemtype) noexcept :
+        explicit NodeRefList(osmium::item_type itemtype) noexcept :
             osmium::memory::Item(sizeof(NodeRefList), itemtype) {
         }
 
diff --git a/include/osmium/osm/relation.hpp b/include/osmium/osm/relation.hpp
index 1a8b686..eec5119 100644
--- a/include/osmium/osm/relation.hpp
+++ b/include/osmium/osm/relation.hpp
@@ -49,7 +49,7 @@ namespace osmium {
     namespace builder {
         template <typename> class ObjectBuilder;
         class RelationMemberListBuilder;
-    }
+    } // namespace builder
 
     class RelationMember : public osmium::memory::detail::ItemHelper {
 
@@ -80,17 +80,15 @@ namespace osmium {
         unsigned char* next() {
             if (full_member()) {
                 return endpos() + reinterpret_cast<osmium::memory::Item*>(endpos())->byte_size();
-            } else {
-                return endpos();
             }
+            return endpos();
         }
 
         unsigned const char* next() const {
             if (full_member()) {
                 return endpos() + reinterpret_cast<const osmium::memory::Item*>(endpos())->byte_size();
-            } else {
-                return endpos();
             }
+            return endpos();
         }
 
         void set_role_size(string_size_type size) noexcept {
diff --git a/include/osmium/osm/segment.hpp b/include/osmium/osm/segment.hpp
index f3a82c9..fe43102 100644
--- a/include/osmium/osm/segment.hpp
+++ b/include/osmium/osm/segment.hpp
@@ -65,12 +65,12 @@ namespace osmium {
         ~Segment() = default;
 
         /// Return first Location of Segment.
-        OSMIUM_CONSTEXPR osmium::Location first() const noexcept {
+        constexpr osmium::Location first() const noexcept {
             return m_first;
         }
 
         /// Return second Location of Segment.
-        OSMIUM_CONSTEXPR osmium::Location second() const noexcept {
+        constexpr osmium::Location second() const noexcept {
             return m_second;
         }
 
@@ -84,11 +84,11 @@ namespace osmium {
     }; // class Segment
 
     /// Segments are equal if both their locations are equal
-    inline OSMIUM_CONSTEXPR bool operator==(const Segment& lhs, const Segment& rhs) noexcept {
+    inline constexpr bool operator==(const Segment& lhs, const Segment& rhs) noexcept {
         return lhs.first() == rhs.first() && lhs.second() == rhs.second();
     }
 
-    inline OSMIUM_CONSTEXPR bool operator!=(const Segment& lhs, const Segment& rhs) noexcept {
+    inline constexpr bool operator!=(const Segment& lhs, const Segment& rhs) noexcept {
         return ! (lhs == rhs);
     }
 
diff --git a/include/osmium/osm/tag.hpp b/include/osmium/osm/tag.hpp
index 30e670d..4eba221 100644
--- a/include/osmium/osm/tag.hpp
+++ b/include/osmium/osm/tag.hpp
@@ -122,9 +122,8 @@ namespace osmium {
             });
             if (result == cend()) {
                 return default_value;
-            } else {
-                return result->value();
             }
+            return result->value();
         }
 
         const char* operator[](const char* key) const noexcept {
diff --git a/include/osmium/osm/timestamp.hpp b/include/osmium/osm/timestamp.hpp
index 9de727f..651b43f 100644
--- a/include/osmium/osm/timestamp.hpp
+++ b/include/osmium/osm/timestamp.hpp
@@ -47,7 +47,10 @@ namespace osmium {
 
     /**
      * A timestamp. Internal representation is an unsigned 32bit integer
-     * holding seconds since epoch, so this will overflow in 2038.
+     * holding seconds since epoch (1970-01-01T00:00:00Z), so this will
+     * overflow in 2106. We can use an unsigned integer here, because the
+     * OpenStreetMap project was started long after 1970, so there will
+     * never be dates before that.
      */
     class Timestamp {
 
@@ -73,14 +76,17 @@ namespace osmium {
         }
 
         /**
-         * Construct a Timestamp from a time_t containing the seconds since
-         * the epoch.
+         * Construct a Timestamp from any integer type containing the seconds
+         * since the epoch. This will not check for overruns, you have to
+         * make sure the value fits into a uint32_t which is used internally
+         * in the Timestamp.
          *
          * The constructor is not declared "explicit" so that conversions
          * like @code node.set_timestamp(123); @endcode work.
          */
-        constexpr Timestamp(time_t timestamp) noexcept :
-            m_timestamp(static_cast<uint32_t>(timestamp)) {
+        template <typename T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
+        constexpr Timestamp(T timestamp) noexcept :
+            m_timestamp(uint32_t(timestamp)) {
         }
 
         /**
@@ -131,19 +137,33 @@ namespace osmium {
             return m_timestamp != 0;
         }
 
-        /// Explicit conversion into time_t.
-        constexpr time_t seconds_since_epoch() const noexcept {
-            return static_cast<time_t>(m_timestamp);
+        /// Explicit conversion into bool.
+        explicit constexpr operator bool() const noexcept {
+            return m_timestamp != 0;
         }
 
-        /// Implicit conversion into time_t.
-        constexpr operator time_t() const noexcept {
-            return static_cast<time_t>(m_timestamp);
+        /// Explicit conversion into time_t.
+        constexpr time_t seconds_since_epoch() const noexcept {
+            return time_t(m_timestamp);
         }
 
         /// Explicit conversion into uint32_t.
         explicit constexpr operator uint32_t() const noexcept {
-            return m_timestamp;
+            return uint32_t(m_timestamp);
+        }
+
+        /// Explicit conversion into uint64_t.
+        explicit constexpr operator uint64_t() const noexcept {
+            return uint64_t(m_timestamp);
+        }
+
+        /**
+         * Implicit conversion into time_t.
+         *
+         * @deprecated You should call seconds_since_epoch() explicitly instead.
+         */
+        OSMIUM_DEPRECATED constexpr operator time_t() const noexcept {
+            return static_cast<time_t>(m_timestamp);
         }
 
         template <typename T>
@@ -190,7 +210,7 @@ namespace osmium {
      * A special Timestamp guaranteed to be ordered before any other valid
      * Timestamp.
      */
-    inline OSMIUM_CONSTEXPR Timestamp start_of_time() noexcept {
+    inline constexpr Timestamp start_of_time() noexcept {
         return Timestamp(1);
     }
 
@@ -198,7 +218,7 @@ namespace osmium {
      * A special Timestamp guaranteed to be ordered after any other valid
      * Timestamp.
      */
-    inline OSMIUM_CONSTEXPR Timestamp end_of_time() noexcept {
+    inline constexpr Timestamp end_of_time() noexcept {
         return Timestamp(std::numeric_limits<uint32_t>::max());
     }
 
@@ -208,6 +228,30 @@ namespace osmium {
         return out;
     }
 
+    inline bool operator==(const Timestamp& lhs, const Timestamp& rhs) noexcept {
+        return uint32_t(lhs) == uint32_t(rhs);
+    }
+
+    inline bool operator!=(const Timestamp& lhs, const Timestamp& rhs) noexcept {
+        return !(lhs == rhs);
+    }
+
+    inline bool operator<(const Timestamp& lhs, const Timestamp& rhs) noexcept {
+        return uint32_t(lhs) < uint32_t(rhs);
+    }
+
+    inline bool operator>(const Timestamp& lhs, const Timestamp& rhs) noexcept {
+        return rhs < lhs;
+    }
+
+    inline bool operator<=(const Timestamp& lhs, const Timestamp& rhs) noexcept {
+        return ! (rhs < lhs);
+    }
+
+    inline bool operator>=(const Timestamp& lhs, const Timestamp& rhs) noexcept {
+        return ! (lhs < rhs);
+    }
+
     template <>
     inline osmium::Timestamp min_op_start_value<osmium::Timestamp>() {
         return end_of_time();
diff --git a/include/osmium/osm/way.hpp b/include/osmium/osm/way.hpp
index 89380e4..90cde8c 100644
--- a/include/osmium/osm/way.hpp
+++ b/include/osmium/osm/way.hpp
@@ -44,7 +44,7 @@ namespace osmium {
 
     namespace builder {
         template <typename T> class ObjectBuilder;
-    }
+    } // namespace builder
 
     /**
      * List of node references (id and location) in a way.
diff --git a/include/osmium/thread/function_wrapper.hpp b/include/osmium/thread/function_wrapper.hpp
index 95b85d6..2fc0b7e 100644
--- a/include/osmium/thread/function_wrapper.hpp
+++ b/include/osmium/thread/function_wrapper.hpp
@@ -63,7 +63,7 @@ namespace osmium {
 
                 F m_functor;
 
-                impl_type(F&& functor) :
+                explicit impl_type(F&& functor) :
                     m_functor(std::forward<F>(functor)) {
                 }
 
diff --git a/include/osmium/thread/pool.hpp b/include/osmium/thread/pool.hpp
index dd1023b..f7b4f40 100644
--- a/include/osmium/thread/pool.hpp
+++ b/include/osmium/thread/pool.hpp
@@ -54,6 +54,32 @@ namespace osmium {
      */
     namespace thread {
 
+        namespace detail {
+
+            // Maximum number of allowed pool threads (just to keep the user
+            // from setting something silly).
+            constexpr const int max_pool_threads = 256;
+
+            inline int get_pool_size(int num_threads, int user_setting, unsigned hardware_concurrency) {
+                if (num_threads == 0) {
+                    num_threads = user_setting ? user_setting : -2;
+                }
+
+                if (num_threads < 0) {
+                    num_threads += hardware_concurrency;
+                }
+
+                if (num_threads < 1) {
+                    num_threads = 1;
+                } else if (num_threads > max_pool_threads) {
+                    num_threads = max_pool_threads;
+                }
+
+                return num_threads;
+            }
+
+        } // namespace detail
+
         /**
          *  Thread pool.
          */
@@ -119,15 +145,7 @@ namespace osmium {
                 m_work_queue(max_queue_size, "work"),
                 m_threads(),
                 m_joiner(m_threads),
-                m_num_threads(num_threads) {
-
-                if (m_num_threads == 0) {
-                    m_num_threads = osmium::config::get_pool_threads();
-                }
-
-                if (m_num_threads <= 0) {
-                    m_num_threads = std::max(1, static_cast<int>(std::thread::hardware_concurrency()) + m_num_threads);
-                }
+                m_num_threads(detail::get_pool_size(num_threads, osmium::config::get_pool_threads(), std::thread::hardware_concurrency())) {
 
                 try {
                     for (int i = 0; i < m_num_threads; ++i) {
diff --git a/include/osmium/thread/queue.hpp b/include/osmium/thread/queue.hpp
index 2837a6e..65b1847 100644
--- a/include/osmium/thread/queue.hpp
+++ b/include/osmium/thread/queue.hpp
@@ -92,7 +92,7 @@ namespace osmium {
              *                 0 for an unlimited size.
              * @param name Optional name for this queue. (Used for debugging.)
              */
-            Queue(size_t max_size = 0, const std::string& name = "") :
+            explicit Queue(size_t max_size = 0, const std::string& name = "") :
                 m_max_size(max_size),
                 m_name(name),
                 m_mutex(),
diff --git a/include/osmium/thread/util.hpp b/include/osmium/thread/util.hpp
index 00de0d8..a20e618 100644
--- a/include/osmium/thread/util.hpp
+++ b/include/osmium/thread/util.hpp
@@ -91,7 +91,7 @@ namespace osmium {
             }
 
             template <typename TFunction, typename... TArgs>
-            thread_handler(TFunction&& f, TArgs&&... args) :
+            explicit thread_handler(TFunction&& f, TArgs&&... args) :
                 m_thread(std::forward<TFunction>(f), std::forward<TArgs>(args)...) {
             }
 
diff --git a/include/osmium/util/compatibility.hpp b/include/osmium/util/compatibility.hpp
index 23753ce..27adca7 100644
--- a/include/osmium/util/compatibility.hpp
+++ b/include/osmium/util/compatibility.hpp
@@ -34,13 +34,10 @@ DEALINGS IN THE SOFTWARE.
 */
 
 // Workarounds for MSVC which doesn't support
-// * constexpr in all cases yet
 // * [[noreturn]]
 #ifdef _MSC_VER
-# define OSMIUM_CONSTEXPR
 # define OSMIUM_NORETURN __declspec(noreturn)
 #else
-# define OSMIUM_CONSTEXPR constexpr
 # define OSMIUM_NORETURN [[noreturn]]
 #endif
 
diff --git a/include/osmium/util/config.hpp b/include/osmium/util/config.hpp
index 3285eed..e31cd6a 100644
--- a/include/osmium/util/config.hpp
+++ b/include/osmium/util/config.hpp
@@ -49,7 +49,7 @@ namespace osmium {
             if (env) {
                 return std::atoi(env);
             }
-            return -2;
+            return 0;
         }
 
         inline bool use_pool_threads_for_pbf_parsing() {
diff --git a/include/osmium/util/delta.hpp b/include/osmium/util/delta.hpp
index cdf3674..558a1d4 100644
--- a/include/osmium/util/delta.hpp
+++ b/include/osmium/util/delta.hpp
@@ -62,7 +62,7 @@ namespace osmium {
             using value_type = TValue;
             using delta_type = TDelta;
 
-            DeltaEncode(TValue value = 0) :
+            explicit DeltaEncode(TValue value = 0) :
                 m_value(value) {
             }
 
diff --git a/include/osmium/util/double.hpp b/include/osmium/util/double.hpp
index 85a2508..e070139 100644
--- a/include/osmium/util/double.hpp
+++ b/include/osmium/util/double.hpp
@@ -68,8 +68,12 @@ namespace osmium {
 #endif
             assert(len > 0 && len < max_double_length);
 
-            while (buffer[len-1] == '0') --len;
-            if (buffer[len-1] == '.') --len;
+            while (buffer[len-1] == '0') {
+                --len;
+            }
+            if (buffer[len-1] == '.') {
+                --len;
+            }
 
             return std::copy_n(buffer, len, iterator);
         }
diff --git a/include/osmium/util/memory_mapping.hpp b/include/osmium/util/memory_mapping.hpp
index 48da13a..b187c3c 100644
--- a/include/osmium/util/memory_mapping.hpp
+++ b/include/osmium/util/memory_mapping.hpp
@@ -248,7 +248,7 @@ private:
              * In a boolean context a MemoryMapping is true when it is a valid
              * existing mapping.
              */
-            operator bool() const noexcept {
+            explicit operator bool() const noexcept {
                 return is_valid();
             }
 
@@ -420,7 +420,7 @@ private:
              * In a boolean context a TypedMemoryMapping is true when it is
              * a valid existing mapping.
              */
-            operator bool() const noexcept {
+            explicit operator bool() const noexcept {
                 return !!m_mapping;
             }
 
diff --git a/include/osmium/visitor.hpp b/include/osmium/visitor.hpp
index 48ce45d..c76eb17 100644
--- a/include/osmium/visitor.hpp
+++ b/include/osmium/visitor.hpp
@@ -46,7 +46,7 @@ namespace osmium {
 
     namespace memory {
         class Item;
-    }
+    } // namespace memory
 
     namespace detail {
 
diff --git a/include/protozero/byteswap.hpp b/include/protozero/byteswap.hpp
index 29c312a..a018c1c 100644
--- a/include/protozero/byteswap.hpp
+++ b/include/protozero/byteswap.hpp
@@ -19,6 +19,8 @@ documentation.
 #include <cstdint>
 #include <cassert>
 
+#include <protozero/config.hpp>
+
 namespace protozero {
 
 /**
@@ -35,9 +37,9 @@ inline void byteswap(const char* /*data*/, char* /*result*/) {
  */
 template <>
 inline void byteswap<4>(const char* data, char* result) {
-# if defined(__GNUC__) || defined(__clang__)
+#ifdef PROTOZERO_USE_BUILTIN_BSWAP
     *reinterpret_cast<uint32_t*>(result) = __builtin_bswap32(*reinterpret_cast<const uint32_t*>(data));
-# else
+#else
     result[3] = data[0];
     result[2] = data[1];
     result[1] = data[2];
@@ -50,9 +52,9 @@ inline void byteswap<4>(const char* data, char* result) {
  */
 template <>
 inline void byteswap<8>(const char* data, char* result) {
-# if defined(__GNUC__) || defined(__clang__)
+#ifdef PROTOZERO_USE_BUILTIN_BSWAP
     *reinterpret_cast<uint64_t*>(result) = __builtin_bswap64(*reinterpret_cast<const uint64_t*>(data));
-# else
+#else
     result[7] = data[0];
     result[6] = data[1];
     result[5] = data[2];
diff --git a/include/protozero/config.hpp b/include/protozero/config.hpp
new file mode 100644
index 0000000..4086994
--- /dev/null
+++ b/include/protozero/config.hpp
@@ -0,0 +1,57 @@
+#ifndef PROTOZERO_CONFIG_HPP
+#define PROTOZERO_CONFIG_HPP
+
+/*****************************************************************************
+
+protozero - Minimalistic protocol buffer decoder and encoder in C++.
+
+This file is from https://github.com/mapbox/protozero where you can find more
+documentation.
+
+*****************************************************************************/
+
+#include <cassert>
+
+/**
+ * @file config.hpp
+ *
+ * @brief Contains macro checks for different configurations.
+ */
+
+#define PROTOZERO_LITTLE_ENDIAN 1234
+#define PROTOZERO_BIG_ENDIAN    4321
+
+// Find out which byte order the machine has.
+#if defined(__BYTE_ORDER)
+# if (__BYTE_ORDER == __LITTLE_ENDIAN)
+#  define PROTOZERO_BYTE_ORDER PROTOZERO_LITTLE_ENDIAN
+# endif
+# if (__BYTE_ORDER == __BIG_ENDIAN)
+#  define PROTOZERO_BYTE_ORDER PROTOZERO_BIG_ENDIAN
+# endif
+#else
+// This probably isn't a very good default, but might do until we figure
+// out something better.
+# define PROTOZERO_BYTE_ORDER PROTOZERO_LITTLE_ENDIAN
+#endif
+
+// On some ARM machines and depending on compiler settings access to unaligned
+// floating point values will result in a SIGBUS. Do not use the bare pointers
+// in this case.
+#if PROTOZERO_BYTE_ORDER == PROTOZERO_LITTLE_ENDIAN
+# if !defined(__arm__) && !defined(_M_ARM)
+#  define PROTOZERO_USE_BARE_POINTER_FOR_PACKED_FIXED
+# endif
+#endif
+
+// Check whether __builtin_bswap is available
+#if defined(__GNUC__) || defined(__clang__)
+# define PROTOZERO_USE_BUILTIN_BSWAP
+#endif
+
+// Wrapper for assert() used for testing
+#ifndef protozero_assert
+# define protozero_assert(x) assert(x)
+#endif
+
+#endif // PROTOZERO_CONFIG_HPP
diff --git a/include/protozero/pbf_reader.hpp b/include/protozero/pbf_reader.hpp
index ac3220c..aced901 100644
--- a/include/protozero/pbf_reader.hpp
+++ b/include/protozero/pbf_reader.hpp
@@ -16,7 +16,6 @@ documentation.
  * @brief Contains the pbf_reader class.
  */
 
-#include <cassert>
 #include <cstddef>
 #include <cstdint>
 #include <cstring>
@@ -24,19 +23,15 @@ documentation.
 #include <string>
 #include <utility>
 
-#include <protozero/pbf_types.hpp>
+#include <protozero/config.hpp>
 #include <protozero/exception.hpp>
+#include <protozero/pbf_types.hpp>
 #include <protozero/varint.hpp>
 
-#if __BYTE_ORDER != __LITTLE_ENDIAN
+#if PROTOZERO_BYTE_ORDER != PROTOZERO_LITTLE_ENDIAN
 # include <protozero/byteswap.hpp>
 #endif
 
-/// Wrapper for assert() used for testing
-#ifndef protozero_assert
-# define protozero_assert(x) assert(x)
-#endif
-
 namespace protozero {
 
 /**
@@ -77,19 +72,27 @@ class pbf_reader {
     // The tag of the current field.
     pbf_tag_type m_tag = 0;
 
+    // Copy N bytes from src to dest on little endian machines, on big endian
+    // swap the bytes in the process.
+    template <int N>
+    static void copy_or_byteswap(const char* src, void* dest) noexcept {
+#if PROTOZERO_BYTE_ORDER == PROTOZERO_LITTLE_ENDIAN
+        memcpy(dest, src, N);
+#else
+        byteswap<N>(src, reinterpret_cast<char*>(dest));
+#endif
+    }
+
     template <typename T>
     inline T get_fixed() {
         T result;
         skip_bytes(sizeof(T));
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-        memcpy(&result, m_data - sizeof(T), sizeof(T));
-#else
-        byteswap<sizeof(T)>(m_data - sizeof(T), reinterpret_cast<char*>(&result));
-#endif
+        copy_or_byteswap<sizeof(T)>(m_data - sizeof(T), &result);
         return result;
     }
 
-#if __BYTE_ORDER == __LITTLE_ENDIAN
+#ifdef PROTOZERO_USE_BARE_POINTER_FOR_PACKED_FIXED
+
     template <typename T>
     inline std::pair<const T*, const T*> packed_fixed() {
         protozero_assert(tag() != 0 && "call next() before accessing field value");
@@ -128,7 +131,7 @@ class pbf_reader {
 
         T operator*() {
             T result;
-            byteswap<sizeof(T)>(m_data, reinterpret_cast<char*>(&result));
+            copy_or_byteswap<sizeof(T)>(m_data , &result);
             return result;
         }
 
@@ -161,6 +164,7 @@ class pbf_reader {
         return std::make_pair(const_fixed_iterator<T>(m_data-len, m_data),
                               const_fixed_iterator<T>(m_data, m_data));
     }
+
 #endif
 
     template <typename T> inline T get_varint();
diff --git a/include/protozero/pbf_writer.hpp b/include/protozero/pbf_writer.hpp
index e4e02de..2b78cb8 100644
--- a/include/protozero/pbf_writer.hpp
+++ b/include/protozero/pbf_writer.hpp
@@ -16,7 +16,6 @@ documentation.
  * @brief Contains the pbf_writer class.
  */
 
-#include <cassert>
 #include <cstddef>
 #include <cstdint>
 #include <cstring>
@@ -24,18 +23,14 @@ documentation.
 #include <limits>
 #include <string>
 
+#include <protozero/config.hpp>
 #include <protozero/pbf_types.hpp>
 #include <protozero/varint.hpp>
 
-#if __BYTE_ORDER != __LITTLE_ENDIAN
+#if PROTOZERO_BYTE_ORDER != PROTOZERO_LITTLE_ENDIAN
 # include <protozero/byteswap.hpp>
 #endif
 
-/// Wrapper for assert() used for testing
-#ifndef protozero_assert
-# define protozero_assert(x) assert(x)
-#endif
-
 namespace protozero {
 
 /**
@@ -71,7 +66,7 @@ class pbf_writer {
     inline void add_fixed(T value) {
         protozero_assert(m_pos == 0 && "you can't add fields to a parent pbf_writer if there is an existing pbf_writer for a submessage");
         protozero_assert(m_data);
-#if __BYTE_ORDER == __LITTLE_ENDIAN
+#if PROTOZERO_BYTE_ORDER == PROTOZERO_LITTLE_ENDIAN
         m_data->append(reinterpret_cast<const char*>(&value), sizeof(T));
 #else
         auto size = m_data->size();
@@ -380,7 +375,7 @@ public:
     inline void add_bytes(pbf_tag_type tag, const char* value, size_t size) {
         protozero_assert(m_pos == 0 && "you can't add fields to a parent pbf_writer if there is an existing pbf_writer for a submessage");
         protozero_assert(m_data);
-        assert(size <= std::numeric_limits<pbf_length_type>::max());
+        protozero_assert(size <= std::numeric_limits<pbf_length_type>::max());
         add_length_varint(tag, pbf_length_type(size));
         m_data->append(value, size);
     }
diff --git a/include/protozero/version.hpp b/include/protozero/version.hpp
index f11d303..4f129ac 100644
--- a/include/protozero/version.hpp
+++ b/include/protozero/version.hpp
@@ -12,11 +12,11 @@ documentation.
 
 #define PROTOZERO_VERSION_MAJOR 1
 #define PROTOZERO_VERSION_MINOR 2
-#define PROTOZERO_VERSION_PATCH 2
+#define PROTOZERO_VERSION_PATCH 3
 
 #define PROTOZERO_VERSION_CODE (PROTOZERO_VERSION_MAJOR * 10000 + PROTOZERO_VERSION_MINOR * 100 + PROTOZERO_VERSION_PATCH)
 
-#define PROTOZERO_VERSION_STRING "1.2.2"
+#define PROTOZERO_VERSION_STRING "1.2.3"
 
 
 #endif // PROTOZERO_VERSION_HPP
diff --git a/test/data-tests/CMakeLists.txt b/test/data-tests/CMakeLists.txt
index 89aead9..a36c31c 100644
--- a/test/data-tests/CMakeLists.txt
+++ b/test/data-tests/CMakeLists.txt
@@ -88,11 +88,11 @@ set_tests_properties(testdata-overview PROPERTIES
 #
 #-----------------------------------------------------------------------------
 
-find_package(Ruby 1.9)
+find_program(RUBY ruby)
 find_package(Gem COMPONENTS json)
 find_program(SPATIALITE spatialite)
 
-if(RUBY_FOUND AND GEM_json_FOUND AND SPATIALITE)
+if(RUBY AND GEM_json_FOUND AND SPATIALITE)
     add_executable(testdata-multipolygon testdata-multipolygon.cpp)
     target_link_libraries(testdata-multipolygon
                         ${OSMIUM_XML_LIBRARIES}
@@ -102,7 +102,7 @@ if(RUBY_FOUND AND GEM_json_FOUND AND SPATIALITE)
     add_test(NAME testdata-multipolygon
             COMMAND ${CMAKE_COMMAND}
                 -D OSM_TESTDATA=${OSM_TESTDATA}
-                -D RUBY=${RUBY_EXECUTABLE}
+                -D RUBY=${RUBY}
                 -P ${CMAKE_CURRENT_SOURCE_DIR}/run-testdata-multipolygon.cmake)
 
     set_tests_properties(testdata-multipolygon PROPERTIES LABELS "data;slow")
diff --git a/test/data-tests/testdata-multipolygon.cpp b/test/data-tests/testdata-multipolygon.cpp
index e0d6583..cf4fc52 100644
--- a/test/data-tests/testdata-multipolygon.cpp
+++ b/test/data-tests/testdata-multipolygon.cpp
@@ -56,7 +56,7 @@ class TestHandler : public osmium::handler::Handler {
 
 public:
 
-    TestHandler(gdalcpp::Dataset& dataset) :
+    explicit TestHandler(gdalcpp::Dataset& dataset) :
         m_layer_point(dataset, "points", wkbPoint),
         m_layer_lines(dataset, "lines", wkbLineString),
         m_layer_mpoly(dataset, "multipolygons", wkbMultiPolygon),
@@ -152,7 +152,7 @@ int main(int argc, char* argv[]) {
     std::string output_filename("multipolygon.db");
 
     CPLSetConfigOption("OGR_SQLITE_SYNCHRONOUS", "FALSE");
-    gdalcpp::Dataset dataset(output_format, output_filename, "", { "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);
diff --git a/test/data-tests/testdata-overview.cpp b/test/data-tests/testdata-overview.cpp
index 2c88ece..43d672d 100644
--- a/test/data-tests/testdata-overview.cpp
+++ b/test/data-tests/testdata-overview.cpp
@@ -25,7 +25,7 @@ class TestOverviewHandler : public osmium::handler::Handler {
 
 public:
 
-    TestOverviewHandler(gdalcpp::Dataset& dataset) :
+    explicit TestOverviewHandler(gdalcpp::Dataset& dataset) :
         m_layer_nodes(dataset, "nodes", wkbPoint),
         m_layer_labels(dataset, "labels", wkbPoint),
         m_layer_ways(dataset, "ways", wkbLineString) {
@@ -85,7 +85,7 @@ int main(int argc, char* argv[]) {
     ::unlink(output_filename.c_str());
 
     CPLSetConfigOption("OGR_SQLITE_SYNCHRONOUS", "FALSE");
-    gdalcpp::Dataset dataset(output_format, output_filename, "", { "SPATIALITE=TRUE" });
+    gdalcpp::Dataset dataset(output_format, output_filename, gdalcpp::SRS{}, { "SPATIALITE=TRUE" });
 
     osmium::io::Reader reader(input_filename);
 
diff --git a/test/t/area/test_node_ref_segment.cpp b/test/t/area/test_node_ref_segment.cpp
index 3097687..3261c24 100644
--- a/test/t/area/test_node_ref_segment.cpp
+++ b/test/t/area/test_node_ref_segment.cpp
@@ -52,6 +52,20 @@ TEST_CASE("NodeRefSegmentClass") {
         REQUIRE(calculate_intersection(s1, s7) == osmium::Location());
     }
 
+    SECTION("intersection of very long segments") {
+        NodeRefSegment s1({ 1, {90.0, 90.0}}, { 2, {-90.0, -90.0}}, nullptr, nullptr);
+        NodeRefSegment s2({ 1, {-90.0, 90.0}}, { 2, {90.0, -90.0}}, nullptr, nullptr);
+        REQUIRE(calculate_intersection(s1, s2) == osmium::Location(0.0, 0.0));
+
+        NodeRefSegment s3({ 1, {-90.0, -90.0}}, { 2, {90.0, 90.0}}, nullptr, nullptr);
+        NodeRefSegment s4({ 1, {-90.0, 90.0}}, { 2, {90.0, -90.0}}, nullptr, nullptr);
+        REQUIRE(calculate_intersection(s3, s4) == osmium::Location(0.0, 0.0));
+
+        NodeRefSegment s5({ 1, {-90.0000001, -90.0}}, { 2, {90.0, 90.0}}, nullptr, nullptr);
+        NodeRefSegment s6({ 1, {-90.0, 90.0}}, { 2, {90.0, -90.0}}, nullptr, nullptr);
+        REQUIRE(calculate_intersection(s5, s6) == osmium::Location(0.0, 0.0));
+    }
+
     SECTION("to_left_of") {
         osmium::Location loc { 2.0, 2.0 };
 
diff --git a/test/t/basic/test_node.cpp b/test/t/basic/test_node.cpp
index 750ad39..9f8b181 100644
--- a/test/t/basic/test_node.cpp
+++ b/test/t/basic/test_node.cpp
@@ -37,7 +37,7 @@ SECTION("node_builder") {
     REQUIRE(333 == node.changeset());
     REQUIRE(21 == node.uid());
     REQUIRE(std::string("foo") == node.user());
-    REQUIRE(123 == node.timestamp());
+    REQUIRE(123 == uint32_t(node.timestamp()));
     REQUIRE(osmium::Location(3.5, 4.7) == node.location());
     REQUIRE(2 == node.tags().size());
 
@@ -61,7 +61,7 @@ SECTION("node_default_attributes") {
     REQUIRE(0 == node.changeset());
     REQUIRE(0 == node.uid());
     REQUIRE(std::string("") == node.user());
-    REQUIRE(0 == node.timestamp());
+    REQUIRE(0 == uint32_t(node.timestamp()));
     REQUIRE(osmium::Location() == node.location());
     REQUIRE(0 == node.tags().size());
 }
diff --git a/test/t/basic/test_relation.cpp b/test/t/basic/test_relation.cpp
index 5419d5e..66b201c 100644
--- a/test/t/basic/test_relation.cpp
+++ b/test/t/basic/test_relation.cpp
@@ -36,7 +36,7 @@ TEST_CASE("Build relation") {
     REQUIRE(333 == relation.changeset());
     REQUIRE(21 == relation.uid());
     REQUIRE(std::string("foo") == relation.user());
-    REQUIRE(123 == relation.timestamp());
+    REQUIRE(123 == uint32_t(relation.timestamp()));
     REQUIRE(2 == relation.tags().size());
     REQUIRE(3 == relation.members().size());
 
diff --git a/test/t/basic/test_timestamp.cpp b/test/t/basic/test_timestamp.cpp
index f5c4eba..f80ffcf 100644
--- a/test/t/basic/test_timestamp.cpp
+++ b/test/t/basic/test_timestamp.cpp
@@ -8,21 +8,21 @@ TEST_CASE("Timestamp") {
 
     SECTION("can be default initialized to invalid value") {
         osmium::Timestamp t;
-        REQUIRE(0 == t);
+        REQUIRE(0 == uint32_t(t));
         REQUIRE("" == t.to_iso());
         REQUIRE_FALSE(t.valid());
     }
 
     SECTION("invalid value is zero") {
         osmium::Timestamp t(static_cast<time_t>(0));
-        REQUIRE(0 == t);
+        REQUIRE(0 == uint32_t(t));
         REQUIRE("" == t.to_iso());
         REQUIRE_FALSE(t.valid());
     }
 
     SECTION("can be initialized from time_t") {
         osmium::Timestamp t(static_cast<time_t>(1));
-        REQUIRE(1 == t);
+        REQUIRE(1 == uint32_t(t));
         REQUIRE("1970-01-01T00:00:01Z" == t.to_iso());
         REQUIRE(t.valid());
     }
@@ -44,9 +44,9 @@ TEST_CASE("Timestamp") {
         REQUIRE_THROWS_AS(osmium::Timestamp("x"), std::invalid_argument);
     }
 
-    SECTION("can be implicitly cast to time_t") {
+    SECTION("can be explicitly cast to time_t") {
         osmium::Timestamp t(4242);
-        time_t x = t;
+        time_t x = t.seconds_since_epoch();
         REQUIRE(x == 4242);
     }
 
diff --git a/test/t/basic/test_way.cpp b/test/t/basic/test_way.cpp
index c8f651f..370cd01 100644
--- a/test/t/basic/test_way.cpp
+++ b/test/t/basic/test_way.cpp
@@ -36,7 +36,7 @@ SECTION("way_builder") {
     REQUIRE(333 == way.changeset());
     REQUIRE(21 == way.uid());
     REQUIRE(std::string("foo") == way.user());
-    REQUIRE(123 == way.timestamp());
+    REQUIRE(123 == uint32_t(way.timestamp()));
     REQUIRE(2 == way.tags().size());
     REQUIRE(3 == way.nodes().size());
     REQUIRE(1 == way.nodes()[0].ref());
diff --git a/test/t/buffer/test_buffer_node.cpp b/test/t/buffer/test_buffer_node.cpp
index e985009..ba2431b 100644
--- a/test/t/buffer/test_buffer_node.cpp
+++ b/test/t/buffer/test_buffer_node.cpp
@@ -9,7 +9,7 @@ void check_node_1(osmium::Node& node) {
     REQUIRE(true == node.visible());
     REQUIRE(333 == node.changeset());
     REQUIRE(21 == node.uid());
-    REQUIRE(123 == node.timestamp());
+    REQUIRE(123 == uint32_t(node.timestamp()));
     REQUIRE(osmium::Location(3.5, 4.7) == node.location());
     REQUIRE(std::string("testuser") == node.user());
 
@@ -28,7 +28,7 @@ void check_node_2(osmium::Node& node) {
     REQUIRE(true == node.visible());
     REQUIRE(333 == node.changeset());
     REQUIRE(21 == node.uid());
-    REQUIRE(123 == node.timestamp());
+    REQUIRE(123 == uint32_t(node.timestamp()));
     REQUIRE(osmium::Location(3.5, 4.7) == node.location());
     REQUIRE(std::string("testuser") == node.user());
 
@@ -162,8 +162,38 @@ TEST_CASE("Node in Buffer") {
         REQUIRE(buffer.committed() == buffer2.committed());
         const osmium::Node& node = buffer2.get<osmium::Node>(0);
         REQUIRE(node.id() == 1);
-        REQUIRE(node.timestamp() == 123);
+        REQUIRE(123 == uint32_t(node.timestamp()));
     }
 
+    SECTION("Use back_inserter on buffer") {
+
+        {
+            // add node 1
+            osmium::builder::NodeBuilder node_builder(buffer);
+            osmium::Node& node = node_builder.object();
+            REQUIRE(osmium::item_type::node == node.type());
+
+            node.set_id(1);
+            node.set_version(3);
+            node.set_visible(true);
+            node.set_changeset(333);
+            node.set_uid(21);
+            node.set_timestamp(123);
+            node.set_location(osmium::Location(3.5, 4.7));
+
+            node_builder.add_user("testuser");
+
+            buffer.commit();
+        }
+
+        osmium::memory::Buffer buffer2(buffer_size, osmium::memory::Buffer::auto_grow::yes);
+
+        std::copy(buffer.begin(), buffer.end(), std::back_inserter(buffer2));
+
+        REQUIRE(buffer.committed() == buffer2.committed());
+        const osmium::Node& node = buffer2.get<osmium::Node>(0);
+        REQUIRE(node.id() == 1);
+        REQUIRE(123 == uint32_t(node.timestamp()));
+    }
 }
 
diff --git a/test/t/io/test_reader_with_mock_decompression.cpp b/test/t/io/test_reader_with_mock_decompression.cpp
index 7a88671..566295a 100644
--- a/test/t/io/test_reader_with_mock_decompression.cpp
+++ b/test/t/io/test_reader_with_mock_decompression.cpp
@@ -27,7 +27,7 @@ public:
         }
     }
 
-    ~MockDecompressor() noexcept override final = default;
+    ~MockDecompressor() noexcept final = default;
 
     void add_node(std::string& s, int i) {
         s += "<node id='";
@@ -35,7 +35,7 @@ public:
         s += "' version='1' timestamp='2014-01-01T00:00:00Z' uid='1' user='test' changeset='1' lon='1.02' lat='1.02'/>\n";
     }
 
-    std::string read() override final {
+    std::string read() final {
         std::string buffer;
         ++m_read_count;
 
@@ -63,7 +63,7 @@ public:
         return buffer;
     }
 
-    void close() override final {
+    void close() final {
         if (m_fail_in == "close") {
             throw std::runtime_error("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 02a944b..7c7dcdd 100644
--- a/test/t/io/test_reader_with_mock_parser.cpp
+++ b/test/t/io/test_reader_with_mock_parser.cpp
@@ -41,7 +41,7 @@ public:
         return buffer;
     }
 
-    void run() override final {
+    void run() final {
         osmium::thread::set_thread_name("_osmium_mock_in");
 
         if (m_fail_in == "header") {
diff --git a/test/t/io/test_writer_with_mock_compression.cpp b/test/t/io/test_writer_with_mock_compression.cpp
index fb7e3e4..c2d3bbd 100644
--- a/test/t/io/test_writer_with_mock_compression.cpp
+++ b/test/t/io/test_writer_with_mock_compression.cpp
@@ -23,15 +23,15 @@ public:
         }
     }
 
-    ~MockCompressor() noexcept override final = default;
+    ~MockCompressor() noexcept final = default;
 
-    void write(const std::string&) override final {
+    void write(const std::string&) final {
         if (m_fail_in == "write") {
             throw std::logic_error("write");
         }
     }
 
-    void close() override final {
+    void close() final {
         if (m_fail_in == "close") {
             throw std::logic_error("close");
         }
diff --git a/test/t/io/test_writer_with_mock_encoder.cpp b/test/t/io/test_writer_with_mock_encoder.cpp
index 23cebd9..a43d591 100644
--- a/test/t/io/test_writer_with_mock_encoder.cpp
+++ b/test/t/io/test_writer_with_mock_encoder.cpp
@@ -22,21 +22,21 @@ public:
         m_fail_in(fail_in) {
     }
 
-    void write_header(const osmium::io::Header&) override final {
+    void write_header(const osmium::io::Header&) final {
         if (m_fail_in == "header") {
             throw std::logic_error("header");
         }
         send_to_output_queue(std::string{"header"});
     }
 
-    void write_buffer(osmium::memory::Buffer&&) override final {
+    void write_buffer(osmium::memory::Buffer&&) final {
         if (m_fail_in == "write") {
             throw std::logic_error("write");
         }
         send_to_output_queue(std::string{"write"});
     }
 
-    void write_end() override final {
+    void write_end() final {
         if (m_fail_in == "write_end") {
             throw std::logic_error("write_end");
         }
diff --git a/test/t/thread/test_pool.cpp b/test/t/thread/test_pool.cpp
index 7b6d20d..c1047db 100644
--- a/test/t/thread/test_pool.cpp
+++ b/test/t/thread/test_pool.cpp
@@ -19,6 +19,35 @@ struct test_job_throw {
     }
 };
 
+TEST_CASE("number of threads in pool") {
+
+    // hardcoded setting
+    REQUIRE(osmium::thread::detail::get_pool_size( 1,  0,  2) ==  1);
+    REQUIRE(osmium::thread::detail::get_pool_size( 4,  0,  2) ==  4);
+    REQUIRE(osmium::thread::detail::get_pool_size( 4,  0,  4) ==  4);
+    REQUIRE(osmium::thread::detail::get_pool_size(16,  0,  4) == 16);
+    REQUIRE(osmium::thread::detail::get_pool_size(16,  0, 16) == 16);
+    REQUIRE(osmium::thread::detail::get_pool_size( 8,  4,  2) ==  8);
+    REQUIRE(osmium::thread::detail::get_pool_size( 8, 16,  2) ==  8);
+    REQUIRE(osmium::thread::detail::get_pool_size(-2, 16,  2) ==  1);
+    REQUIRE(osmium::thread::detail::get_pool_size(-2, 16,  8) ==  6);
+
+    // user decides through OSMIUM_POOL_THREADS env variable
+    REQUIRE(osmium::thread::detail::get_pool_size( 0,  0,  2) ==  1);
+    REQUIRE(osmium::thread::detail::get_pool_size( 0, -2,  4) ==  2);
+    REQUIRE(osmium::thread::detail::get_pool_size( 0, -1,  8) ==  7);
+    REQUIRE(osmium::thread::detail::get_pool_size( 0,  0, 16) == 14);
+    REQUIRE(osmium::thread::detail::get_pool_size( 0,  1, 16) ==  1);
+    REQUIRE(osmium::thread::detail::get_pool_size( 0,  2, 16) ==  2);
+    REQUIRE(osmium::thread::detail::get_pool_size( 0,  4, 16) ==  4);
+    REQUIRE(osmium::thread::detail::get_pool_size( 0,  8, 16) ==  8);
+
+    // outliers
+    REQUIRE(osmium::thread::detail::get_pool_size(-100, 0, 16) ==   1);
+    REQUIRE(osmium::thread::detail::get_pool_size(1000, 0, 16) == 256);
+
+}
+
 TEST_CASE("thread") {
 
     auto& pool = osmium::thread::Pool::instance();

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