[Git][debian-gis-team/libosmium][upstream] New upstream version 2.22.0

Bas Couwenberg (@sebastic) gitlab at salsa.debian.org
Tue Mar 18 04:26:03 GMT 2025



Bas Couwenberg pushed to branch upstream at Debian GIS Project / libosmium


Commits:
23fb18dc by Bas Couwenberg at 2025-03-18T05:17:26+01:00
New upstream version 2.22.0
- - - - -


22 changed files:

- CHANGELOG.md
- CMakeLists.txt
- NOTES_FOR_DEVELOPERS.md
- examples/osmium_dump_internal.cpp
- include/osmium/area/detail/segment_list.hpp
- include/osmium/index/relations_map.hpp
- include/osmium/io/detail/read_thread.hpp
- include/osmium/io/detail/xml_input_format.hpp
- include/osmium/io/reader.hpp
- include/osmium/io/writer.hpp
- include/osmium/relations/members_database.hpp
- include/osmium/relations/relations_database.hpp
- − include/osmium/tags/regex_filter.hpp
- include/osmium/util/progress_bar.hpp
- include/osmium/util/string_matcher.hpp
- include/osmium/version.hpp
- include/osmium/visitor.hpp
- test/t/index/test_relations_map.cpp
- test/t/io/test_reader.cpp
- test/t/tags/test_filter.cpp
- test/t/tags/test_tags_filter.cpp
- test/t/util/test_string_matcher.cpp


Changes:

