[libosmium] 01/04: Imported Upstream version 2.5.3

Sebastiaan Couwenberg sebastic at moszumanska.debian.org
Wed Nov 18 21:54:19 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 eec33478f11b5535dcf3587595aa1e3ea2b8bb02
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date:   Wed Nov 18 22:36:47 2015 +0100

    Imported Upstream version 2.5.3
---
 CHANGELOG.md                                   |  21 ++-
 CMakeLists.txt                                 |   2 +-
 include/osmium/area/multipolygon_collector.hpp |  22 ---
 include/osmium/diff_handler.hpp                |   3 +-
 include/osmium/diff_iterator.hpp               |  35 ++--
 include/osmium/diff_visitor.hpp                |   2 +-
 include/osmium/io/output_iterator.hpp          |  13 +-
 include/osmium/memory/buffer.hpp               | 231 +++++++++++++++++++------
 include/osmium/memory/item_iterator.hpp        |  16 +-
 include/osmium/osm/diff_object.hpp             | 140 ++++++++++++---
 include/osmium/osm/item_type.hpp               |   8 +
 include/osmium/osm/node_ref.hpp                |  74 +++++++-
 include/osmium/osm/node_ref_list.hpp           |  29 ++--
 include/osmium/osm/timestamp.hpp               |  66 +++++--
 include/osmium/osm/types_from_string.hpp       |  67 +++++++
 include/osmium/relations/collector.hpp         | 159 +++++++++--------
 include/osmium/util/data_file.hpp              | 194 ---------------------
 include/osmium/util/memory_mapping.hpp         |  25 ++-
 include/osmium/util/options.hpp                |  66 +++++--
 include/osmium/visitor.hpp                     |   7 +-
 test/CMakeLists.txt                            |   1 -
 test/t/basic/test_object_comparisons.cpp       |  44 ++---
 test/t/basic/test_timestamp.cpp                |  17 +-
 test/t/buffer/test_buffer_node.cpp             |  44 ++++-
 test/t/util/test_data_file.cpp                 |  81 ---------
 test/t/util/test_options.cpp                   |  30 +++-
 26 files changed, 813 insertions(+), 584 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 781a04a..70d77bc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,6 +13,24 @@ This project adheres to [Semantic Versioning](http://semver.org/).
 ### Fixed
 
 
+## [2.5.3] - 2015-11-17
+
+### Added
+
+- osmium::make_diff_iterator() helper function.
+
+### Changed
+
+- Deprecated osmium::Buffer::set_full_callback().
+- Removed DataFile class which was never used anywhere.
+- Removed unused and obscure Buffer::value_type typedef.
+
+### Fixed
+
+- Possible overrun in Buffer when using the full-callback.
+- Incorrect swapping of Buffer.
+
+
 ## [2.5.2] - 2015-11-06
 
 # Fixed
@@ -196,7 +214,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
   Doxygen (up to version 1.8.8). This version contains a workaround to fix
   this.
 
-[unreleased]: https://github.com/osmcode/libosmium/compare/v2.5.2...HEAD
+[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
 [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 f28e2aa..fc3e97e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -27,7 +27,7 @@ project(libosmium)
 
 set(LIBOSMIUM_VERSION_MAJOR 2)
 set(LIBOSMIUM_VERSION_MINOR 5)
-set(LIBOSMIUM_VERSION_PATCH 2)
+set(LIBOSMIUM_VERSION_PATCH 3)
 
 set(LIBOSMIUM_VERSION
     "${LIBOSMIUM_VERSION_MAJOR}.${LIBOSMIUM_VERSION_MINOR}.${LIBOSMIUM_VERSION_PATCH}")
diff --git a/include/osmium/area/multipolygon_collector.hpp b/include/osmium/area/multipolygon_collector.hpp
index c4155db..d3ca10f 100644
--- a/include/osmium/area/multipolygon_collector.hpp
+++ b/include/osmium/area/multipolygon_collector.hpp
@@ -177,28 +177,6 @@ namespace osmium {
                 } catch (osmium::invalid_location&) {
                     // XXX ignore
                 }
-
-                // clear member metas
-                for (const auto& member : relation.members()) {
-                    if (member.ref() != 0) {
-                        auto& mmv = this->member_meta(member.type());
-                        auto range = std::equal_range(mmv.begin(), mmv.end(), osmium::relations::MemberMeta(member.ref()));
-                        assert(range.first != range.second);
-
-                        // if this is the last time this object was needed
-                        // then mark it as removed
-                        if (osmium::relations::count_not_removed(range.first, range.second) == 1) {
-                            this->get_member(range.first->buffer_offset()).set_removed(true);
-                        }
-
-                        for (auto it = range.first; it != range.second; ++it) {
-                            if (!it->removed() && relation.id() == this->get_relation(it->relation_pos()).id()) {
-                                it->remove();
-                                break;
-                            }
-                        }
-                    }
-                }
             }
 
             void flush() {
diff --git a/include/osmium/diff_handler.hpp b/include/osmium/diff_handler.hpp
index 4f9b3a1..06d8a93 100644
--- a/include/osmium/diff_handler.hpp
+++ b/include/osmium/diff_handler.hpp
@@ -46,8 +46,7 @@ namespace osmium {
 
         public:
 
-            DiffHandler() {
-            }
+            DiffHandler() = default;
 
             void node(const osmium::DiffNode&) const {
             }
diff --git a/include/osmium/diff_iterator.hpp b/include/osmium/diff_iterator.hpp
index ae80afb..6725fec 100644
--- a/include/osmium/diff_iterator.hpp
+++ b/include/osmium/diff_iterator.hpp
@@ -43,6 +43,11 @@ namespace osmium {
 
     class OSMObject;
 
+    /**
+     * An input iterator wrapping any iterator over OSMObjects. When
+     * dereferenced it will yield DiffObject objects pointing to the
+     * underlying OSMObjects.
+     */
     template <typename TBasicIterator>
     class DiffIterator : public std::iterator<std::input_iterator_tag, const osmium::DiffObject> {
 
@@ -56,7 +61,7 @@ namespace osmium {
 
         mutable osmium::DiffObject m_diff;
 
-        void set_diff() const {
+        void set_diff() const noexcept {
             assert(m_curr != m_end);
 
             bool use_curr_for_prev =                    m_prev->type() != m_curr->type() || m_prev->id() != m_curr->id();
@@ -71,19 +76,14 @@ namespace osmium {
 
     public:
 
-        explicit DiffIterator(TBasicIterator begin, TBasicIterator end) :
+        DiffIterator(TBasicIterator begin, TBasicIterator end) :
             m_prev(begin),
             m_curr(begin),
             m_next(begin == end ? begin : ++begin),
-            m_end(std::move(end)) {
+            m_end(std::move(end)),
+            m_diff() {
         }
 
-        DiffIterator(const DiffIterator&) = default;
-        DiffIterator& operator=(const DiffIterator&) = default;
-
-        DiffIterator(DiffIterator&&) = default;
-        DiffIterator& operator=(DiffIterator&&) = default;
-
         DiffIterator& operator++() {
             m_prev = std::move(m_curr);
             m_curr = m_next;
@@ -101,26 +101,35 @@ namespace osmium {
             return tmp;
         }
 
-        bool operator==(const DiffIterator& rhs) const {
+        bool operator==(const DiffIterator& rhs) const noexcept {
             return m_curr == rhs.m_curr && m_end == rhs.m_end;
         }
 
-        bool operator!=(const DiffIterator& rhs) const {
+        bool operator!=(const DiffIterator& rhs) const noexcept {
             return !(*this == rhs);
         }
 
-        reference operator*() const {
+        reference operator*() const noexcept {
             set_diff();
             return m_diff;
         }
 
-        pointer operator->() const {
+        pointer operator->() const noexcept {
             set_diff();
             return &m_diff;
         }
 
     }; // class DiffIterator
 
+    /**
+     * Create a DiffIterator based on the given iterators.
+     */
+    template <typename TBasicIterator>
+    inline DiffIterator<TBasicIterator> make_diff_iterator(TBasicIterator begin,
+                                                           TBasicIterator end) {
+        return DiffIterator<TBasicIterator>{begin, end};
+    }
+
 } // namespace osmium
 
 #endif // OSMIUM_DIFF_ITERATOR_HPP
diff --git a/include/osmium/diff_visitor.hpp b/include/osmium/diff_visitor.hpp
index e7dc576..ac16a8e 100644
--- a/include/osmium/diff_visitor.hpp
+++ b/include/osmium/diff_visitor.hpp
@@ -70,7 +70,7 @@ namespace osmium {
 
     template <typename TIterator, typename... THandlers>
     inline void apply_diff(TIterator it, TIterator end, THandlers&... handlers) {
-        typedef osmium::DiffIterator<TIterator> diff_iterator;
+        using diff_iterator = osmium::DiffIterator<TIterator>;
 
         diff_iterator dit(it, end);
         diff_iterator dend(end, end);
diff --git a/include/osmium/io/output_iterator.hpp b/include/osmium/io/output_iterator.hpp
index 3d60fe6..1cf1d1d 100644
--- a/include/osmium/io/output_iterator.hpp
+++ b/include/osmium/io/output_iterator.hpp
@@ -62,7 +62,8 @@ namespace osmium {
             }
 
             /**
-             * Warning! Use of buffer size argument on OutputIterator
+             * @deprecated
+             * Use of buffer size argument on OutputIterator
              * constructor is deprecated. Call Writer::set_buffer_size()
              * instead if you want to change the default.
              */
@@ -80,7 +81,8 @@ namespace osmium {
             ~OutputIterator() = default;
 
             /**
-             * Warning! Calling OutputIterator<Writer>::flush() is usually not
+             * @deprecated
+             * Calling OutputIterator<Writer>::flush() is usually not
              * needed any more. Call flush() on the Writer instead if needed.
              */
             OSMIUM_DEPRECATED void flush() {
@@ -116,9 +118,10 @@ namespace osmium {
         }
 
         /**
-         * Warning! Use of buffer size argument on make_output_iterator is
-         * deprecated. Call Writer::set_buffer_size() instead if you want to
-         * change the default.
+         * @deprecated
+         * Use of buffer size argument on make_output_iterator is deprecated.
+         * Call Writer::set_buffer_size() instead if you want to change the
+         * default.
          */
         template <typename TDest>
         OSMIUM_DEPRECATED OutputIterator<TDest> make_output_iterator(TDest& destination, const size_t buffer_size) {
diff --git a/include/osmium/memory/buffer.hpp b/include/osmium/memory/buffer.hpp
index 11a4c97..ce8c587 100644
--- a/include/osmium/memory/buffer.hpp
+++ b/include/osmium/memory/buffer.hpp
@@ -46,6 +46,7 @@ DEALINGS IN THE SOFTWARE.
 #include <osmium/memory/item.hpp>
 #include <osmium/memory/item_iterator.hpp>
 #include <osmium/osm/entity.hpp>
+#include <osmium/util/compatibility.hpp>
 
 namespace osmium {
 
@@ -89,7 +90,9 @@ namespace osmium {
          *
          * By default, if a buffer gets full it will throw a buffer_is_full exception.
          * You can use the set_full_callback() method to set a callback functor
-         * which will be called instead of throwing an exception.
+         * which will be called instead of throwing an exception. The full
+         * callback functionality is deprecated and will be removed in the
+         * future. See the documentation for set_full_callback() for alternatives.
          */
         class Buffer {
 
@@ -112,12 +115,13 @@ namespace osmium {
 
         public:
 
-            typedef Item value_type;
-
             /**
-             * The constructor without any parameters creates a non-initialized
+             * The constructor without any parameters creates an invalid,
              * buffer, ie an empty hull of a buffer that has no actual memory
              * associated with it. It can be used to signify end-of-data.
+             *
+             * Most methods of the Buffer class will not work with an invalid
+             * buffer.
              */
             Buffer() noexcept :
                 m_memory(),
@@ -128,12 +132,14 @@ namespace osmium {
             }
 
             /**
-             * Constructs an externally memory-managed buffer using the given
-             * memory and size.
+             * Constructs a valid externally memory-managed buffer using the
+             * given memory and size.
              *
              * @param data A pointer to some already initialized data.
              * @param size The size of the initialized data.
-             * @throws std::invalid_argument When the size isn't a multiple of the alignment.
+             *
+             * @throws std::invalid_argument if the size isn't a multiple of
+             *         the alignment.
              */
             explicit Buffer(unsigned char* data, size_t size) :
                 m_memory(),
@@ -147,13 +153,15 @@ namespace osmium {
             }
 
             /**
-             * Constructs an externally memory-managed buffer with the given
-             * capacity that already contains 'committed' bytes of data.
+             * Constructs a valid externally memory-managed buffer with the
+             * given capacity that already contains 'committed' bytes of data.
              *
              * @param data A pointer to some (possibly initialized) data.
              * @param capacity The size of the memory for this buffer.
              * @param committed The size of the initialized data. If this is 0, the buffer startes out empty.
-             * @throws std::invalid_argument When the capacity or committed isn't a multiple of the alignment.
+             *
+             * @throws std::invalid_argument if the capacity or committed isn't
+             *         a multiple of the alignment.
              */
             explicit Buffer(unsigned char* data, size_t capacity, size_t committed) :
                 m_memory(),
@@ -170,10 +178,18 @@ namespace osmium {
             }
 
             /**
-             * Create an internally memory-managed buffer with the given capacity.
-             * different in that it internally gets dynamic memory of the
-             * required size. The dynamic memory will be automatically
-             * freed when the Buffer is destroyed.
+             * Constructs a valid internally memory-managed buffer with the
+             * given capacity.
+             * Will internally get dynamic memory of the required size.
+             * The dynamic memory will be automatically freed when the Buffer
+             * is destroyed.
+             *
+             * @param capacity The (initial) size of the memory for this buffer.
+             * @param auto_grow Should this buffer automatically grow when it
+             *        becomes to small?
+             *
+             * @throws std::invalid_argument if the capacity isn't a multiple
+             *         of the alignment.
              */
             explicit Buffer(size_t capacity, auto_grow auto_grow = auto_grow::yes) :
                 m_memory(capacity),
@@ -199,6 +215,8 @@ namespace osmium {
 
             /**
              * Return a pointer to data inside the buffer.
+             *
+             * @pre The buffer must be valid.
              */
             unsigned char* data() const noexcept {
                 assert(m_data);
@@ -206,8 +224,8 @@ namespace osmium {
             }
 
             /**
-             * Returns the capacity of the buffer, ie how many bytes it can contain.
-             * Always returns 0 on invalid buffers.
+             * Returns the capacity of the buffer, ie how many bytes it can
+             * contain. Always returns 0 on invalid buffers.
              */
             size_t capacity() const noexcept {
                 return m_capacity;
@@ -234,8 +252,7 @@ namespace osmium {
              * This tests if the current state of the buffer is aligned
              * properly. Can be used for asserts.
              *
-             * The behaviour is undefined if you call this on an invalid
-             * buffer.
+             * @pre The buffer must be valid.
              */
             bool is_aligned() const noexcept {
                 assert(m_data);
@@ -248,8 +265,21 @@ namespace osmium {
              *
              * The behaviour is undefined if you call this on an invalid
              * buffer.
+             *
+             * @pre The buffer must be valid.
+             *
+             * @deprecated
+             * Callback functionality will be removed in the future. Either
+             * detect the buffer_is_full exception or use a buffer with
+             * auto_grow::yes. If you want to avoid growing buffers, check
+             * that the used size of the buffer (committed()) is small enough
+             * compared to the capacity (for instance small than 90% of the
+             * capacity) before adding anything to the Buffer. If the buffer
+             * is initialized with auto_grow::yes, it will still grow in the
+             * rare case that a very large object will be added taking more
+             * than the difference between committed() and capacity().
              */
-            void set_full_callback(std::function<void(Buffer&)> full) {
+            OSMIUM_DEPRECATED void set_full_callback(std::function<void(Buffer&)> full) {
                 assert(m_data);
                 m_full = full;
             }
@@ -257,13 +287,18 @@ namespace osmium {
             /**
              * Grow capacity of this buffer to the given size.
              * This works only with internally memory-managed buffers.
-             * If the given size is not larger than the current capacity, nothing is done.
+             * If the given size is not larger than the current capacity,
+             * nothing is done.
              * Already written but not committed data is discarded.
              *
-             * The behaviour is undefined if you call this on an invalid
-             * buffer.
+             * @pre The buffer must be valid.
              *
              * @param size New capacity.
+             *
+             * @throws std::logic_error if the buffer doesn't use internal
+             *         memory management.
+             * @throws std::invalid_argument if the size isn't a multiple
+             *         of the alignment.
              */
             void grow(size_t size) {
                 assert(m_data);
@@ -283,10 +318,12 @@ namespace osmium {
             /**
              * Mark currently written bytes in the buffer as committed.
              *
-             * The behaviour is undefined if you call this on an invalid
-             * buffer.
+             * @pre The buffer must be valid and aligned properly (as indicated
+             *      by is_aligned().
              *
-             * @returns Last number of committed bytes before this commit.
+             * @returns Number of committed bytes before this commit. Can be
+             *          used as an offset into the buffer to get to the
+             *          object being committed by this call.
              */
             size_t commit() {
                 assert(m_data);
@@ -300,8 +337,7 @@ namespace osmium {
             /**
              * Roll back changes in buffer to last committed state.
              *
-             * The behaviour is undefined if you call this on an invalid
-             * buffer.
+             * @pre The buffer must be valid.
              */
             void rollback() {
                 assert(m_data);
@@ -325,11 +361,12 @@ namespace osmium {
             /**
              * Get the data in the buffer at the given offset.
              *
-             * The behaviour is undefined if you call this on an invalid
-             * buffer.
+             * @pre The buffer must be valid.
              *
              * @tparam T Type we want to the data to be interpreted as.
-             * @returns Reference of given type pointing to the data in the buffer.
+             *
+             * @returns Reference of given type pointing to the data in the
+             *          buffer.
              */
             template <typename T>
             T& get(const size_t offset) const {
@@ -350,27 +387,35 @@ namespace osmium {
              *
              * * If you have set a callback with set_full_callback(), it is
              *   called. After the call returns, you must have either grown
-             *   the buffer or cleared it by calling buffer.clear().
+             *   the buffer or cleared it by calling buffer.clear(). (Usage
+             *   of the full callback is deprecated and this functionality
+             *   will be removed in the future. See the documentation for
+             *   set_full_callback() for alternatives.
              * * If no callback is defined and this buffer uses internal
              *   memory management, the buffers capacity is grown, so that
              *   the new data will fit.
              * * Else the buffer_is_full exception is thrown.
              *
-             * The behaviour is undefined if you call this on an invalid
-             * buffer.
+             * @pre The buffer must be valid.
              *
              * @param size Number of bytes to reserve.
+             *
              * @returns Pointer to reserved space. Note that this pointer is
-             *         only guaranteed to be valid until the next call to
-             *         reserve_space().
-             * @throws osmium::buffer_is_full Might be thrown if the buffer is full.
+             *          only guaranteed to be valid until the next call to
+             *          reserve_space().
+             *
+             * @throws osmium::buffer_is_full if the buffer is full there is
+             *         no callback defined and the buffer isn't auto-growing.
              */
             unsigned char* reserve_space(const size_t size) {
                 assert(m_data);
+                // try to flush the buffer empty first.
+                if (m_written + size > m_capacity && m_full) {
+                    m_full(*this);
+                }
+                // if there's still not enough space, then try growing the buffer.
                 if (m_written + size > m_capacity) {
-                    if (m_full) {
-                        m_full(*this);
-                    } else if (!m_memory.empty() && (m_auto_grow == auto_grow::yes)) {
+                    if (!m_memory.empty() && (m_auto_grow == auto_grow::yes)) {
                         // double buffer size until there is enough space
                         size_t new_capacity = m_capacity * 2;
                         while (m_written + size > new_capacity) {
@@ -393,11 +438,12 @@ namespace osmium {
              * Note that you have to eventually call commit() to actually
              * commit this data.
              *
-             * The behaviour is undefined if you call this on an invalid
-             * buffer.
+             * @pre The buffer must be valid.
              *
              * @tparam T Class of the item to be copied.
+             *
              * @param item Reference to the item to be copied.
+             *
              * @returns Reference to newly copied data in the buffer.
              */
             template <typename T>
@@ -411,24 +457,26 @@ namespace osmium {
             /**
              * Add committed contents of the given buffer to this buffer.
              *
-             * The behaviour is undefined if you call this on an invalid
-             * buffer.
+             * @pre The buffer must be valid.
              *
              * Note that you have to eventually call commit() to actually
              * commit this data.
+             *
+             * @param buffer The source of the copy. Must be valid.
              */
             void add_buffer(const Buffer& buffer) {
-                assert(m_data);
+                assert(m_data && buffer);
                 unsigned char* target = reserve_space(buffer.committed());
-                std::copy_n(reinterpret_cast<const unsigned char*>(buffer.data()), buffer.committed(), target);
+                std::copy_n(buffer.data(), buffer.committed(), target);
             }
 
             /**
              * Add an item to the buffer. This function is provided so that
              * you can use std::back_inserter.
              *
-             * The behaviour is undefined if you call this on an invalid
-             * buffer.
+             * @pre The buffer must be valid.
+             *
+             * @param item The item to be added.
              */
             void push_back(const osmium::memory::Item& item) {
                 assert(m_data);
@@ -437,46 +485,109 @@ namespace osmium {
             }
 
             /**
-             * These iterators can be used to iterate over all items in
-             * a buffer.
+             * An iterator that can be used to iterate over all items of
+             * type T in a buffer.
              */
             template <typename T>
             using t_iterator = osmium::memory::ItemIterator<T>;
 
+            /**
+             * A const iterator that can be used to iterate over all items of
+             * type T in a buffer.
+             */
             template <typename T>
             using t_const_iterator = osmium::memory::ItemIterator<const T>;
 
-            typedef t_iterator<osmium::OSMEntity> iterator;
-            typedef t_const_iterator<osmium::OSMEntity> const_iterator;
+            /**
+             * An iterator that can be used to iterate over all OSMEntity
+             * objects in a buffer.
+             */
+            using iterator = t_iterator<osmium::OSMEntity>;
+
+            /**
+             * A const iterator that can be used to iterate over all OSMEntity
+             * objects in a buffer.
+             */
+            using const_iterator = t_const_iterator<osmium::OSMEntity>;
 
+            /**
+             * Get iterator for iterating over all items of type T in the
+             * buffer.
+             *
+             * @pre The buffer must be valid.
+             *
+             * @returns Iterator to first item of type T in the buffer.
+             */
             template <typename T>
             t_iterator<T> begin() {
                 assert(m_data);
                 return t_iterator<T>(m_data, m_data + m_committed);
             }
 
+            /**
+             * Get iterator for iterating over all objects of class OSMEntity
+             * in the buffer.
+             *
+             * @pre The buffer must be valid.
+             *
+             * @returns Iterator to first OSMEntity in the buffer.
+             */
             iterator begin() {
                 assert(m_data);
                 return iterator(m_data, m_data + m_committed);
             }
 
+            /**
+             * Get iterator for iterating over all items of type T in the
+             * buffer.
+             *
+             * @pre The buffer must be valid.
+             *
+             * @returns Iterator to first item of type T after given offset
+             *          in the buffer.
+             */
             template <typename T>
             t_iterator<T> get_iterator(size_t offset) {
                 assert(m_data);
                 return t_iterator<T>(m_data + offset, m_data + m_committed);
             }
 
+            /**
+             * Get iterator for iterating over all objects of class OSMEntity
+             * in the buffer.
+             *
+             * @pre The buffer must be valid.
+             *
+             * @returns Iterator to first OSMEntity after given offset in the
+             *          buffer.
+             */
             iterator get_iterator(size_t offset) {
                 assert(m_data);
                 return iterator(m_data + offset, m_data + m_committed);
             }
 
+            /**
+             * Get iterator for iterating over all items of type T in the
+             * buffer.
+             *
+             * @pre The buffer must be valid.
+             *
+             * @returns End iterator.
+             */
             template <typename T>
             t_iterator<T> end() {
                 assert(m_data);
                 return t_iterator<T>(m_data + m_committed, m_data + m_committed);
             }
 
+            /**
+             * Get iterator for iterating over all objects of class OSMEntity
+             * in the buffer.
+             *
+             * @pre The buffer must be valid.
+             *
+             * @returns End iterator.
+             */
             iterator end() {
                 assert(m_data);
                 return iterator(m_data + m_committed, m_data + m_committed);
@@ -534,7 +645,7 @@ namespace osmium {
             }
 
             /**
-             * In a bool context any initialized buffer is true.
+             * In a bool context any valid buffer is true.
              */
             explicit operator bool() const {
                 return m_data != nullptr;
@@ -548,6 +659,8 @@ namespace osmium {
                 swap(lhs.m_capacity, rhs.m_capacity);
                 swap(lhs.m_written, rhs.m_written);
                 swap(lhs.m_committed, rhs.m_committed);
+                swap(lhs.m_auto_grow, rhs.m_auto_grow);
+                swap(lhs.m_full, rhs.m_full);
             }
 
             /**
@@ -555,8 +668,8 @@ namespace osmium {
              * non-removed items forward in the buffer overwriting removed
              * items and then correcting the m_written and m_committed numbers.
              *
-             * Note that calling this function invalidates all iterators on this
-             * buffer and all offsets in this buffer.
+             * Note that calling this function invalidates all iterators on
+             * this buffer and all offsets in this buffer.
              *
              * For every non-removed item that moves its position, the function
              * 'moving_in_buffer' is called on the given callback object with
@@ -564,8 +677,7 @@ namespace osmium {
              * be and is now, respectively. This call can be used to update any
              * indexes.
              *
-             * The behaviour is undefined if you call this on an invalid
-             * buffer.
+             * @pre The buffer must be valid.
              */
             template <typename TCallbackClass>
             void purge_removed(TCallbackClass* callback) {
@@ -599,6 +711,13 @@ namespace osmium {
 
         }; // class Buffer
 
+        /**
+         * Compare two buffers for equality.
+         *
+         * Buffers are equal if they are both invalid or if they are both
+         * valid and have the same data pointer, capacity and committed
+         * data.
+         */
         inline bool operator==(const Buffer& lhs, const Buffer& rhs) noexcept {
             if (!lhs || !rhs) {
                 return !lhs && !rhs;
diff --git a/include/osmium/memory/item_iterator.hpp b/include/osmium/memory/item_iterator.hpp
index c6b4205..5751698 100644
--- a/include/osmium/memory/item_iterator.hpp
+++ b/include/osmium/memory/item_iterator.hpp
@@ -38,24 +38,12 @@ DEALINGS IN THE SOFTWARE.
 #include <iosfwd>
 #include <type_traits>
 
+#include <osmium/fwd.hpp>
 #include <osmium/memory/item.hpp>
 #include <osmium/osm/item_type.hpp>
 
 namespace osmium {
 
-    class Node;
-    class Way;
-    class Relation;
-    class Area;
-    class Changeset;
-    class OSMObject;
-    class OSMEntity;
-    class TagList;
-    class WayNodeList;
-    class RelationMemberList;
-    class InnerRing;
-    class OuterRing;
-
     namespace memory {
 
         namespace detail {
@@ -217,7 +205,7 @@ namespace osmium {
             }
 
             explicit operator bool() const {
-                return m_data != nullptr;
+                return bool(m_data) && (m_data != m_end);
             }
 
             template <typename TChar, typename TTraits>
diff --git a/include/osmium/osm/diff_object.hpp b/include/osmium/osm/diff_object.hpp
index 96e07bc..d9872ea 100644
--- a/include/osmium/osm/diff_object.hpp
+++ b/include/osmium/osm/diff_object.hpp
@@ -33,6 +33,8 @@ DEALINGS IN THE SOFTWARE.
 
 */
 
+#include <cassert>
+
 #include <osmium/fwd.hpp>
 #include <osmium/osm/item_type.hpp>
 #include <osmium/osm/object.hpp>
@@ -41,71 +43,158 @@ DEALINGS IN THE SOFTWARE.
 
 namespace osmium {
 
+    /**
+     * A DiffObject holds pointers to three OSMObjects, the current object,
+     * the previous, and the next. They always have the same type (Node, Way,
+     * or Relation) and the same ID, but may have different versions.
+     *
+     * It is used when iterating over OSM files with history data to make
+     * working with versioned OSM objects easier. Because you have access to
+     * the previous and next objects as well as the current one, comparisons
+     * between object versions is easy.
+     *
+     * If the current object is the first version available, the previous
+     * pointer must be the same as the current one. If the current object is
+     * the last version available, the next pointer must be the same as the
+     * current one.
+     *
+     * DiffObjects are immutable.
+     */
     class DiffObject {
 
-    protected:
-
-        osmium::OSMObject* m_prev;
-        osmium::OSMObject* m_curr;
-        osmium::OSMObject* m_next;
+        const osmium::OSMObject* m_prev;
+        const osmium::OSMObject* m_curr;
+        const osmium::OSMObject* m_next;
 
     public:
 
+        /**
+         * Default construct an empty DiffObject. Most methods of this class
+         * can not be called on empty DiffObjects.
+         */
         DiffObject() noexcept :
             m_prev(nullptr),
             m_curr(nullptr),
             m_next(nullptr) {
         }
 
-        explicit DiffObject(osmium::OSMObject& prev, osmium::OSMObject& curr, osmium::OSMObject& next) noexcept :
+        /**
+         * Construct a non-empty DiffObject from the given OSMObjects. All
+         * OSMObjects must be of the same type (Node, Way, or Relation) and
+         * have the same ID.
+         */
+        DiffObject(const osmium::OSMObject& prev, const osmium::OSMObject& curr, const osmium::OSMObject& next) noexcept :
             m_prev(&prev),
             m_curr(&curr),
             m_next(&next) {
+            assert(prev.type() == curr.type() && curr.type() == next.type());
+            assert(prev.id()   == curr.id()   && curr.id()   == next.id());
         }
 
-        DiffObject(const DiffObject&) = default;
-        DiffObject& operator=(const DiffObject&) = default;
-
-        DiffObject(DiffObject&&) = default;
-        DiffObject& operator=(DiffObject&&) = default;
+        /**
+         * Check whether the DiffObject was created empty.
+         */
+        bool empty() const noexcept {
+            return m_prev == nullptr;
+        }
 
+        /**
+         * Get the previous object stored.
+         *
+         * @pre DiffObject must not be empty.
+         */
         const osmium::OSMObject& prev() const noexcept {
+            assert(m_prev && m_curr && m_next);
             return *m_prev;
         }
 
+        /**
+         * Get the current object stored.
+         *
+         * @pre DiffObject must not be empty.
+         */
         const osmium::OSMObject& curr() const noexcept {
+            assert(m_prev && m_curr && m_next);
             return *m_curr;
         }
 
+        /**
+         * Get the next object stored.
+         *
+         * @pre DiffObject must not be empty.
+         */
         const osmium::OSMObject& next() const noexcept {
+            assert(m_prev && m_curr && m_next);
             return *m_next;
         }
 
+        /**
+         * Is the current object version the first (with this type and ID)?
+         *
+         * @pre DiffObject must not be empty.
+         */
         bool first() const noexcept {
+            assert(m_prev && m_curr && m_next);
             return m_prev == m_curr;
         }
 
+        /**
+         * Is the current object version the last (with this type and ID)?
+         *
+         * @pre DiffObject must not be empty.
+         */
         bool last() const noexcept {
+            assert(m_prev && m_curr && m_next);
             return m_curr == m_next;
         }
 
+        /**
+         * Return the type of the current object.
+         *
+         * @pre DiffObject must not be empty.
+         */
         osmium::item_type type() const noexcept {
+            assert(m_prev && m_curr && m_next);
             return m_curr->type();
         }
 
+        /**
+         * Return the ID of the current object.
+         *
+         * @pre DiffObject must not be empty.
+         */
         osmium::object_id_type id() const noexcept {
+            assert(m_prev && m_curr && m_next);
             return m_curr->id();
         }
 
+        /**
+         * Return the version of the current object.
+         *
+         * @pre DiffObject must not be empty.
+         */
         osmium::object_version_type version() const noexcept {
+            assert(m_prev && m_curr && m_next);
             return m_curr->version();
         }
 
+        /**
+         * Return the changeset ID of the current object.
+         *
+         * @pre DiffObject must not be empty.
+         */
         osmium::changeset_id_type changeset() const noexcept {
+            assert(m_prev && m_curr && m_next);
             return m_curr->changeset();
         }
 
+        /**
+         * Return the timestamp when the current object version was created.
+         *
+         * @pre DiffObject must not be empty.
+         */
         const osmium::Timestamp start_time() const noexcept {
+            assert(m_prev && m_curr && m_next);
             return m_curr->timestamp();
         }
 
@@ -115,8 +204,11 @@ namespace osmium {
          * is valid. If this is the last version of the object, this will
          * return a special "end of time" timestamp that is guaranteed to
          * be larger than any normal timestamp.
+         *
+         * @pre DiffObject must not be empty.
          */
         const osmium::Timestamp end_time() const noexcept {
+            assert(m_prev && m_curr && m_next);
             return last() ? osmium::end_of_time() : m_next->timestamp();
         }
 
@@ -126,8 +218,11 @@ namespace osmium {
          *
          * This is a bit more complex than you'd think, because we have to
          * handle the case properly where the start_time() == end_time().
+         *
+         * @pre DiffObject must not be empty.
          */
         bool is_between(const osmium::Timestamp& from, const osmium::Timestamp& to) const noexcept {
+            assert(m_prev && m_curr && m_next);
             return start_time() < to &&
                    ((start_time() != end_time() && end_time() >  from) ||
                     (start_time() == end_time() && end_time() >= from));
@@ -135,8 +230,11 @@ namespace osmium {
 
         /**
          * Current object version is visible at the given timestamp.
+         *
+         * @pre DiffObject must not be empty.
          */
         bool is_visible_at(const osmium::Timestamp& timestamp) const noexcept {
+            assert(m_prev && m_curr && m_next);
             return start_time() <= timestamp && end_time() > timestamp && m_curr->visible();
         }
 
@@ -147,33 +245,27 @@ namespace osmium {
 
     public:
 
-        DiffObjectDerived(T& prev, T& curr, T& next) noexcept :
+        DiffObjectDerived(const T& prev, const T& curr, const T& next) noexcept :
             DiffObject(prev, curr, next) {
         }
 
-        DiffObjectDerived(const DiffObjectDerived&) = default;
-        DiffObjectDerived& operator=(const DiffObjectDerived&) = default;
-
-        DiffObjectDerived(DiffObjectDerived&&) = default;
-        DiffObjectDerived& operator=(DiffObjectDerived&&) = default;
-
         const T& prev() const noexcept {
-            return *static_cast<const T*>(m_prev);
+            return static_cast<const T&>(DiffObject::prev());
         }
 
         const T& curr() const noexcept {
-            return *static_cast<const T*>(m_curr);
+            return static_cast<const T&>(DiffObject::curr());
         }
 
         const T& next() const noexcept {
-            return *static_cast<const T*>(m_next);
+            return static_cast<const T&>(DiffObject::next());
         }
 
     }; // class DiffObjectDerived
 
-    typedef DiffObjectDerived<osmium::Node>     DiffNode;
-    typedef DiffObjectDerived<osmium::Way>      DiffWay;
-    typedef DiffObjectDerived<osmium::Relation> DiffRelation;
+    using DiffNode     = DiffObjectDerived<osmium::Node>;
+    using DiffWay      = DiffObjectDerived<osmium::Way>;
+    using DiffRelation = DiffObjectDerived<osmium::Relation>;
 
 } // namespace osmium
 
diff --git a/include/osmium/osm/item_type.hpp b/include/osmium/osm/item_type.hpp
index d8f5296..95826bc 100644
--- a/include/osmium/osm/item_type.hpp
+++ b/include/osmium/osm/item_type.hpp
@@ -61,6 +61,10 @@ namespace osmium {
     /**
      * Return item_type for index:
      * 0 -> node, 1 -> way, 2 -> relation
+     *
+     * @param i Index. Must be between 0 and 2.
+     *
+     * @returns Item type.
      */
     inline item_type nwr_index_to_item_type(unsigned int i) noexcept {
         assert(i <= 2);
@@ -70,6 +74,10 @@ namespace osmium {
     /**
      * Return index for item_type:
      * node -> 0, way -> 1, relation -> 2
+     *
+     * @param type Item type. Must be node, way, or relation.
+     *
+     * @returns Index.
      */
     inline unsigned int item_type_to_nwr_index(item_type type) noexcept {
         unsigned int i = static_cast<unsigned int>(type);
diff --git a/include/osmium/osm/node_ref.hpp b/include/osmium/osm/node_ref.hpp
index 72359cd..def63b2 100644
--- a/include/osmium/osm/node_ref.hpp
+++ b/include/osmium/osm/node_ref.hpp
@@ -59,10 +59,16 @@ namespace osmium {
             m_location(location) {
         }
 
+        /**
+         * Get reference ID of this NodeRef.
+         */
         osmium::object_id_type ref() const noexcept {
             return m_ref;
         }
 
+        /**
+         * Get absolute value of the reference ID of this NodeRef.
+         */
         osmium::unsigned_object_id_type positive_ref() const noexcept {
             return static_cast<osmium::unsigned_object_id_type>(std::abs(m_ref));
         }
@@ -74,31 +80,60 @@ namespace osmium {
             return m_location;
         }
 
+        /**
+         * Get location of this NodeRef.
+         */
         osmium::Location location() const noexcept {
             return m_location;
         }
 
+        /**
+         * Get longitude of the location in this NodeRef.
+         *
+         * @throws osmium::invalid_location if the location is not set.
+         */
         double lon() const {
             return m_location.lon();
         }
 
+        /**
+         * Get latitude of the location in this NodeRef.
+         *
+         * @throws osmium::invalid_location if the location is not set.
+         */
         double lat() const {
             return m_location.lat();
         }
 
+        /**
+         * Get internal x value of the location in this NodeRef.
+         */
         int32_t x() const noexcept {
             return m_location.x();
         }
 
+        /**
+         * Get internal y value of the location in this NodeRef.
+         */
         int32_t y() const noexcept {
             return m_location.y();
         }
 
+        /**
+         * Set the referenced ID.
+         *
+         * @returns Reference to this NodeRef for chaining calls.
+         */
         NodeRef& set_ref(const osmium::object_id_type ref) noexcept {
             m_ref = ref;
             return *this;
         }
 
+        /**
+         * Set the location.
+         *
+         * @returns Reference to this NodeRef for chaining calls.
+         */
         NodeRef& set_location(const osmium::Location& location) noexcept {
             m_location = location;
             return *this;
@@ -106,26 +141,49 @@ namespace osmium {
 
     }; // class NodeRef
 
+    /**
+     * Compare two NodeRefs. They are equal if they reference the same Node ID.
+     */
     inline bool operator==(const NodeRef& lhs, const NodeRef& rhs) noexcept {
         return lhs.ref() == rhs.ref();
     }
 
+    /**
+     * Compare two NodeRefs. They are not equal if they reference different
+     * Node IDs.
+     */
     inline bool operator!=(const NodeRef& lhs, const NodeRef& rhs) noexcept {
         return ! (lhs == rhs);
     }
 
+    /**
+     * Compare two NodeRefs. NodeRefs are ordered according to the Node ID
+     * they reference.
+     */
     inline bool operator<(const NodeRef& lhs, const NodeRef& rhs) noexcept {
         return lhs.ref() < rhs.ref();
     }
 
+    /**
+     * Compare two NodeRefs. NodeRefs are ordered according to the Node ID
+     * they reference.
+     */
     inline bool operator>(const NodeRef& lhs, const NodeRef& rhs) noexcept {
         return rhs < lhs;
     }
 
+    /**
+     * Compare two NodeRefs. NodeRefs are ordered according to the Node ID
+     * they reference.
+     */
     inline bool operator<=(const NodeRef& lhs, const NodeRef& rhs) noexcept {
         return ! (rhs < lhs);
     }
 
+    /**
+     * Compare two NodeRefs. NodeRefs are ordered according to the Node ID
+     * they reference.
+     */
     inline bool operator>=(const NodeRef& lhs, const NodeRef& rhs) noexcept {
         return ! (lhs < rhs);
     }
@@ -139,7 +197,7 @@ namespace osmium {
     }
 
     /**
-     * Functor to compare NodeRefs by Location instead of id.
+     * Functor to compare NodeRefs by Location instead of ID.
      */
     struct location_equal {
 
@@ -147,14 +205,14 @@ namespace osmium {
             return lhs.location() == rhs.location();
         }
 
-        typedef NodeRef first_argument_type;
-        typedef NodeRef second_argument_type;
-        typedef bool result_type;
+        using first_argument_type = NodeRef;
+        using second_argument_type = NodeRef;
+        using result_type = bool;
 
     }; // struct location_equal
 
     /**
-     * Functor to compare NodeRefs by Location instead of id.
+     * Functor to compare NodeRefs by Location instead of ID.
      */
     struct location_less {
 
@@ -162,9 +220,9 @@ namespace osmium {
             return lhs.location() < rhs.location();
         }
 
-        typedef NodeRef first_argument_type;
-        typedef NodeRef second_argument_type;
-        typedef bool result_type;
+        using first_argument_type = NodeRef;
+        using second_argument_type = NodeRef;
+        using result_type = bool;
 
     }; // struct location_less
 
diff --git a/include/osmium/osm/node_ref_list.hpp b/include/osmium/osm/node_ref_list.hpp
index c6c4213..e46a66d 100644
--- a/include/osmium/osm/node_ref_list.hpp
+++ b/include/osmium/osm/node_ref_list.hpp
@@ -44,8 +44,8 @@ DEALINGS IN THE SOFTWARE.
 namespace osmium {
 
     /**
-     * A vector of NodeRef objects. Usually this is not instantiated directly,
-     * but one of its subclasses are used.
+     * An ordered collection of NodeRef objects. Usually this is not
+     * instantiated directly, but one of its subclasses are used.
      */
     class NodeRefList : public osmium::memory::Item {
 
@@ -56,14 +56,14 @@ namespace osmium {
         }
 
         /**
-         * Checks whether the node list is empty.
+         * Checks whether the collection is empty.
          */
         bool empty() const noexcept {
             return sizeof(NodeRefList) == byte_size();
         }
 
         /**
-         * Returns the number of nodes in the list.
+         * Returns the number of NodeRefs in the collection.
          */
         size_t size() const noexcept {
             auto size_node_refs = byte_size() - sizeof(NodeRefList);
@@ -74,8 +74,9 @@ namespace osmium {
         /**
          * Access specified element.
          *
-         * @param n Get this element of the list.
          * @pre @code n < size() @endcode
+         *
+         * @param n Get the n-th element of the collection.
          */
         const NodeRef& operator[](size_t n) const noexcept {
             assert(n < size());
@@ -104,16 +105,18 @@ namespace osmium {
         }
 
         /**
-         * Checks whether the first and last node in the list have the same ID.
+         * Checks whether the first and last node in the collection have the
+         * same ID. The locations are not checked.
          *
          * @pre @code !empty() @endcode
          */
         bool is_closed() const noexcept {
-            return front().ref() == back().ref();
+            return ends_have_same_id();
         }
 
         /**
-         * Checks whether the first and last node in the list have the same ID.
+         * Checks whether the first and last node in the collection have the
+         * same ID. The locations are not checked.
          *
          * @pre @code !empty() @endcode
          */
@@ -122,8 +125,8 @@ namespace osmium {
         }
 
         /**
-         * Checks whether the first and last node in the list have the same
-         * location. The ID is not checked.
+         * Checks whether the first and last node in the collection have the
+         * same location. The IDs are not checked.
          *
          * @pre @code !empty() @endcode
          * @pre @code front().location() && back().location() @endcode
@@ -133,9 +136,9 @@ namespace osmium {
             return front().location() == back().location();
         }
 
-        typedef NodeRef* iterator;
-        typedef const NodeRef* const_iterator;
-        typedef std::reverse_iterator<const NodeRef*> const_reverse_iterator;
+        using iterator = NodeRef*;
+        using const_iterator = const NodeRef*;
+        using const_reverse_iterator = std::reverse_iterator<const NodeRef*>;
 
         /// Returns an iterator to the beginning.
         iterator begin() noexcept {
diff --git a/include/osmium/osm/timestamp.hpp b/include/osmium/osm/timestamp.hpp
index 2145fcb..9de727f 100644
--- a/include/osmium/osm/timestamp.hpp
+++ b/include/osmium/osm/timestamp.hpp
@@ -54,10 +54,8 @@ namespace osmium {
         // length of ISO timestamp string yyyy-mm-ddThh:mm:ssZ\0
         static constexpr int timestamp_length = 20 + 1;
 
-        /**
-         * The timestamp format for OSM timestamps in strftime(3) format.
-         * This is the ISO-Format yyyy-mm-ddThh:mm:ssZ
-         */
+        // The timestamp format for OSM timestamps in strftime(3) format.
+        // This is the ISO-Format "yyyy-mm-ddThh:mm:ssZ".
         static const char* timestamp_format() {
             static const char f[timestamp_length] = "%Y-%m-%dT%H:%M:%SZ";
             return f;
@@ -67,27 +65,29 @@ namespace osmium {
 
     public:
 
+        /**
+         * Default construct an invalid Timestamp.
+         */
         constexpr Timestamp() noexcept :
             m_timestamp(0) {
         }
 
-        // Not "explicit" so that conversions from time_t work
-        // like in node.timestamp(123);
-        constexpr Timestamp(time_t timestamp) noexcept :
-            m_timestamp(static_cast<uint32_t>(timestamp)) {
-        }
-
         /**
-         * Returns true if this timestamp is valid (ie set to something other
-         * than 0).
+         * Construct a Timestamp from a time_t containing the seconds since
+         * the epoch.
+         *
+         * The constructor is not declared "explicit" so that conversions
+         * like @code node.set_timestamp(123); @endcode work.
          */
-        bool valid() const noexcept {
-            return m_timestamp != 0;
+        constexpr Timestamp(time_t timestamp) noexcept :
+            m_timestamp(static_cast<uint32_t>(timestamp)) {
         }
 
         /**
-         * Construct timestamp from ISO date/time string.
-         * Throws std::invalid_argument, if the timestamp can not be parsed.
+         * Construct timestamp from ISO date/time string in the format
+         * "yyyy-mm-ddThh:mm:ssZ".
+         *
+         * @throws std::invalid_argument if the timestamp can not be parsed.
          */
         explicit Timestamp(const char* timestamp) {
 #ifndef _WIN32
@@ -113,14 +113,35 @@ namespace osmium {
 #endif
         }
 
+        /**
+         * Construct timestamp from ISO date/time string in the format
+         * "yyyy-mm-ddThh:mm:ssZ".
+         *
+         * @throws std::invalid_argument if the timestamp can not be parsed.
+         */
+        explicit Timestamp(const std::string& timestamp) :
+            Timestamp(timestamp.c_str()) {
+        }
+
+        /**
+         * Returns true if this timestamp is valid (ie set to something other
+         * than 0).
+         */
+        bool valid() const noexcept {
+            return m_timestamp != 0;
+        }
+
+        /// Explicit conversion into time_t.
         constexpr time_t seconds_since_epoch() const noexcept {
             return static_cast<time_t>(m_timestamp);
         }
 
+        /// Implicit conversion into time_t.
         constexpr operator time_t() const noexcept {
             return static_cast<time_t>(m_timestamp);
         }
 
+        /// Explicit conversion into uint32_t.
         explicit constexpr operator uint32_t() const noexcept {
             return m_timestamp;
         }
@@ -136,7 +157,8 @@ namespace osmium {
         }
 
         /**
-         * Return UTC Unix time as string in ISO date/time format.
+         * Return UTC Unix time as string in ISO date/time
+         * ("yyyy-mm-ddThh:mm:ssZ") format.
          */
         std::string to_iso() const {
             std::string s;
@@ -164,12 +186,20 @@ namespace osmium {
 
     }; // class Timestamp
 
+    /**
+     * A special Timestamp guaranteed to be ordered before any other valid
+     * Timestamp.
+     */
     inline OSMIUM_CONSTEXPR Timestamp start_of_time() noexcept {
         return Timestamp(1);
     }
 
+    /**
+     * A special Timestamp guaranteed to be ordered after any other valid
+     * Timestamp.
+     */
     inline OSMIUM_CONSTEXPR Timestamp end_of_time() noexcept {
-        return Timestamp(std::numeric_limits<time_t>::max());
+        return Timestamp(std::numeric_limits<uint32_t>::max());
     }
 
     template <typename TChar, typename TTraits>
diff --git a/include/osmium/osm/types_from_string.hpp b/include/osmium/osm/types_from_string.hpp
index b0e22a7..67ab2c1 100644
--- a/include/osmium/osm/types_from_string.hpp
+++ b/include/osmium/osm/types_from_string.hpp
@@ -47,6 +47,15 @@ DEALINGS IN THE SOFTWARE.
 
 namespace osmium {
 
+    /**
+     * Convert string with object id to object_id_type.
+     *
+     * @pre input must not be nullptr.
+     *
+     * @param input Input string.
+     *
+     * @throws std::range_error if the value is out of range.
+     */
     inline object_id_type string_to_object_id(const char* input) {
         assert(input);
         if (*input != '\0' && !std::isspace(*input)) {
@@ -59,6 +68,19 @@ namespace osmium {
         throw std::range_error(std::string("illegal id: '") + input + "'");
     }
 
+    /**
+     * Parse string with object type identifier followed by object id. This
+     * reads strings like "n1234" and "w10".
+     *
+     * @pre input must not be nullptr.
+     *
+     * @param input Input string.
+     * @param types Allowed types. Must not be osmium::osm_entity_bits::nothing.
+     *
+     * @returns std::pair of type and id.
+     *
+     * @throws std::range_error if the value is out of range.
+     */
     inline std::pair<osmium::item_type, osmium::object_id_type> string_to_object_id(const char* input, osmium::osm_entity_bits::type types) {
         assert(input);
         assert(types != osmium::osm_entity_bits::nothing);
@@ -89,16 +111,43 @@ namespace osmium {
 
     } // namespace detail
 
+    /**
+     * Convert string with object version to object_version_type.
+     *
+     * @pre input must not be nullptr.
+     *
+     * @param input Input string.
+     *
+     * @throws std::range_error if the value is out of range.
+     */
     inline object_version_type string_to_object_version(const char* input) {
         assert(input);
         return static_cast_with_assert<object_version_type>(detail::string_to_ulong(input, "version"));
     }
 
+    /**
+     * Convert string with object version to object_version_type.
+     *
+     * @pre input must not be nullptr.
+     *
+     * @param input Input string.
+     *
+     * @throws std::range_error if the value is out of range.
+     */
     inline changeset_id_type string_to_changeset_id(const char* input) {
         assert(input);
         return static_cast_with_assert<changeset_id_type>(detail::string_to_ulong(input, "changeset"));
     }
 
+    /**
+     * Convert string with user id to signed_user_id_type.
+     *
+     * @pre input must not be nullptr.
+     *
+     * @param input Input string.
+     *
+     * @throws std::range_error if the value is out of range.
+     */
     inline signed_user_id_type string_to_user_id(const char* input) {
         assert(input);
         if (input[0] == '-' && input[1] == '1' && input[2] == '\0') {
@@ -107,11 +156,29 @@ namespace osmium {
         return static_cast_with_assert<signed_user_id_type>(detail::string_to_ulong(input, "user id"));
     }
 
+    /**
+     * Convert string with number of changes to num_changes_type.
+     *
+     * @pre input must not be nullptr.
+     *
+     * @param input Input string.
+     *
+     * @throws std::range_error if the value is out of range.
+     */
     inline num_changes_type string_to_num_changes(const char* input) {
         assert(input);
         return static_cast_with_assert<num_changes_type>(detail::string_to_ulong(input, "value for num changes"));
     }
 
+    /**
+     * Convert string with number of comments to num_comments_type.
+     *
+     * @pre input must not be nullptr.
+     *
+     * @param input Input string.
+     *
+     * @throws std::range_error if the value is out of range.
+     */
     inline num_comments_type string_to_num_comments(const char* input) {
         assert(input);
         return static_cast_with_assert<num_comments_type>(detail::string_to_ulong(input, "value for num comments"));
diff --git a/include/osmium/relations/collector.hpp b/include/osmium/relations/collector.hpp
index e7f76a2..7d27b33 100644
--- a/include/osmium/relations/collector.hpp
+++ b/include/osmium/relations/collector.hpp
@@ -122,82 +122,15 @@ namespace osmium {
 
                 TCollector& m_collector;
 
-                /**
-                 * This variable is initialized with the number of different
-                 * kinds of OSM objects we are interested in. If we only need
-                 * way members (for instance for the multipolygon collector)
-                 * it is intialized with 1 for instance. If node and way
-                 * members are needed, it is initialized with 2.
-                 *
-                 * In the after_* methods of this handler, it is decremented
-                 * and once it reaches 0, we know we have all members available
-                 * that we are ever going to get.
-                 */
-                int m_want_types;
-
-                /**
-                 * Find this object in the member vectors and add it to all
-                 * relations that need it.
-                 *
-                 * @returns true if the member was added to at least one
-                 *          relation and false otherwise
-                 */
-                bool find_and_add_object(const osmium::OSMObject& object) {
-                    auto& mmv = m_collector.member_meta(object.type());
-                    auto range = std::equal_range(mmv.begin(), mmv.end(), MemberMeta(object.id()));
-
-                    if (osmium::relations::count_not_removed(range.first, range.second) == 0) {
-                        // nothing found
-                        return false;
-                    }
-
-                    {
-                        m_collector.members_buffer().add_item(object);
-                        const size_t member_offset = m_collector.members_buffer().commit();
-
-                        for (auto it = range.first; it != range.second; ++it) {
-                            it->set_buffer_offset(member_offset);
-                        }
-                    }
-
-                    for (auto it = range.first; it != range.second; ++it) {
-                        MemberMeta& member_meta = *it;
-                        if (member_meta.removed()) {
-                            break;
-                        }
-                        assert(member_meta.member_id() == object.id());
-                        assert(member_meta.relation_pos() < m_collector.m_relations.size());
-                        RelationMeta& relation_meta = m_collector.m_relations[member_meta.relation_pos()];
-//                        std::cerr << "  => " << member_meta.member_pos() << " < " << m_collector.get_relation(relation_meta).members().size() << " (id=" << m_collector.get_relation(relation_meta).id() << ")\n";
-                        assert(member_meta.member_pos() < m_collector.get_relation(relation_meta).members().size());
-//                        std::cerr << "  add way " << member_meta.member_id() << " to rel " << m_collector.get_relation(relation_meta).id() << " at pos " << member_meta.member_pos() << "\n";
-                        relation_meta.got_one_member();
-                        if (relation_meta.has_all_members()) {
-                            const size_t relation_offset = member_meta.relation_pos();
-                            m_collector.complete_relation(relation_meta);
-                            m_collector.m_relations[relation_offset] = RelationMeta();
-                            m_collector.possibly_purge_removed_members();
-                        }
-                    }
-
-                    // Remove MemberMetas that were marked as removed.
-                    mmv.erase(std::remove_if(mmv.begin(), mmv.end(), [](MemberMeta& mm) {
-                        return mm.removed();
-                    }), mmv.end());
-
-                    return true;
-                }
-
             public:
 
                 HandlerPass2(TCollector& collector) noexcept :
-                    m_collector(collector),
-                    m_want_types((TNodes?1:0) + (TWays?1:0) + (TRelations?1:0)) {
+                    m_collector(collector) {
                 }
 
                 void node(const osmium::Node& node) {
                     if (TNodes) {
-                        if (! find_and_add_object(node)) {
+                        if (! m_collector.find_and_add_object(node)) {
                             m_collector.node_not_in_any_relation(node);
                         }
                     }
@@ -205,7 +138,7 @@ namespace osmium {
 
                 void way(const osmium::Way& way) {
                     if (TWays) {
-                        if (! find_and_add_object(way)) {
+                        if (! m_collector.find_and_add_object(way)) {
                             m_collector.way_not_in_any_relation(way);
                         }
                     }
@@ -213,7 +146,7 @@ namespace osmium {
 
                 void relation(const osmium::Relation& relation) {
                     if (TRelations) {
-                        if (! find_and_add_object(relation)) {
+                        if (! m_collector.find_and_add_object(relation)) {
                             m_collector.relation_not_in_any_relation(relation);
                         }
                     }
@@ -225,6 +158,8 @@ namespace osmium {
 
             }; // class HandlerPass2
 
+        private:
+
             HandlerPass2 m_handler_pass2;
 
             // All relations we are interested in will be kept in this buffer
@@ -373,6 +308,8 @@ namespace osmium {
                 return m_members_buffer.get<osmium::OSMObject>(offset);
             }
 
+        private:
+
             /**
              * Tell the Collector that you are interested in this relation
              * and want it kept until all members have been assembled and
@@ -422,6 +359,84 @@ namespace osmium {
                 std::sort(m_member_meta[2].begin(), m_member_meta[2].end());
             }
 
+            /**
+             * Find this object in the member vectors and add it to all
+             * relations that need it.
+             *
+             * @returns true if the member was added to at least one
+             *          relation and false otherwise
+             */
+            bool find_and_add_object(const osmium::OSMObject& object) {
+                auto& mmv = member_meta(object.type());
+                auto range = std::equal_range(mmv.begin(), mmv.end(), MemberMeta(object.id()));
+
+                if (osmium::relations::count_not_removed(range.first, range.second) == 0) {
+                    // nothing found
+                    return false;
+                }
+
+                {
+                    members_buffer().add_item(object);
+                    const size_t member_offset = members_buffer().commit();
+
+                    for (auto it = range.first; it != range.second; ++it) {
+                        it->set_buffer_offset(member_offset);
+                    }
+                }
+
+                for (auto it = range.first; it != range.second; ++it) {
+                    MemberMeta& member_meta = *it;
+                    if (member_meta.removed()) {
+                        break;
+                    }
+                    assert(member_meta.member_id() == object.id());
+                    assert(member_meta.relation_pos() < m_relations.size());
+                    RelationMeta& relation_meta = m_relations[member_meta.relation_pos()];
+//                        std::cerr << "  => " << member_meta.member_pos() << " < " << get_relation(relation_meta).members().size() << " (id=" << get_relation(relation_meta).id() << ")\n";
+                    assert(member_meta.member_pos() < get_relation(relation_meta).members().size());
+//                        std::cerr << "  add way " << member_meta.member_id() << " to rel " << get_relation(relation_meta).id() << " at pos " << member_meta.member_pos() << "\n";
+                    relation_meta.got_one_member();
+                    if (relation_meta.has_all_members()) {
+                        const size_t relation_offset = member_meta.relation_pos();
+                        static_cast<TCollector*>(this)->complete_relation(relation_meta);
+                        clear_member_metas(relation_meta);
+                        m_relations[relation_offset] = RelationMeta();
+                        possibly_purge_removed_members();
+                    }
+                }
+
+                // Remove MemberMetas that were marked as removed.
+                mmv.erase(std::remove_if(mmv.begin(), mmv.end(), [](MemberMeta& mm) {
+                    return mm.removed();
+                }), mmv.end());
+
+                return true;
+            }
+
+            void clear_member_metas(const osmium::relations::RelationMeta& relation_meta) {
+                const osmium::Relation& relation = get_relation(relation_meta);
+                for (const auto& member : relation.members()) {
+                    if (member.ref() != 0) {
+                        auto& mmv = member_meta(member.type());
+                        auto range = std::equal_range(mmv.begin(), mmv.end(), MemberMeta(member.ref()));
+                        assert(range.first != range.second);
+
+                        // if this is the last time this object was needed
+                        // then mark it as removed
+                        if (osmium::relations::count_not_removed(range.first, range.second) == 1) {
+                            get_member(range.first->buffer_offset()).set_removed(true);
+                        }
+
+                        for (auto it = range.first; it != range.second; ++it) {
+                            if (!it->removed() && relation.id() == get_relation(it->relation_pos()).id()) {
+                                it->remove();
+                                break;
+                            }
+                        }
+                    }
+                }
+            }
+
         public:
 
             uint64_t used_memory() const {
@@ -488,7 +503,7 @@ namespace osmium {
             void moving_in_buffer(size_t old_offset, size_t new_offset) {
                 const osmium::OSMObject& object = m_members_buffer.get<osmium::OSMObject>(old_offset);
                 auto& mmv = member_meta(object.type());
-                auto range = std::equal_range(mmv.begin(), mmv.end(), osmium::relations::MemberMeta(object.id()));
+                auto range = std::equal_range(mmv.begin(), mmv.end(), MemberMeta(object.id()));
                 for (auto it = range.first; it != range.second; ++it) {
                     assert(it->buffer_offset() == old_offset);
                     it->set_buffer_offset(new_offset);
diff --git a/include/osmium/util/data_file.hpp b/include/osmium/util/data_file.hpp
deleted file mode 100644
index 53bb81c..0000000
--- a/include/osmium/util/data_file.hpp
+++ /dev/null
@@ -1,194 +0,0 @@
-#ifndef OSMIUM_UTIL_DATA_FILE_HPP
-#define OSMIUM_UTIL_DATA_FILE_HPP
-
-/*
-
-This file is part of Osmium (http://osmcode.org/libosmium).
-
-Copyright 2013-2015 Jochen Topf <jochen at topf.org> and others (see README).
-
-Boost Software License - Version 1.0 - August 17th, 2003
-
-Permission is hereby granted, free of charge, to any person or organization
-obtaining a copy of the software and accompanying documentation covered by
-this license (the "Software") to use, reproduce, display, distribute,
-execute, and transmit the Software, and to prepare derivative works of the
-Software, and to permit third-parties to whom the Software is furnished to
-do so, all subject to the following:
-
-The copyright notices in the Software and this entire statement, including
-the above license grant, this restriction and the following disclaimer,
-must be included in all copies of the Software, in whole or in part, and
-all derivative works of the Software, unless such copies or derivative
-works are solely in the form of machine-executable object code generated by
-a source language processor.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
-SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
-FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
-ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-DEALINGS IN THE SOFTWARE.
-
-*/
-
-#include <cerrno>
-#include <cstddef>
-#include <cstdio>
-#include <stdexcept>
-#include <string>
-#include <system_error>
-
-#ifdef _WIN32
-# include <io.h>
-# include <windows.h>
-#endif
-
-#include <osmium/util/file.hpp>
-
-namespace osmium {
-
-    namespace util {
-
-        /**
-         * Class wrapper for convenient access to some low-level file
-         * functions.
-         */
-        class DataFile {
-
-            FILE* m_file;
-
-        public:
-
-            /**
-             * Create and open a temporary file. It is removed after opening.
-             *
-             * @throws std::system_error if something went wrong.
-             */
-            DataFile() :
-                m_file(::tmpfile()) {
-                if (!m_file) {
-                    throw std::system_error(errno, std::system_category(), "tmpfile failed");
-                }
-            }
-
-            /**
-             * Create and open a temporary file with the specified size. It
-             * is removed after opening.
-             *
-             * @throws std::system_error if something went wrong.
-             */
-            explicit DataFile(size_t size) :
-                DataFile() {
-                grow(size);
-            }
-
-            /**
-             * Create and open a named file.
-             *
-             * @param filename the name of the file
-             * @param writable should the file be writable?
-             * @throws std::system_error if something went wrong.
-             */
-            DataFile(const char* filename, bool writable) :
-                m_file(::fopen(filename, writable ? "wb+" : "rb" )) {
-                if (!m_file) {
-                    throw std::system_error(errno, std::system_category(), "fopen failed");
-                }
-            }
-
-            /**
-             * Create and open a named file.
-             *
-             * @param filename the name of the file
-             * @param writable should the file be writable?
-             * @throws std::system_error if something went wrong.
-             */
-            DataFile(const std::string& filename, bool writable) :
-                DataFile(filename.c_str(), writable) {
-            }
-
-            /**
-             * In boolean context the DataFile class returns true if the file
-             * is open.
-             */
-            operator bool() const noexcept {
-                return m_file != nullptr;
-            }
-
-            /**
-             * Close the file.
-             *
-             * Does nothing if the file is already closed.
-             *
-             * @throws std::system_error if file could not be closed
-             */
-            void close() {
-                if (m_file) {
-                    if (::fclose(m_file) != 0) {
-                        throw std::system_error(errno, std::system_category(), "fclose failed");
-                    }
-                    m_file = nullptr;
-                }
-            }
-
-            ~DataFile() noexcept {
-                try {
-                    close();
-                } catch (std::system_error&) {
-                    // Ignore any exceptions because destructor must not throw.
-                }
-            }
-
-            /**
-             * Get file descriptor of underlying file.
-             *
-             * @throws std::runtime_errro if file is not open
-             * @throws std::system_error if fileno(3) call failed
-             */
-            int fd() const {
-                if (!m_file) {
-                    throw std::runtime_error("no open file");
-                }
-
-                int fd = ::fileno(m_file);
-
-                if (fd == -1) {
-                    throw std::system_error(errno, std::system_category(), "fileno failed");
-                }
-
-                return fd;
-            }
-
-            /**
-             * Ask the operating system for the size of this file.
-             *
-             * @throws std::system_error if fstat(2) call failed
-             */
-            size_t size() const {
-                return osmium::util::file_size(fd());
-            }
-
-            /**
-             * Grow file to given size.
-             *
-             * If the file is large enough already, nothing is done.
-             * The file is never shrunk.
-             *
-             * @throws std::system_error if ftruncate(2) call failed
-             */
-            void grow(size_t new_size) const {
-                if (size() < new_size) {
-                    osmium::util::resize_file(fd(), new_size);
-                }
-            }
-
-        }; // class DataFile
-
-    } // namespace util
-
-} // namespace osmium
-
-
-#endif // OSMIUM_UTIL_DATA_FILE_HPP
diff --git a/include/osmium/util/memory_mapping.hpp b/include/osmium/util/memory_mapping.hpp
index d5a057d..48da13a 100644
--- a/include/osmium/util/memory_mapping.hpp
+++ b/include/osmium/util/memory_mapping.hpp
@@ -38,6 +38,7 @@ DEALINGS IN THE SOFTWARE.
 #include <stdexcept>
 #include <system_error>
 
+#include <osmium/util/compatibility.hpp>
 #include <osmium/util/file.hpp>
 
 #ifndef _WIN32
@@ -173,7 +174,8 @@ private:
              * created, otherwise a mapping based on the file descriptor will
              * be created.
              *
-             * @pre size > 0 or mode == write_shared oder write_private
+             * @pre @code size > 0 @endcode or
+             *      @code mode == write_shared || mode == write_private @endcode
              *
              * @param size Size of the mapping in bytes
              * @param mode Mapping mode: readonly, or writable (shared or private)
@@ -183,8 +185,12 @@ private:
              */
             MemoryMapping(size_t size, mapping_mode mode, int fd=-1, off_t offset=0);
 
-            /// DEPRECATED: For backwards compatibility
-            MemoryMapping(size_t size, bool writable=true, int fd=-1, off_t offset=0) :
+            /**
+             * @deprecated
+             * For backwards compatibility only. Use the constructor taking
+             * a mapping_mode as second argument instead.
+             */
+            OSMIUM_DEPRECATED MemoryMapping(size_t size, bool writable=true, int fd=-1, off_t offset=0) :
                 MemoryMapping(size, writable ? mapping_mode::write_shared : mapping_mode::readonly, fd, offset)  {
             }
 
@@ -232,8 +238,9 @@ private:
              * systems it will unmap and remap the memory. This can only be
              * done for file-based mappings, not anonymous mappings!
              *
-             * @param new_size Number of bytes to resize to
-             * @throws std::system_error if the remapping fails
+             * @param new_size Number of bytes to resize to (must be > 0).
+             *
+             * @throws std::system_error if the remapping fails.
              */
             void resize(size_t new_size);
 
@@ -353,8 +360,12 @@ private:
                 m_mapping(sizeof(T) * size, mode, fd, sizeof(T) * offset) {
             }
 
-            /// DEPRECATED: For backwards compatibility
-            TypedMemoryMapping(size_t size, bool writable, int fd, off_t offset = 0) :
+            /**
+             * @deprecated
+             * For backwards compatibility only. Use the constructor taking
+             * a mapping_mode as second argument instead.
+             */
+            OSMIUM_DEPRECATED TypedMemoryMapping(size_t size, bool writable, int fd, off_t offset = 0) :
                 m_mapping(sizeof(T) * size, writable ? MemoryMapping::mapping_mode::write_shared : MemoryMapping::mapping_mode::readonly, fd, sizeof(T) * offset) {
             }
 
diff --git a/include/osmium/util/options.hpp b/include/osmium/util/options.hpp
index 24c0918..1019c8b 100644
--- a/include/osmium/util/options.hpp
+++ b/include/osmium/util/options.hpp
@@ -47,46 +47,65 @@ namespace osmium {
          * as a base class. Options are stored and retrieved by key using the
          * different set() and get() methods.
          *
+         * Both keys and values are stored as strings. The values "true",
+         * "yes", "false", and "no" are interpreted as boolean values in some
+         * functions.
+         *
          * You can iterate over all set options. Dereferencing an iterator
          * yields a std::pair of the key and value strings.
          */
         class Options {
 
-            typedef std::map<std::string, std::string> option_map;
+            using option_map = std::map<std::string, std::string>;
             option_map m_options;
 
         public:
 
-            typedef option_map::iterator iterator;
-            typedef option_map::const_iterator const_iterator;
-            typedef option_map::value_type value_type;
+            using iterator = option_map::iterator;
+            using const_iterator = option_map::const_iterator;
+            using value_type = option_map::value_type;
 
+            /**
+             * Construct empty option set.
+             */
             Options() = default;
 
+            /**
+             * Construct option set from initializer list:
+             * @code
+             *   Options options{ { "foo", "true" }, { "bar", "17" } };
+             * @endcode
+             */
             explicit Options(const std::initializer_list<value_type>& values) :
                 m_options(values) {
             }
 
-            Options(const Options&) = default;
-            Options& operator=(const Options&) = default;
-
-            Options(Options&&) = default;
-            Options& operator=(Options&&) = default;
-
-            ~Options() = default;
-
+            /**
+             * Set option 'key' to 'value'.
+             */
             void set(const std::string& key, const std::string& value) {
                 m_options[key] = value;
             }
 
+            /**
+             * Set option 'key' to 'value'.
+             */
             void set(const std::string& key, const char* value) {
                 m_options[key] = value;
             }
 
+            /**
+             * Set option 'key' to 'value'.
+             */
             void set(const std::string& key, bool value) {
                 m_options[key] = value ? "true" : "false";
             }
 
+            /**
+             * Set option from string in the form 'key=value'. If the string
+             * contains no equal sign, the whole string is the key and it will
+             * be set to "true".
+             */
             void set(std::string data) {
                 size_t pos = data.find_first_of('=');
                 if (pos == std::string::npos) {
@@ -99,7 +118,7 @@ namespace osmium {
             }
 
             /**
-             * Get value of "key" option. If not set the default_value (or
+             * Get value of "key" option. If not set, the default_value (or
              * empty string) is returned.
              */
             std::string get(const std::string& key, const std::string& default_value="") const noexcept {
@@ -128,30 +147,51 @@ namespace osmium {
                 return !(value == "false" || value == "no");
             }
 
+            /**
+             * The number of options set.
+             */
             size_t size() const noexcept {
                 return m_options.size();
             }
 
+            /**
+             * Returns an iterator to the beginning.
+             */
             iterator begin() noexcept {
                 return m_options.begin();
             }
 
+            /**
+             * Returns an iterator to the end.
+             */
             iterator end() noexcept {
                 return m_options.end();
             }
 
+            /**
+             * Returns an iterator to the beginning.
+             */
             const_iterator begin() const noexcept {
                 return m_options.cbegin();
             }
 
+            /**
+             * Returns an iterator to the end.
+             */
             const_iterator end() const noexcept {
                 return m_options.cend();
             }
 
+            /**
+             * Returns an iterator to the beginning.
+             */
             const_iterator cbegin() const noexcept {
                 return m_options.cbegin();
             }
 
+            /**
+             * Returns a iterator to the end.
+             */
             const_iterator cend() const noexcept {
                 return m_options.cend();
             }
diff --git a/include/osmium/visitor.hpp b/include/osmium/visitor.hpp
index 35fcb4e..48ce45d 100644
--- a/include/osmium/visitor.hpp
+++ b/include/osmium/visitor.hpp
@@ -35,6 +35,7 @@ DEALINGS IN THE SOFTWARE.
 
 #include <type_traits>
 
+#include <osmium/fwd.hpp>
 #include <osmium/io/reader_iterator.hpp> // IWYU pragma: keep
 #include <osmium/memory/buffer.hpp>
 #include <osmium/osm.hpp>
@@ -43,12 +44,6 @@ DEALINGS IN THE SOFTWARE.
 
 namespace osmium {
 
-    class TagList;
-    class WayNodeList;
-    class RelationMemberList;
-    class OuterRing;
-    class InnerRing;
-
     namespace memory {
         class Item;
     }
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index b9f02ee..f574161 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -151,7 +151,6 @@ add_unit_test(tags test_tag_list)
 add_unit_test(thread test_pool ENABLE_IF ${Threads_FOUND} LIBS ${CMAKE_THREAD_LIBS_INIT})
 
 add_unit_test(util test_cast_with_assert)
-add_unit_test(util test_data_file)
 add_unit_test(util test_delta)
 add_unit_test(util test_double)
 add_unit_test(util test_file)
diff --git a/test/t/basic/test_object_comparisons.cpp b/test/t/basic/test_object_comparisons.cpp
index 2bfdcad..ec9e6fa 100644
--- a/test/t/basic/test_object_comparisons.cpp
+++ b/test/t/basic/test_object_comparisons.cpp
@@ -31,20 +31,20 @@ TEST_CASE("Object_Comparisons") {
         node1.set_version(1);
         node2.set_id(15);
         node2.set_version(2);
-        REQUIRE(true == (node1 < node2));
-        REQUIRE(false == (node1 > node2));
+        REQUIRE(node1 < node2);
+        REQUIRE_FALSE(node1 > node2);
         node1.set_id(20);
         node1.set_version(1);
         node2.set_id(20);
         node2.set_version(2);
-        REQUIRE(true == (node1 < node2));
-        REQUIRE(false == (node1 > node2));
+        REQUIRE(node1 < node2);
+        REQUIRE_FALSE(node1 > node2);
         node1.set_id(-10);
         node1.set_version(2);
         node2.set_id(-15);
         node2.set_version(1);
-        REQUIRE(true == (node1 < node2));
-        REQUIRE(false == (node1 > node2));
+        REQUIRE(node1 < node2);
+        REQUIRE_FALSE(node1 > node2);
     }
 
     SECTION("order_types") {
@@ -122,26 +122,26 @@ TEST_CASE("Object_Comparisons") {
         const osmium::Way& way = static_cast<const osmium::Way&>(*(++it));
         const osmium::Relation& relation = static_cast<const osmium::Relation&>(*(++it));
 
-        REQUIRE(true == (node1 < node2));
-        REQUIRE(true == (node2 < way));
-        REQUIRE(false == (node2 > way));
-        REQUIRE(true == (way < relation));
-        REQUIRE(true == (node1 < relation));
+        REQUIRE(node1 < node2);
+        REQUIRE(node2 < way);
+        REQUIRE_FALSE(node2 > way);
+        REQUIRE(way < relation);
+        REQUIRE(node1 < relation);
 
-        REQUIRE(true == osmium::object_order_type_id_version()(node1, node2));
-        REQUIRE(true == osmium::object_order_type_id_reverse_version()(node2, node1));
-        REQUIRE(true == osmium::object_order_type_id_version()(node1, way));
-        REQUIRE(true == osmium::object_order_type_id_reverse_version()(node1, way));
+        REQUIRE(osmium::object_order_type_id_version()(node1, node2));
+        REQUIRE(osmium::object_order_type_id_reverse_version()(node2, node1));
+        REQUIRE(osmium::object_order_type_id_version()(node1, way));
+        REQUIRE(osmium::object_order_type_id_reverse_version()(node1, way));
 
-        REQUIRE(false == osmium::object_equal_type_id_version()(node1, node2));
-        REQUIRE(true == osmium::object_equal_type_id_version()(node2, node3));
+        REQUIRE_FALSE(osmium::object_equal_type_id_version()(node1, node2));
+        REQUIRE(osmium::object_equal_type_id_version()(node2, node3));
 
-        REQUIRE(true == osmium::object_equal_type_id()(node1, node2));
-        REQUIRE(true == osmium::object_equal_type_id()(node2, node3));
+        REQUIRE(osmium::object_equal_type_id()(node1, node2));
+        REQUIRE(osmium::object_equal_type_id()(node2, node3));
 
-        REQUIRE(false == osmium::object_equal_type_id_version()(node1, way));
-        REQUIRE(false == osmium::object_equal_type_id_version()(node1, relation));
-        REQUIRE(false == osmium::object_equal_type_id()(node1, relation));
+        REQUIRE_FALSE(osmium::object_equal_type_id_version()(node1, way));
+        REQUIRE_FALSE(osmium::object_equal_type_id_version()(node1, relation));
+        REQUIRE_FALSE(osmium::object_equal_type_id()(node1, relation));
     }
 
 }
diff --git a/test/t/basic/test_timestamp.cpp b/test/t/basic/test_timestamp.cpp
index f015730..f5c4eba 100644
--- a/test/t/basic/test_timestamp.cpp
+++ b/test/t/basic/test_timestamp.cpp
@@ -10,23 +10,34 @@ TEST_CASE("Timestamp") {
         osmium::Timestamp t;
         REQUIRE(0 == 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("" == 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("1970-01-01T00:00:01Z" == t.to_iso());
+        REQUIRE(t.valid());
     }
 
-    SECTION("can be initialized from string") {
+    SECTION("can be initialized from const char*") {
         osmium::Timestamp t("2000-01-01T00:00:00Z");
         REQUIRE("2000-01-01T00:00:00Z" == t.to_iso());
+        REQUIRE(t.valid());
+    }
+
+    SECTION("can be initialized from string") {
+        std::string s = "2000-01-01T00:00:00Z";
+        osmium::Timestamp t(s);
+        REQUIRE("2000-01-01T00:00:00Z" == t.to_iso());
+        REQUIRE(t.valid());
     }
 
     SECTION("throws if initialized from bad string") {
@@ -50,6 +61,10 @@ TEST_CASE("Timestamp") {
         osmium::Timestamp t1(10);
         osmium::Timestamp t2(50);
         REQUIRE(t1 < t2);
+        REQUIRE(t1 > osmium::start_of_time());
+        REQUIRE(t2 > osmium::start_of_time());
+        REQUIRE(t1 < osmium::end_of_time());
+        REQUIRE(t2 < osmium::end_of_time());
     }
 
     SECTION("can be written to stream") {
diff --git a/test/t/buffer/test_buffer_node.cpp b/test/t/buffer/test_buffer_node.cpp
index 9bc8f70..e985009 100644
--- a/test/t/buffer/test_buffer_node.cpp
+++ b/test/t/buffer/test_buffer_node.cpp
@@ -56,13 +56,14 @@ void check_node_2(osmium::Node& node) {
     REQUIRE(2 == n);
 }
 
-TEST_CASE("Buffer_Node") {
+TEST_CASE("Node in Buffer") {
 
-    SECTION("buffer_node") {
-        constexpr size_t buffer_size = 10000;
-        unsigned char data[buffer_size];
+    constexpr size_t buffer_size = 10000;
+    unsigned char data[buffer_size];
 
-        osmium::memory::Buffer buffer(data, buffer_size, 0);
+    osmium::memory::Buffer buffer(data, buffer_size, 0);
+
+    SECTION("Add node to buffer") {
 
         {
             // add node 1
@@ -132,4 +133,37 @@ TEST_CASE("Buffer_Node") {
 
     }
 
+    SECTION("Add buffer to another one") {
+
+        {
+            // 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);
+
+        buffer2.add_buffer(buffer);
+        buffer2.commit();
+
+        REQUIRE(buffer.committed() == buffer2.committed());
+        const osmium::Node& node = buffer2.get<osmium::Node>(0);
+        REQUIRE(node.id() == 1);
+        REQUIRE(node.timestamp() == 123);
+    }
+
 }
+
diff --git a/test/t/util/test_data_file.cpp b/test/t/util/test_data_file.cpp
deleted file mode 100644
index 792cedf..0000000
--- a/test/t/util/test_data_file.cpp
+++ /dev/null
@@ -1,81 +0,0 @@
-#include "catch.hpp"
-
-#include <cstring>
-
-#include <osmium/util/data_file.hpp>
-
-TEST_CASE("temporary file") {
-
-    SECTION("create/open") {
-        osmium::util::DataFile file;
-
-        REQUIRE(!!file);
-        int fd = file.fd();
-
-        REQUIRE(fd > 0);
-
-        const char buf[] = "foobar";
-        REQUIRE(::write(fd, buf, sizeof(buf)) == sizeof(buf));
-
-        file.close();
-
-        REQUIRE(!file);
-    }
-
-}
-
-TEST_CASE("named file") {
-
-    SECTION("create/open") {
-        {
-            osmium::util::DataFile file("test.data", true);
-
-            REQUIRE(!!file);
-            int fd = file.fd();
-
-            REQUIRE(fd > 0);
-
-            REQUIRE(file.size() == 0);
-
-            const char buf[] = "foobar";
-            REQUIRE(::write(fd, buf, sizeof(buf) - 1) == sizeof(buf) - 1);
-
-            file.close();
-
-            REQUIRE(!file);
-        }
-        {
-            osmium::util::DataFile file("test.data", false);
-
-            REQUIRE(!!file);
-            int fd = file.fd();
-
-            REQUIRE(fd > 0);
-
-            REQUIRE(file.size() == 6);
-
-            char buf[10];
-            auto len = ::read(fd, buf, sizeof(buf));
-
-            REQUIRE(len == 6);
-            REQUIRE(!strncmp(buf, "foobar", 6));
-
-            file.close();
-
-            REQUIRE(!file);
-            REQUIRE(unlink("test.data") == 0);
-        }
-    }
-
-    SECTION("grow file") {
-        osmium::util::DataFile file("test.data", true);
-
-        REQUIRE(!!file);
-
-        REQUIRE(file.size() == 0);
-        file.grow(10);
-        REQUIRE(file.size() == 10);
-    }
-
-}
-
diff --git a/test/t/util/test_options.cpp b/test/t/util/test_options.cpp
index c1e13bd..8cba095 100644
--- a/test/t/util/test_options.cpp
+++ b/test/t/util/test_options.cpp
@@ -8,7 +8,7 @@ TEST_CASE("Options") {
 
     osmium::util::Options o;
 
-    SECTION("set_simple") {
+    SECTION("set a single value from string") {
         o.set("foo", "bar");
         REQUIRE("bar" == o.get("foo"));
         REQUIRE("" == o.get("empty"));
@@ -23,7 +23,7 @@ TEST_CASE("Options") {
         REQUIRE(1 == o.size());
     }
 
-    SECTION("set_from_bool") {
+    SECTION("set values from booleans") {
         o.set("t", true);
         o.set("f", false);
         REQUIRE("true" == o.get("t"));
@@ -39,13 +39,13 @@ TEST_CASE("Options") {
         REQUIRE(2 == o.size());
     }
 
-    SECTION("set_from_single_string_with_equals") {
+    SECTION("set value from string with equal sign") {
         o.set("foo=bar");
         REQUIRE("bar" == o.get("foo"));
         REQUIRE(1 == o.size());
     }
 
-    SECTION("set_from_single_string_without_equals") {
+    SECTION("set value from string without equal sign") {
         o.set("foo");
         REQUIRE("true" == o.get("foo"));
 
@@ -57,3 +57,25 @@ TEST_CASE("Options") {
 
 }
 
+TEST_CASE("Options with initializer list") {
+
+    osmium::util::Options o{ { "foo", "true" }, { "bar", "17" } };
+
+    REQUIRE(o.get("foo") == "true");
+    REQUIRE(o.get("bar") == "17");
+    REQUIRE(o.is_true("foo"));
+    REQUIRE_FALSE(o.is_true("bar"));
+    REQUIRE(o.size() == 2);
+
+    SECTION("Change existing value") {
+        o.set("foo", "false");
+        REQUIRE_FALSE(o.is_true("foo"));
+    }
+
+    SECTION("Add new value") {
+        o.set("new", "something");
+        REQUIRE_FALSE(o.is_true("new"));
+        REQUIRE(o.get("new") == "something");
+    }
+}
+

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