=====================================
CHANGELOG.md
=====================================
@@ -13,6 +13,19 @@ This project adheres to [Semantic Versioning](https://semver.org/).
 ### Fixed
 
 
+## [2.22.0] - 2025-03-17
+
+### Changed
+
+* Extend RelationsMapIndex to work with 64bit IDs. This should not change
+  anything for typical OSM use (where relation IDs fit in 32bit), but help
+  with users adding their own relations.
+* Removed deprecated support for regexes from osmium::tags::Filter, use
+  osmium::TagsFilter instead (`osmium/tags/regex_filter.hpp` removed).
+* Remove special cases disabling regex support for old C++ libs.
+* Various code cleanups.
+
+
 ## [2.21.0] - 2025-01-13
 
 ### Changed
@@ -1304,7 +1317,8 @@ long time. These will not be part of the next version of libosmium:
   Doxygen (up to version 1.8.8). This version contains a workaround to fix
   this.
 
-[unreleased]: https://github.com/osmcode/libosmium/compare/v2.21.0...HEAD
+[unreleased]: https://github.com/osmcode/libosmium/compare/v2.22.0...HEAD
+[2.22.0]: https://github.com/osmcode/libosmium/compare/v2.21.0...v2.22.0
 [2.21.0]: https://github.com/osmcode/libosmium/compare/v2.20.0...v2.21.0
 [2.20.0]: https://github.com/osmcode/libosmium/compare/v2.19.0...v2.20.0
 [2.19.0]: https://github.com/osmcode/libosmium/compare/v2.18.9...v2.19.0


=====================================
CMakeLists.txt
=====================================
@@ -39,7 +39,7 @@ set(CMAKE_CONFIGURATION_TYPES "Debug;Release;RelWithDebInfo;MinSizeRel;Dev;Cover
 project(libosmium)
 
 set(LIBOSMIUM_VERSION_MAJOR 2)
-set(LIBOSMIUM_VERSION_MINOR 21)
+set(LIBOSMIUM_VERSION_MINOR 22)
 set(LIBOSMIUM_VERSION_PATCH 0)
 
 set(LIBOSMIUM_VERSION


=====================================
NOTES_FOR_DEVELOPERS.md
=====================================
@@ -14,7 +14,7 @@ All Osmium code MUST be in the `osmium` namespace or one of its sub-namespaces.
 Osmium is a include-only library. You can't compile the library itself. There
 is no `libosmium.so` or `libosmium.dll`.
 
-One drawback ist that you can't have static data in classes, because there
+One drawback is that you can't have static data in classes, because there
 is no place to put this data.
 
 All free functions must be declared `inline`.


=====================================
examples/osmium_dump_internal.cpp
=====================================
@@ -33,9 +33,9 @@
 #include <exception>
 #include <iostream>    // for std::cout, std::cerr
 #include <string>      // for std::string
-#include <system_error>
 #include <sys/stat.h>  // for open
 #include <sys/types.h> // for open
+#include <system_error>
 
 #ifdef _WIN32
 # include <io.h>       // for _setmode


=====================================
include/osmium/area/detail/segment_list.hpp
=====================================
@@ -50,6 +50,7 @@ DEALINGS IN THE SOFTWARE.
 #include <iterator>
 #include <numeric>
 #include <unordered_set>
+#include <utility>
 #include <vector>
 
 namespace osmium {
@@ -64,13 +65,13 @@ namespace osmium {
              * way as parameter. This takes into account that there might be
              * non-way members in the relation.
              */
-            template <typename F>
-            inline void for_each_member(const osmium::Relation& relation, const std::vector<const osmium::Way*>& ways, F&& func) {
+            template <typename TFunc>
+            inline void for_each_member(const osmium::Relation& relation, const std::vector<const osmium::Way*>& ways, TFunc&& func) {
                 auto way_it = ways.cbegin();
                 for (const osmium::RelationMember& member : relation.members()) {
                     if (member.type() == osmium::item_type::way) {
                         assert(way_it != ways.cend());
-                        func(member, **way_it);
+                        std::forward<TFunc>(func)(member, **way_it);
                         ++way_it;
                     }
                 }


=====================================
include/osmium/index/relations_map.hpp
=====================================
@@ -41,6 +41,7 @@ DEALINGS IN THE SOFTWARE.
 #include <cassert>
 #include <cstddef>
 #include <cstdint>
+#include <limits>
 #include <tuple>
 #include <type_traits>
 #include <utility>
@@ -137,8 +138,25 @@ namespace osmium {
                     m_map.reserve(size);
                 }
 
+                void clear() {
+                    m_map.clear();
+                    m_map.shrink_to_fit();
+                }
+
+                typename std::vector<kv_pair>::const_iterator begin() const noexcept {
+                    return m_map.cbegin();
+                }
+
+                typename std::vector<kv_pair>::const_iterator end() const noexcept {
+                    return m_map.cend();
+                }
+
             }; // class flat_map
 
+            template <typename VType>
+            using rel_index_map_type = detail::flat_map<osmium::unsigned_object_id_type, VType,
+                                                        osmium::unsigned_object_id_type, VType>;
+
         } // namespace detail
 
         /**
@@ -171,13 +189,17 @@ namespace osmium {
             friend class RelationsMapStash;
             friend class RelationsMapIndexes;
 
-            using map_type = detail::flat_map<osmium::unsigned_object_id_type, uint32_t,
-                                              osmium::unsigned_object_id_type, uint32_t>;
+            detail::rel_index_map_type<uint32_t> m_map32;
+            detail::rel_index_map_type<uint64_t> m_map64;
 
-            map_type m_map;
+            bool m_small;
 
-            explicit RelationsMapIndex(map_type&& map) :
-                m_map(std::move(map)) {
+            explicit RelationsMapIndex(detail::rel_index_map_type<uint32_t>&& map) :
+                m_map32(std::move(map)), m_small(true) {
+            }
+
+            explicit RelationsMapIndex(detail::rel_index_map_type<uint64_t>&& map) :
+                m_map64(std::move(map)), m_small(false) {
             }
 
         public:
@@ -187,35 +209,11 @@ namespace osmium {
             RelationsMapIndex(const RelationsMapIndex&) = delete;
             RelationsMapIndex& operator=(const RelationsMapIndex&) = delete;
 
-            RelationsMapIndex(RelationsMapIndex&& /*other*/) noexcept(std::is_nothrow_move_constructible<map_type>::value);
-            RelationsMapIndex& operator=(RelationsMapIndex&& /*other*/) noexcept(std::is_nothrow_move_assignable<map_type>::value);
+            RelationsMapIndex(RelationsMapIndex&& /*other*/) noexcept;
+            RelationsMapIndex& operator=(RelationsMapIndex&& /*other*/) noexcept;
 
             ~RelationsMapIndex() noexcept = default;
 
-            /**
-             * Find the given relation id in the index and call the given
-             * function with all parent relation ids.
-             *
-             * @code
-             * osmium::unsigned_object_id_type member_id = 17;
-             * index.for_each_parent(member_id, [](osmium::unsigned_object_id_type id) {
-             *   ...
-             * });
-             * @endcode
-             *
-             * @deprecated Use for_each() instead.
-             *
-             * Complexity: Logarithmic in the number of elements in the index.
-             *             (Lookup uses binary search.)
-             */
-            template <typename TFunc>
-            void for_each_parent(const osmium::unsigned_object_id_type member_id, TFunc&& func) const {
-                const auto parents = m_map.get(member_id);
-                for (auto it = parents.first; it != parents.second; ++it) {
-                    func(it->value);
-                }
-            }
-
             /**
              * Find the given relation id in the index and call the given
              * function with all related relation ids.
@@ -232,9 +230,16 @@ namespace osmium {
              */
             template <typename TFunc>
             void for_each(const osmium::unsigned_object_id_type id, TFunc&& func) const {
-                const auto parents = m_map.get(id);
-                for (auto it = parents.first; it != parents.second; ++it) {
-                    func(it->value);
+                if (m_small) {
+                    const auto parents = m_map32.get(id);
+                    for (auto it = parents.first; it != parents.second; ++it) {
+                        std::forward<TFunc>(func)(it->value);
+                    }
+                } else {
+                    const auto parents = m_map64.get(id);
+                    for (auto it = parents.first; it != parents.second; ++it) {
+                        std::forward<TFunc>(func)(it->value);
+                    }
                 }
             }
 
@@ -244,7 +249,7 @@ namespace osmium {
              * Complexity: Constant.
              */
             bool empty() const noexcept {
-                return m_map.empty();
+                return m_small ? m_map32.empty() : m_map64.empty();
             }
 
             /**
@@ -253,15 +258,15 @@ namespace osmium {
              * Complexity: Constant.
              */
             std::size_t size() const noexcept {
-                return m_map.size();
+                return m_small ? m_map32.size() : m_map64.size();
             }
 
         }; // class RelationsMapIndex
 
         // defined outside the class on purpose
         // see https://akrzemi1.wordpress.com/2015/09/11/declaring-the-move-constructor/
-        inline RelationsMapIndex::RelationsMapIndex(RelationsMapIndex&&) noexcept(std::is_nothrow_move_constructible<map_type>::value) = default; // NOLINT(readability-redundant-inline-specifier)
-        inline RelationsMapIndex& RelationsMapIndex::operator=(RelationsMapIndex&&) noexcept(std::is_nothrow_move_assignable<map_type>::value) = default; // NOLINT(readability-redundant-inline-specifier)
+        inline RelationsMapIndex::RelationsMapIndex(RelationsMapIndex&&) noexcept = default; // NOLINT(readability-redundant-inline-specifier)
+        inline RelationsMapIndex& RelationsMapIndex::operator=(RelationsMapIndex&&) noexcept = default; // NOLINT(readability-redundant-inline-specifier)
 
         class RelationsMapIndexes {
 
@@ -270,7 +275,12 @@ namespace osmium {
             RelationsMapIndex m_member_to_parent;
             RelationsMapIndex m_parent_to_member;
 
-            RelationsMapIndexes(RelationsMapIndex::map_type&& map1, RelationsMapIndex::map_type&& map2) :
+            RelationsMapIndexes(detail::rel_index_map_type<uint32_t>&& map1, detail::rel_index_map_type<uint32_t>&& map2) :
+                m_member_to_parent(std::move(map1)),
+                m_parent_to_member(std::move(map2)) {
+            }
+
+            RelationsMapIndexes(detail::rel_index_map_type<uint64_t>&& map1, detail::rel_index_map_type<uint64_t>&& map2) :
                 m_member_to_parent(std::move(map1)),
                 m_parent_to_member(std::move(map2)) {
             }
@@ -312,15 +322,23 @@ namespace osmium {
          */
         class RelationsMapStash {
 
-            using map_type = detail::flat_map<osmium::unsigned_object_id_type, uint32_t,
-                                              osmium::unsigned_object_id_type, uint32_t>;
-
-            map_type m_map;
+            detail::rel_index_map_type<uint32_t> m_map32;
+            detail::rel_index_map_type<uint64_t> m_map64;
 
 #ifndef NDEBUG
             bool m_valid = true;
 #endif
 
+            static void append32to64(detail::rel_index_map_type<uint32_t>& map32, detail::rel_index_map_type<uint64_t>& map64) {
+                map64.sort_unique();
+                map64.reserve(map64.size() + map32.size());
+                for (const auto& item : map32) {
+                    map64.set(item.key, item.value);
+                }
+                map64.sort_unique();
+                map32.clear();
+            }
+
         public:
 
             RelationsMapStash() = default;
@@ -328,8 +346,8 @@ namespace osmium {
             RelationsMapStash(const RelationsMapStash&) = delete;
             RelationsMapStash& operator=(const RelationsMapStash&) = delete;
 
-            RelationsMapStash(RelationsMapStash&& /*other*/) noexcept(std::is_nothrow_move_constructible<map_type>::value);
-            RelationsMapStash& operator=(RelationsMapStash&& /*other*/) noexcept(std::is_nothrow_move_assignable<map_type>::value);
+            RelationsMapStash(RelationsMapStash&& /*other*/) noexcept;
+            RelationsMapStash& operator=(RelationsMapStash&& /*other*/) noexcept;
 
             ~RelationsMapStash() noexcept = default;
 
@@ -338,7 +356,12 @@ namespace osmium {
              */
             void add(const osmium::unsigned_object_id_type member_id, const osmium::unsigned_object_id_type relation_id) {
                 assert(m_valid && "You can't use the RelationsMap any more after calling build_index()");
-                m_map.set(member_id, relation_id);
+                constexpr const osmium::unsigned_object_id_type max32 = std::numeric_limits<uint32_t>::max();
+                if (member_id <= max32 && relation_id <= max32) {
+                    m_map32.set(member_id, relation_id);
+                } else {
+                    m_map64.set(member_id, relation_id);
+                }
             }
 
             /**
@@ -348,7 +371,7 @@ namespace osmium {
                 assert(m_valid && "You can't use the RelationsMap any more after calling build_index()");
                 for (const auto& member : relation.members()) {
                     if (member.type() == osmium::item_type::relation) {
-                        m_map.set(member.positive_ref(), relation.positive_id());
+                        add(member.positive_ref(), relation.positive_id());
                     }
                 }
             }
@@ -360,7 +383,7 @@ namespace osmium {
              */
             bool empty() const noexcept {
                 assert(m_valid && "You can't use the RelationsMap any more after calling build_index()");
-                return m_map.empty();
+                return m_map32.empty() && m_map64.empty();
             }
 
             /**
@@ -370,24 +393,17 @@ namespace osmium {
              */
             std::size_t size() const noexcept {
                 assert(m_valid && "You can't use the RelationsMap any more after calling build_index()");
-                return m_map.size();
+                return m_map32.size() + m_map64.size();
             }
 
             /**
-             * Build an index for member to parent lookups from the contents
-             * of this stash and return it.
+             * How many "small" and "large" entries are in this stash?
+             * For tests and debugging only!
              *
-             * After you get the index you can not use the stash any more!
-             *
-             * @deprecated Use build_member_to_parent_index() instead.
+             * Complexity: Constant.
              */
-            RelationsMapIndex build_index() {
-                assert(m_valid && "You can't use the RelationsMap any more after calling build_index()");
-                m_map.sort_unique();
-#ifndef NDEBUG
-                m_valid = false;
-#endif
-                return RelationsMapIndex{std::move(m_map)};
+            std::pair<std::size_t, std::size_t> sizes() const noexcept {
+                return std::make_pair(m_map32.size(), m_map64.size());
             }
 
             /**
@@ -398,11 +414,17 @@ namespace osmium {
              */
             RelationsMapIndex build_member_to_parent_index() {
                 assert(m_valid && "You can't use the RelationsMap any more after calling build_member_to_parent_index()");
-                m_map.sort_unique();
 #ifndef NDEBUG
                 m_valid = false;
 #endif
-                return RelationsMapIndex{std::move(m_map)};
+                m_map32.sort_unique();
+                if (m_map64.empty()) {
+                    return RelationsMapIndex{std::move(m_map32)};
+                }
+
+                append32to64(m_map32, m_map64);
+
+                return RelationsMapIndex{std::move(m_map64)};
             }
 
             /**
@@ -413,12 +435,19 @@ namespace osmium {
              */
             RelationsMapIndex build_parent_to_member_index() {
                 assert(m_valid && "You can't use the RelationsMap any more after calling build_parent_to_member_index()");
-                m_map.flip_in_place();
-                m_map.sort_unique();
 #ifndef NDEBUG
                 m_valid = false;
 #endif
-                return RelationsMapIndex{std::move(m_map)};
+                m_map32.flip_in_place();
+                m_map32.sort_unique();
+                if (m_map64.empty()) {
+                    return RelationsMapIndex{std::move(m_map32)};
+                }
+
+                m_map64.flip_in_place();
+                append32to64(m_map32, m_map64);
+
+                return RelationsMapIndex{std::move(m_map64)};
             }
 
             /**
@@ -429,21 +458,29 @@ namespace osmium {
              */
             RelationsMapIndexes build_indexes() {
                 assert(m_valid && "You can't use the RelationsMap any more after calling build_indexes()");
-                auto reverse_map = m_map.flip_copy();
-                reverse_map.sort_unique();
-                m_map.sort_unique();
 #ifndef NDEBUG
                 m_valid = false;
 #endif
-                return RelationsMapIndexes{std::move(m_map), std::move(reverse_map)};
+                auto reverse_map32 = m_map32.flip_copy();
+                reverse_map32.sort_unique();
+                m_map32.sort_unique();
+                if (m_map64.empty()) {
+                    return RelationsMapIndexes{std::move(m_map32), std::move(reverse_map32)};
+                }
+
+                auto reverse_map64 = m_map64.flip_copy();
+                append32to64(reverse_map32, reverse_map64);
+                append32to64(m_map32, m_map64);
+
+                return RelationsMapIndexes{std::move(m_map64), std::move(reverse_map64)};
             }
 
         }; // class RelationsMapStash
 
         // defined outside the class on purpose
         // see https://akrzemi1.wordpress.com/2015/09/11/declaring-the-move-constructor/
-        inline RelationsMapStash::RelationsMapStash(RelationsMapStash&&) noexcept(std::is_nothrow_move_constructible<map_type>::value) = default; // NOLINT(readability-redundant-inline-specifier)
-        inline RelationsMapStash& RelationsMapStash::operator=(RelationsMapStash&&) noexcept(std::is_nothrow_move_assignable<map_type>::value) = default; // NOLINT(readability-redundant-inline-specifier)
+        inline RelationsMapStash::RelationsMapStash(RelationsMapStash&&) noexcept = default; // NOLINT(readability-redundant-inline-specifier)
+        inline RelationsMapStash& RelationsMapStash::operator=(RelationsMapStash&&) noexcept = default; // NOLINT(readability-redundant-inline-specifier)
 
     } // namespace index
 


=====================================
include/osmium/io/detail/read_thread.hpp
=====================================
@@ -106,7 +106,7 @@ namespace osmium {
                 ~ReadThreadManager() noexcept {
                     try {
                         close();
-                    } catch (...) {
+                    } catch (...) { // NOLINT(bugprone-empty-catch)
                         // Ignore any exceptions because destructor must not throw.
                     }
                 }


=====================================
include/osmium/io/detail/xml_input_format.hpp
=====================================
@@ -179,7 +179,7 @@ namespace osmium {
                             return;
                         }
                         try {
-                            func(xml_parser);
+                            std::forward<TFunc>(func)(xml_parser);
                         } catch (...) {
                             m_exception_ptr = std::current_exception();
                             XML_StopParser(m_parser, 0);
@@ -267,10 +267,10 @@ namespace osmium {
 
                 ExpatXMLParser* m_expat_xml_parser{nullptr};
 
-                template <typename T>
-                static void check_attributes(const XML_Char** attrs, T&& check) {
+                template <typename TFunc>
+                static void check_attributes(const XML_Char** attrs, TFunc&& check) {
                     while (*attrs) {
-                        check(attrs[0], attrs[1]);
+                        std::forward<TFunc>(check)(attrs[0], attrs[1]);
                         attrs += 2;
                     }
                 }


=====================================
include/osmium/io/reader.hpp
=====================================
@@ -327,7 +327,7 @@ namespace osmium {
                 m_osmdata_queue(detail::get_osmdata_queue_size(), "parser_results"),
                 m_osmdata_queue_wrapper(m_osmdata_queue) {
 
-                (void)std::initializer_list<int>{(set_option(args), 0)...};
+                (void)std::initializer_list<int>{(set_option(std::forward<TArgs>(args)), 0)...};
 
                 if (!m_pool) {
                     m_pool = &thread::Pool::default_instance();
@@ -390,7 +390,7 @@ namespace osmium {
 
                 try {
                     m_read_thread_manager.close();
-                } catch (...) {
+                } catch (...) { // NOLINT(bugprone-empty-catch)
                     // Ignore any exceptions.
                 }
 


=====================================
include/osmium/io/writer.hpp
=====================================
@@ -269,7 +269,7 @@ namespace osmium {
                 assert(!m_file.buffer()); // XXX can't handle pseudo-files
 
                 options_type options;
-                (void)std::initializer_list<int>{(set_option(options, args), 0)...};
+                (void)std::initializer_list<int>{(set_option(options, std::forward<TArgs>(args)), 0)...};
 
                 if (!options.pool) {
                     options.pool = &thread::Pool::default_instance();


=====================================
include/osmium/relations/members_database.hpp
=====================================
@@ -46,6 +46,7 @@ DEALINGS IN THE SOFTWARE.
 #include <limits>
 #include <tuple>
 #include <type_traits>
+#include <utility>
 #include <vector>
 
 namespace osmium {
@@ -384,7 +385,7 @@ namespace osmium {
                     rel_handle.decrement_members();
 
                     if (rel_handle.has_all_members()) {
-                        func(rel_handle);
+                        std::forward<TFunc>(func)(rel_handle);
                     }
                 }
 


=====================================
include/osmium/relations/relations_database.hpp
=====================================
@@ -323,7 +323,7 @@ namespace osmium {
         void RelationsDatabase::for_each_relation(TFunc&& func) {
             for (std::size_t pos = 0; pos < m_elements.size(); ++pos) {
                 if (m_elements[pos].handle.valid()) {
-                    func(RelationHandle{this, pos});
+                    std::forward<TFunc>(func)(RelationHandle{this, pos});
                 }
             }
         }


=====================================
include/osmium/tags/regex_filter.hpp deleted
=====================================
@@ -1,66 +0,0 @@
-#ifndef OSMIUM_TAGS_REGEX_FILTER_HPP
-#define OSMIUM_TAGS_REGEX_FILTER_HPP
-
-/*
-
-This file is part of Osmium (https://osmcode.org/libosmium).
-
-Copyright 2013-2025 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 <osmium/tags/filter.hpp>
-
-#include <regex>
-#include <string>
-
-namespace osmium {
-
-    namespace tags {
-
-        template <>
-        struct match_key<std::regex> {
-            bool operator()(const std::regex& rule_key, const char* tag_key) const {
-                return std::regex_match(tag_key, rule_key);
-            }
-        }; // struct match_key<std::regex>
-
-        template <>
-        struct match_value<std::regex> {
-            bool operator()(const std::regex& rule_value, const char* tag_value) const {
-                return std::regex_match(tag_value, rule_value);
-            }
-        }; // struct match_value<std::regex>
-
-        /// @deprecated Use osmium::TagsFilter instead.
-        using RegexFilter = Filter<std::string, std::regex>;
-
-    } // namespace tags
-
-} // namespace osmium
-
-#endif // OSMIUM_TAGS_REGEX_FILTER_HPP


=====================================
include/osmium/util/progress_bar.hpp
=====================================
@@ -132,7 +132,7 @@ namespace osmium {
             if (m_do_cleanup) {
                 try {
                     done();
-                } catch (...) {
+                } catch (...) { // NOLINT(bugprone-empty-catch)
                     // Swallow any exceptions, because a destructor should
                     // not throw.
                 }


=====================================
include/osmium/util/string_matcher.hpp
=====================================
@@ -54,30 +54,6 @@ DEALINGS IN THE SOFTWARE.
 # include <boost/variant.hpp>
 #endif
 
-
-// std::regex isn't implemented properly in glibc++ (before the version
-// delivered with GCC 4.9) and libc++ before the version 3.6, so the use is
-// disabled by these checks. Checks for GLIBC were based on
-// https://stackoverflow.com/questions/12530406/is-gcc-4-8-or-earlier-buggy-about-regular-expressions
-// Checks for libc++ are simply based on compiler defines. This is probably
-// not optimal but seems to work for now.
-#if defined(__GLIBCXX__)
-# if ((__cplusplus >= 201402L) || \
-        defined(_GLIBCXX_REGEX_DFS_QUANTIFIERS_LIMIT) || \
-        defined(_GLIBCXX_REGEX_STATE_LIMIT))
-#  define OSMIUM_WITH_REGEX
-# else
-#  pragma message("Disabling regex functionality. See source code for info.")
-# endif
-#elif defined(__clang__)
-# if ((__clang_major__ > 3) || \
-      (__clang_minor__ == 3 && __clang_minor__ > 5))
-#  define OSMIUM_WITH_REGEX
-# else
-#  pragma message("Disabling regex functionality")
-# endif
-#endif
-
 namespace osmium {
 
     /**
@@ -211,7 +187,6 @@ namespace osmium {
 
         }; // class substring
 
-#ifdef OSMIUM_WITH_REGEX
         /**
          * Matches if the test string matches the regular expression.
          */
@@ -235,7 +210,6 @@ namespace osmium {
             }
 
         }; // class regex
-#endif
 
         /**
          * Matches if the test string is equal to any of the stored strings.
@@ -293,9 +267,7 @@ namespace osmium {
                  equal,
                  prefix,
                  substring,
-#ifdef OSMIUM_WITH_REGEX
                  regex,
-#endif
                  list>;
 
         matcher_type m_matcher;
@@ -388,7 +360,6 @@ namespace osmium {
             m_matcher(equal{str}) {
         }
 
-#ifdef OSMIUM_WITH_REGEX
         /**
          * Create a string matcher that will match the specified regex.
          * Shortcut for
@@ -398,7 +369,6 @@ namespace osmium {
         StringMatcher(const std::regex& aregex) : // NOLINT(google-explicit-constructor, hicpp-explicit-conversions)
             m_matcher(regex{aregex}) {
         }
-#endif
 
         /**
          * Create a string matcher that will match if any of the strings


=====================================
include/osmium/version.hpp
=====================================
@@ -37,11 +37,11 @@ DEALINGS IN THE SOFTWARE.
 #define LIBOSMIUM_VERSION_MAJOR 2
 
 // NOLINTNEXTLINE(modernize-macro-to-enum)
-#define LIBOSMIUM_VERSION_MINOR 21
+#define LIBOSMIUM_VERSION_MINOR 22
 
 // NOLINTNEXTLINE(modernize-macro-to-enum)
 #define LIBOSMIUM_VERSION_PATCH 0
 
-#define LIBOSMIUM_VERSION_STRING "2.21.0"
+#define LIBOSMIUM_VERSION_STRING "2.22.0"
 
 #endif // OSMIUM_VERSION_HPP


=====================================
include/osmium/visitor.hpp
=====================================
@@ -57,42 +57,42 @@ namespace osmium {
                 case osmium::item_type::undefined:
                     break;
                 case osmium::item_type::node:
-                    handler.osm_object(static_cast<ConstIfConst<TItem, osmium::OSMObject>&>(item));
-                    handler.node(static_cast<ConstIfConst<TItem, osmium::Node>&>(item));
+                    std::forward<THandler>(handler).osm_object(static_cast<ConstIfConst<TItem, osmium::OSMObject>&>(item));
+                    std::forward<THandler>(handler).node(static_cast<ConstIfConst<TItem, osmium::Node>&>(item));
                     break;
                 case osmium::item_type::way:
-                    handler.osm_object(static_cast<ConstIfConst<TItem, osmium::OSMObject>&>(item));
-                    handler.way(static_cast<ConstIfConst<TItem, osmium::Way>&>(item));
+                    std::forward<THandler>(handler).osm_object(static_cast<ConstIfConst<TItem, osmium::OSMObject>&>(item));
+                    std::forward<THandler>(handler).way(static_cast<ConstIfConst<TItem, osmium::Way>&>(item));
                     break;
                 case osmium::item_type::relation:
-                    handler.osm_object(static_cast<ConstIfConst<TItem, osmium::OSMObject>&>(item));
-                    handler.relation(static_cast<ConstIfConst<TItem, osmium::Relation>&>(item));
+                    std::forward<THandler>(handler).osm_object(static_cast<ConstIfConst<TItem, osmium::OSMObject>&>(item));
+                    std::forward<THandler>(handler).relation(static_cast<ConstIfConst<TItem, osmium::Relation>&>(item));
                     break;
                 case osmium::item_type::area:
-                    handler.osm_object(static_cast<ConstIfConst<TItem, osmium::OSMObject>&>(item));
-                    handler.area(static_cast<ConstIfConst<TItem, osmium::Area>&>(item));
+                    std::forward<THandler>(handler).osm_object(static_cast<ConstIfConst<TItem, osmium::OSMObject>&>(item));
+                    std::forward<THandler>(handler).area(static_cast<ConstIfConst<TItem, osmium::Area>&>(item));
                     break;
                 case osmium::item_type::changeset:
-                    handler.changeset(static_cast<ConstIfConst<TItem, osmium::Changeset>&>(item));
+                    std::forward<THandler>(handler).changeset(static_cast<ConstIfConst<TItem, osmium::Changeset>&>(item));
                     break;
                 case osmium::item_type::tag_list:
-                    handler.tag_list(static_cast<ConstIfConst<TItem, osmium::TagList>&>(item));
+                    std::forward<THandler>(handler).tag_list(static_cast<ConstIfConst<TItem, osmium::TagList>&>(item));
                     break;
                 case osmium::item_type::way_node_list:
-                    handler.way_node_list(static_cast<ConstIfConst<TItem, osmium::WayNodeList>&>(item));
+                    std::forward<THandler>(handler).way_node_list(static_cast<ConstIfConst<TItem, osmium::WayNodeList>&>(item));
                     break;
                 case osmium::item_type::relation_member_list:
                 case osmium::item_type::relation_member_list_with_full_members:
-                    handler.relation_member_list(static_cast<ConstIfConst<TItem, osmium::RelationMemberList>&>(item));
+                    std::forward<THandler>(handler).relation_member_list(static_cast<ConstIfConst<TItem, osmium::RelationMemberList>&>(item));
                     break;
                 case osmium::item_type::outer_ring:
-                    handler.outer_ring(static_cast<ConstIfConst<TItem, osmium::OuterRing>&>(item));
+                    std::forward<THandler>(handler).outer_ring(static_cast<ConstIfConst<TItem, osmium::OuterRing>&>(item));
                     break;
                 case osmium::item_type::inner_ring:
-                    handler.inner_ring(static_cast<ConstIfConst<TItem, osmium::InnerRing>&>(item));
+                    std::forward<THandler>(handler).inner_ring(static_cast<ConstIfConst<TItem, osmium::InnerRing>&>(item));
                     break;
                 case osmium::item_type::changeset_discussion:
-                    handler.changeset_discussion(static_cast<ConstIfConst<TItem, osmium::ChangesetDiscussion>&>(item));
+                    std::forward<THandler>(handler).changeset_discussion(static_cast<ConstIfConst<TItem, osmium::ChangesetDiscussion>&>(item));
                     break;
             }
         }
@@ -101,23 +101,23 @@ namespace osmium {
         inline void apply_item_impl(const osmium::OSMEntity& item, THandler&& handler) {
             switch (item.type()) {
                 case osmium::item_type::node:
-                    handler.osm_object(static_cast<const osmium::OSMObject&>(item));
-                    handler.node(static_cast<const osmium::Node&>(item));
+                    std::forward<THandler>(handler).osm_object(static_cast<const osmium::OSMObject&>(item));
+                    std::forward<THandler>(handler).node(static_cast<const osmium::Node&>(item));
                     break;
                 case osmium::item_type::way:
-                    handler.osm_object(static_cast<const osmium::OSMObject&>(item));
-                    handler.way(static_cast<const osmium::Way&>(item));
+                    std::forward<THandler>(handler).osm_object(static_cast<const osmium::OSMObject&>(item));
+                    std::forward<THandler>(handler).way(static_cast<const osmium::Way&>(item));
                     break;
                 case osmium::item_type::relation:
-                    handler.osm_object(static_cast<const osmium::OSMObject&>(item));
-                    handler.relation(static_cast<const osmium::Relation&>(item));
+                    std::forward<THandler>(handler).osm_object(static_cast<const osmium::OSMObject&>(item));
+                    std::forward<THandler>(handler).relation(static_cast<const osmium::Relation&>(item));
                     break;
                 case osmium::item_type::area:
-                    handler.osm_object(static_cast<const osmium::OSMObject&>(item));
-                    handler.area(static_cast<const osmium::Area&>(item));
+                    std::forward<THandler>(handler).osm_object(static_cast<const osmium::OSMObject&>(item));
+                    std::forward<THandler>(handler).area(static_cast<const osmium::Area&>(item));
                     break;
                 case osmium::item_type::changeset:
-                    handler.changeset(static_cast<const osmium::Changeset&>(item));
+                    std::forward<THandler>(handler).changeset(static_cast<const osmium::Changeset&>(item));
                     break;
                 default:
                     throw osmium::unknown_type{};
@@ -128,23 +128,23 @@ namespace osmium {
         inline void apply_item_impl(osmium::OSMEntity& item, THandler&& handler) {
             switch (item.type()) {
                 case osmium::item_type::node:
-                    handler.osm_object(static_cast<osmium::OSMObject&>(item));
-                    handler.node(static_cast<osmium::Node&>(item));
+                    std::forward<THandler>(handler).osm_object(static_cast<osmium::OSMObject&>(item));
+                    std::forward<THandler>(handler).node(static_cast<osmium::Node&>(item));
                     break;
                 case osmium::item_type::way:
-                    handler.osm_object(static_cast<osmium::OSMObject&>(item));
-                    handler.way(static_cast<osmium::Way&>(item));
+                    std::forward<THandler>(handler).osm_object(static_cast<osmium::OSMObject&>(item));
+                    std::forward<THandler>(handler).way(static_cast<osmium::Way&>(item));
                     break;
                 case osmium::item_type::relation:
-                    handler.osm_object(static_cast<osmium::OSMObject&>(item));
-                    handler.relation(static_cast<osmium::Relation&>(item));
+                    std::forward<THandler>(handler).osm_object(static_cast<osmium::OSMObject&>(item));
+                    std::forward<THandler>(handler).relation(static_cast<osmium::Relation&>(item));
                     break;
                 case osmium::item_type::area:
-                    handler.osm_object(static_cast<osmium::OSMObject&>(item));
-                    handler.area(static_cast<osmium::Area&>(item));
+                    std::forward<THandler>(handler).osm_object(static_cast<osmium::OSMObject&>(item));
+                    std::forward<THandler>(handler).area(static_cast<osmium::Area&>(item));
                     break;
                 case osmium::item_type::changeset:
-                    handler.changeset(static_cast<osmium::Changeset&>(item));
+                    std::forward<THandler>(handler).changeset(static_cast<osmium::Changeset&>(item));
                     break;
                 default:
                     throw osmium::unknown_type{};
@@ -155,20 +155,20 @@ namespace osmium {
         inline void apply_item_impl(const osmium::OSMObject& item, THandler&& handler) {
             switch (item.type()) {
                 case osmium::item_type::node:
-                    handler.osm_object(item);
-                    handler.node(static_cast<const osmium::Node&>(item));
+                    std::forward<THandler>(handler).osm_object(item);
+                    std::forward<THandler>(handler).node(static_cast<const osmium::Node&>(item));
                     break;
                 case osmium::item_type::way:
-                    handler.osm_object(item);
-                    handler.way(static_cast<const osmium::Way&>(item));
+                    std::forward<THandler>(handler).osm_object(item);
+                    std::forward<THandler>(handler).way(static_cast<const osmium::Way&>(item));
                     break;
                 case osmium::item_type::relation:
-                    handler.osm_object(item);
-                    handler.relation(static_cast<const osmium::Relation&>(item));
+                    std::forward<THandler>(handler).osm_object(item);
+                    std::forward<THandler>(handler).relation(static_cast<const osmium::Relation&>(item));
                     break;
                 case osmium::item_type::area:
-                    handler.osm_object(item);
-                    handler.area(static_cast<const osmium::Area&>(item));
+                    std::forward<THandler>(handler).osm_object(item);
+                    std::forward<THandler>(handler).area(static_cast<const osmium::Area&>(item));
                     break;
                 default:
                     throw osmium::unknown_type{};
@@ -179,20 +179,20 @@ namespace osmium {
         inline void apply_item_impl(osmium::OSMObject& item, THandler&& handler) {
             switch (item.type()) {
                 case osmium::item_type::node:
-                    handler.osm_object(item);
-                    handler.node(static_cast<osmium::Node&>(item));
+                    std::forward<THandler>(handler).osm_object(item);
+                    std::forward<THandler>(handler).node(static_cast<osmium::Node&>(item));
                     break;
                 case osmium::item_type::way:
-                    handler.osm_object(item);
-                    handler.way(static_cast<osmium::Way&>(item));
+                    std::forward<THandler>(handler).osm_object(item);
+                    std::forward<THandler>(handler).way(static_cast<osmium::Way&>(item));
                     break;
                 case osmium::item_type::relation:
-                    handler.osm_object(item);
-                    handler.relation(static_cast<osmium::Relation&>(item));
+                    std::forward<THandler>(handler).osm_object(item);
+                    std::forward<THandler>(handler).relation(static_cast<osmium::Relation&>(item));
                     break;
                 case osmium::item_type::area:
-                    handler.osm_object(item);
-                    handler.area(static_cast<osmium::Area&>(item));
+                    std::forward<THandler>(handler).osm_object(item);
+                    std::forward<THandler>(handler).area(static_cast<osmium::Area&>(item));
                     break;
                 default:
                     throw osmium::unknown_type{};


=====================================
test/t/index/test_relations_map.cpp
=====================================
@@ -9,6 +9,10 @@ static_assert(!std::is_copy_constructible<osmium::index::RelationsMapIndex>::val
 static_assert(!std::is_copy_constructible<osmium::index::RelationsMapStash>::value, "RelationsMapStash should not be copy constructible");
 static_assert(!std::is_copy_assignable<osmium::index::RelationsMapIndex>::value, "RelationsMapIndex should not be copy assignable");
 static_assert(!std::is_copy_assignable<osmium::index::RelationsMapStash>::value, "RelationsMapStash should not be copy assignable");
+static_assert(std::is_move_constructible<osmium::index::RelationsMapIndex>::value, "RelationsMapIndex should be move constructible");
+static_assert(std::is_move_constructible<osmium::index::RelationsMapStash>::value, "RelationsMapStash should be move constructible");
+static_assert(std::is_move_assignable<osmium::index::RelationsMapIndex>::value, "RelationsMapIndex should be move assignable");
+static_assert(std::is_move_assignable<osmium::index::RelationsMapStash>::value, "RelationsMapStash should be move assignable");
 
 TEST_CASE("RelationsMapStash lvalue") {
     osmium::index::RelationsMapStash stash;
@@ -20,6 +24,10 @@ TEST_CASE("RelationsMapStash lvalue") {
     REQUIRE_FALSE(stash.empty());
     REQUIRE(stash.size() == 2);
 
+    const auto sizes = stash.sizes();
+    REQUIRE(sizes.first == 2);
+    REQUIRE(sizes.second == 0);
+
     const auto index = stash.build_member_to_parent_index();
 
     REQUIRE_FALSE(index.empty());
@@ -33,6 +41,156 @@ TEST_CASE("RelationsMapStash lvalue") {
     REQUIRE(count == 1);
 }
 
+TEST_CASE("RelationsMapStash 64bit") {
+    osmium::index::RelationsMapStash stash;
+    REQUIRE(stash.empty());
+    REQUIRE(stash.size() == 0); // NOLINT(readability-container-size-empty)
+
+    const uint64_t maxsmall = (1ULL << 32ULL) - 1;
+    const uint64_t large = 1ULL << 33ULL;
+
+    stash.add(1, 2);
+    stash.add(2, maxsmall);
+    stash.add(3, large + 1);
+    stash.add(4, large + 2);
+    stash.add(5, large + 3);
+    stash.add(large + 5, 5);
+    stash.add(large + 6, 6);
+    stash.add(large + 7, large + 8);
+    REQUIRE_FALSE(stash.empty());
+    REQUIRE(stash.size() == 8);
+
+    const auto sizes = stash.sizes();
+    REQUIRE(sizes.first == 2);
+    REQUIRE(sizes.second == 6);
+
+    const auto index = stash.build_member_to_parent_index();
+
+    REQUIRE_FALSE(index.empty());
+    REQUIRE(index.size() == 8);
+
+    int count = 0;
+
+    index.for_each(1, [&](osmium::unsigned_object_id_type id) {
+        REQUIRE(id == 2);
+        ++count;
+    });
+    index.for_each(2, [&](osmium::unsigned_object_id_type id) {
+        REQUIRE(id == maxsmall);
+        ++count;
+    });
+    index.for_each(3, [&](osmium::unsigned_object_id_type id) {
+        REQUIRE(id == large + 1);
+        ++count;
+    });
+    index.for_each(4, [&](osmium::unsigned_object_id_type id) {
+        REQUIRE(id == large + 2);
+        ++count;
+    });
+    index.for_each(5, [&](osmium::unsigned_object_id_type id) {
+        REQUIRE(id == large + 3);
+        ++count;
+    });
+    index.for_each(large + 5, [&](osmium::unsigned_object_id_type id) {
+        REQUIRE(id == 5);
+        ++count;
+    });
+    index.for_each(large + 6, [&](osmium::unsigned_object_id_type id) {
+        REQUIRE(id == 6);
+        ++count;
+    });
+    index.for_each(large + 7, [&](osmium::unsigned_object_id_type id) {
+        REQUIRE(id == large + 8);
+        ++count;
+    });
+
+
+    REQUIRE(count == 8);
+}
+
+TEST_CASE("RelationsMapStash duplicates will be removed in index") {
+    osmium::index::RelationsMapStash stash;
+    REQUIRE(stash.empty());
+
+    const uint64_t large = 1ULL << 33ULL;
+
+    stash.add(1, 2);
+    stash.add(2, 3);
+    stash.add(1, 2); // duplicate
+    stash.add(2, 2);
+    stash.add(1, 2); // another duplicate
+    stash.add(5, large + 1);
+    stash.add(5, 4);
+    stash.add(5, large + 1); // also duplicate
+    stash.add(large + 2, 1);
+    stash.add(large + 2, 4);
+    stash.add(large + 2, 1); // also duplicate
+
+    REQUIRE(stash.size() == 11);
+
+    const auto sizes = stash.sizes();
+    REQUIRE(sizes.first == 6);
+    REQUIRE(sizes.second == 5);
+
+    SECTION("member to parent") {
+        const auto index = stash.build_member_to_parent_index();
+        REQUIRE_FALSE(index.empty());
+        REQUIRE(index.size() == 7);
+    }
+
+    SECTION("parent to member") {
+        const auto index = stash.build_parent_to_member_index();
+        REQUIRE_FALSE(index.empty());
+        REQUIRE(index.size() == 7);
+    }
+}
+
+TEST_CASE("RelationsMapStash n:m results") {
+    osmium::index::RelationsMapStash stash;
+    REQUIRE(stash.empty());
+
+    const uint64_t large = 1ULL << 33ULL;
+
+    stash.add(3, large + 1);
+    stash.add(3, large + 2);
+    stash.add(4, large + 1);
+    stash.add(4, large + 2);
+    stash.add(4, large + 1);
+    stash.add(5, large + 2);
+
+    REQUIRE_FALSE(stash.empty());
+    REQUIRE(stash.size() == 6);
+
+    const auto sizes = stash.sizes();
+    REQUIRE(sizes.first == 0);
+    REQUIRE(sizes.second == 6);
+
+    const auto index = stash.build_member_to_parent_index();
+
+    REQUIRE_FALSE(index.empty());
+    REQUIRE(index.size() == 5);
+
+    int count = 0;
+
+    index.for_each(2, [&](osmium::unsigned_object_id_type /*id*/) {
+        REQUIRE(false);
+    });
+    index.for_each(3, [&](osmium::unsigned_object_id_type id) {
+        REQUIRE(((id == large + 1) || (id == large + 2)));
+        ++count;
+    });
+    index.for_each(4, [&](osmium::unsigned_object_id_type id) {
+        REQUIRE(((id == large + 1) || (id == large + 2)));
+        ++count;
+    });
+    index.for_each(5, [&](osmium::unsigned_object_id_type id) {
+        REQUIRE(id == large + 2);
+        ++count;
+    });
+
+    REQUIRE(count == 5);
+}
+
 namespace {
 
 osmium::index::RelationsMapIndex func() {
@@ -83,6 +241,74 @@ TEST_CASE("RelationsMapStash reverse index") {
     REQUIRE(count == 2);
 }
 
+TEST_CASE("RelationsMapStash reverse index with 64bit values") {
+    osmium::index::RelationsMapStash stash;
+    REQUIRE(stash.empty());
+
+    const uint64_t large = 1ULL << 33ULL;
+
+    stash.add(1, 2);
+    stash.add(2, 3);
+    stash.add(3, large + 1);
+    stash.add(4, large + 2);
+    stash.add(5, large + 3);
+    stash.add(large + 5, 5);
+    stash.add(large + 6, 6);
+    stash.add(large + 7, large + 8);
+    REQUIRE_FALSE(stash.empty());
+    REQUIRE(stash.size() == 8);
+
+    const auto sizes = stash.sizes();
+    REQUIRE(sizes.first == 2);
+    REQUIRE(sizes.second == 6);
+
+    const auto index = stash.build_parent_to_member_index();
+
+    REQUIRE_FALSE(index.empty());
+    REQUIRE(index.size() == 8);
+
+    int count = 0;
+
+    index.for_each(1, [&](osmium::unsigned_object_id_type /*id*/) {
+        REQUIRE(false);
+    });
+    index.for_each(2, [&](osmium::unsigned_object_id_type id) {
+        REQUIRE(id == 1);
+        ++count;
+    });
+    index.for_each(3, [&](osmium::unsigned_object_id_type id) {
+        REQUIRE(id == 2);
+        ++count;
+    });
+    index.for_each(large + 1, [&](osmium::unsigned_object_id_type id) {
+        REQUIRE(id == 3);
+        ++count;
+    });
+    index.for_each(large + 2, [&](osmium::unsigned_object_id_type id) {
+        REQUIRE(id == 4);
+        ++count;
+    });
+    index.for_each(large + 3, [&](osmium::unsigned_object_id_type id) {
+        REQUIRE(id == 5);
+        ++count;
+    });
+    index.for_each(5, [&](osmium::unsigned_object_id_type id) {
+        REQUIRE(id == large + 5);
+        ++count;
+    });
+    index.for_each(6, [&](osmium::unsigned_object_id_type id) {
+        REQUIRE(id == large + 6);
+        ++count;
+    });
+    index.for_each(large + 8, [&](osmium::unsigned_object_id_type id) {
+        REQUIRE(id == large + 7);
+        ++count;
+    });
+
+
+    REQUIRE(count == 8);
+}
+
 TEST_CASE("RelationsMapStash both indexes") {
     osmium::index::RelationsMapStash stash;
     REQUIRE(stash.empty());
@@ -92,20 +318,44 @@ TEST_CASE("RelationsMapStash both indexes") {
     REQUIRE_FALSE(stash.empty());
     REQUIRE(stash.size() == 2);
 
-    const auto index = stash.build_indexes();
+    const auto indexes = stash.build_indexes();
 
-    REQUIRE_FALSE(index.empty());
-    REQUIRE(index.size() == 2);
+    REQUIRE_FALSE(indexes.empty());
+    REQUIRE(indexes.size() == 2);
 
     int count = 0;
-    index.member_to_parent().for_each(2, [&](osmium::unsigned_object_id_type id) {
+    indexes.member_to_parent().for_each(2, [&](osmium::unsigned_object_id_type id) {
         REQUIRE(id == 3);
         ++count;
     });
-    index.parent_to_member().for_each(2, [&](osmium::unsigned_object_id_type id) {
+    indexes.parent_to_member().for_each(2, [&](osmium::unsigned_object_id_type id) {
         REQUIRE(id == 1);
         ++count;
     });
     REQUIRE(count == 2);
 }
 
+TEST_CASE("RelationsMapStash small and large") {
+    osmium::index::RelationsMapStash stash;
+    REQUIRE(stash.empty());
+
+    stash.add(1, 2);
+    stash.add(2, 3);
+    stash.add(4, (1ULL << 32ULL) - 1);
+    stash.add((1ULL << 32ULL) - 1, 5);
+
+    REQUIRE(stash.sizes().first == 4);
+    REQUIRE(stash.sizes().second == 0);
+
+    stash.add(6, (1ULL << 32ULL) + 1);
+    stash.add((1ULL << 32ULL) + 1, 7);
+
+    REQUIRE(stash.sizes().first == 4);
+    REQUIRE(stash.sizes().second == 2);
+
+    stash.add(8, (1ULL << 63ULL));
+    stash.add((1ULL << 63ULL), 9);
+
+    REQUIRE(stash.sizes().first == 4);
+    REQUIRE(stash.sizes().second == 4);
+}


=====================================
test/t/io/test_reader.cpp
=====================================
@@ -266,7 +266,7 @@ TEST_CASE("Reader should work when there is an exception in main thread before g
         const osmium::io::Reader reader{with_data_dir("t/io/data.osm")};
         REQUIRE_FALSE(reader.eof());
         throw std::runtime_error{"foo"};
-    } catch (...) {
+    } catch (...) { // NOLINT(bugprone-empty-catch)
     }
 
     REQUIRE(count == count_fds());
@@ -280,7 +280,7 @@ TEST_CASE("Reader should work when there is an exception in main thread while re
         REQUIRE_FALSE(reader.eof());
         auto header = reader.header();
         throw std::runtime_error{"foo"};
-    } catch (...) {
+    } catch (...) { // NOLINT(bugprone-empty-catch)
     }
 
     REQUIRE(count == count_fds());


=====================================
test/t/tags/test_filter.cpp
=====================================
@@ -4,7 +4,6 @@
 #include <osmium/memory/buffer.hpp>
 #include <osmium/osm/tag.hpp>
 #include <osmium/tags/filter.hpp>
-#include <osmium/tags/regex_filter.hpp>
 #include <osmium/tags/taglist.hpp>
 
 #include <algorithm>
@@ -190,68 +189,3 @@ TEST_CASE("KeyValueFilter") {
     }
 
 }
-
-TEST_CASE("RegexFilter matches some tags") {
-    osmium::memory::Buffer buffer{10240};
-
-    osmium::tags::RegexFilter filter{false};
-    filter.add(true, "highway", std::regex{".*_link"});
-
-    const osmium::TagList& tag_list1 = make_tag_list(buffer, {
-        { "highway", "primary_link" },
-        { "source", "GPS" }
-    });
-    const osmium::TagList& tag_list2 = make_tag_list(buffer, {
-        { "highway", "primary" },
-        { "source", "GPS" }
-    });
-
-    check_filter(tag_list1, filter, {true, false});
-    check_filter(tag_list2, filter, {false, false});
-}
-
-TEST_CASE("RegexFilter matches some tags with lvalue regex") {
-    osmium::memory::Buffer buffer{10240};
-    osmium::tags::RegexFilter filter{false};
-    const std::regex r{".*straße"};
-    filter.add(true, "name", r);
-
-    const osmium::TagList& tag_list = make_tag_list(buffer, {
-        { "highway", "primary" },
-        { "name", "Hauptstraße" }
-    });
-
-    check_filter(tag_list, filter, {false, true});
-}
-
-TEST_CASE("KeyPrefixFilter matches some keys") {
-    osmium::memory::Buffer buffer{10240};
-
-    osmium::tags::KeyPrefixFilter filter{false};
-    filter.add(true, "name:");
-
-    const osmium::TagList& tag_list = make_tag_list(buffer, {
-        { "highway", "primary" },
-        { "name:de", "Hauptstraße" }
-    });
-
-    check_filter(tag_list, filter, {false, true});
-
-}
-
-TEST_CASE("Generic Filter with regex matches some keys") {
-    osmium::memory::Buffer buffer{10240};
-
-    osmium::tags::Filter<std::regex> filter{false};
-    filter.add(true, std::regex{"restriction.+conditional"});
-
-    const osmium::TagList& tag_list = make_tag_list(buffer, {
-        { "highway", "primary" },
-        { "restrictionconditional", "only_right_turn @ (Mo-Fr 07:00-14:00)" },
-        { "restriction:conditional", "only_right_turn @ (Mo-Fr 07:00-14:00)" },
-        { "restriction:psv:conditional", "only_right_turn @ (Mo-Fr 07:00-14:00)" }
-    });
-
-    check_filter(tag_list, filter, {false, false, true, true});
-
-}


=====================================
test/t/tags/test_tags_filter.cpp
=====================================
@@ -99,7 +99,7 @@ struct result_type {
 
 }; // struct result_type
 
-bool operator==(const result_type& lhs, const result_type& rhs) noexcept {
+static bool operator==(const result_type& lhs, const result_type& rhs) noexcept {
     return lhs.v == rhs.v && lhs.b == rhs.b;
 }
 


=====================================
test/t/util/test_string_matcher.cpp
=====================================
@@ -2,16 +2,13 @@
 
 #include <osmium/util/string_matcher.hpp>
 
+#include <regex>
 #include <sstream>
 #include <string>
 #include <type_traits>
 #include <utility>
 #include <vector>
 
-#ifdef OSMIUM_WITH_REGEX
-#include <regex>
-#endif
-
 static_assert(std::is_default_constructible<osmium::StringMatcher>::value, "StringMatcher should be default constructible");
 static_assert(std::is_copy_constructible<osmium::StringMatcher>::value, "StringMatcher should be copy constructible");
 static_assert(std::is_move_constructible<osmium::StringMatcher>::value, "StringMatcher should be move constructible");
@@ -90,7 +87,6 @@ TEST_CASE("String matcher: empty prefix") {
     REQUIRE(m.match(""));
 }
 
-#ifdef OSMIUM_WITH_REGEX
 TEST_CASE("String matcher: regex prefix") {
     const osmium::StringMatcher::regex m{std::regex{"^foo", std::regex::optimize}};
     REQUIRE(m.match("foo"));
@@ -107,7 +103,6 @@ TEST_CASE("String matcher: regex substr") {
     REQUIRE(m.match("xfoox"));
     REQUIRE_FALSE(m.match(""));
 }
-#endif
 
 TEST_CASE("String matcher: list") {
     const osmium::StringMatcher::list m{{"foo", "bar"}};
@@ -157,14 +152,12 @@ TEST_CASE("Construct StringMatcher from string") {
     REQUIRE(print(m) == "equal[foo]");
 }
 
-#ifdef OSMIUM_WITH_REGEX
 TEST_CASE("Construct StringMatcher from regex") {
     const osmium::StringMatcher m{std::regex{"^foo"}};
     REQUIRE(m("foo"));
     REQUIRE_FALSE(m("bar"));
     REQUIRE(print(m) == "regex");
 }
-#endif
 
 TEST_CASE("Construct StringMatcher from list") {
     const std::vector<std::string> v{"foo", "xxx"};



View it on GitLab: https://salsa.debian.org/debian-gis-team/libosmium/-/commit/23fb18dc51572089f66a515c3bdb84b7ed0b6bcb

-- 
View it on GitLab: https://salsa.debian.org/debian-gis-team/libosmium/-/commit/23fb18dc51572089f66a515c3bdb84b7ed0b6bcb
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-grass-devel/attachments/20250318/50dc07b6/attachment-0001.htm>


More information about the Pkg-grass-devel mailing list