Loading...
Searching...
No Matches
relations_map.hpp
Go to the documentation of this file.
#ifndef OSMIUM_INDEX_RELATIONS_MAP_HPP
#define OSMIUM_INDEX_RELATIONS_MAP_HPP
/*
This file is part of Osmium (https://osmcode.org/libosmium).
Copyright 2013-2025 Jochen Topf <jochen@topf.org> and others (see README).
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#include <osmium/osm/item_type.hpp>
#include <osmium/osm/relation.hpp>
#include <osmium/osm/types.hpp>
#include <algorithm>
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <limits>
#include <tuple>
#include <type_traits>
#include <utility>
#include <vector>
namespace osmium {
namespace index {
namespace detail {
template <typename TKey, typename TKeyInternal, typename TValue, typename TValueInternal>
class flat_map {
public:
using key_type = TKey;
using value_type = TValue;
private:
struct kv_pair {
TKeyInternal key;
TValueInternal value;
explicit kv_pair(const key_type key_id) :
key(static_cast<TKeyInternal>(key_id)),
value() {
}
kv_pair(const key_type key_id, const value_type value_id) :
key(static_cast<TKeyInternal>(key_id)),
value(static_cast<TValueInternal>(value_id)) {
}
bool operator<(const kv_pair& other) const noexcept {
return std::tie(key, value) < std::tie(other.key, other.value);
}
bool operator==(const kv_pair& other) const noexcept {
return std::tie(key, value) == std::tie(other.key, other.value);
}
}; // struct kv_pair
std::vector<kv_pair> m_map;
public:
using const_iterator = typename std::vector<kv_pair>::const_iterator;
void set(const key_type key, const value_type value) {
m_map.emplace_back(key, value);
}
std::enable_if_t<std::is_same<TKey, TValue>::value> flip_in_place() {
for (auto& p : m_map) {
using std::swap;
swap(p.key, p.value);
}
}
flat_map<TValue, TValueInternal, TKey, TKeyInternal> flip_copy() {
flat_map<TValue, TValueInternal, TKey, TKeyInternal> map;
map.reserve(m_map.size());
for (const auto& p : m_map) {
map.set(p.value, p.key);
}
return map;
}
void sort_unique() {
std::sort(m_map.begin(), m_map.end());
const auto last = std::unique(m_map.begin(), m_map.end());
m_map.erase(last, m_map.end());
}
std::pair<const_iterator, const_iterator> get(const key_type key) const noexcept {
return std::equal_range(m_map.begin(), m_map.end(), kv_pair{key}, [](const kv_pair& lhs, const kv_pair& rhs) {
return lhs.key < rhs.key;
});
}
bool empty() const noexcept {
return m_map.empty();
}
std::size_t size() const noexcept {
return m_map.size();
}
void reserve(const std::size_t size) {
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
class RelationsMapIndex {
friend class RelationsMapStash;
friend class RelationsMapIndexes;
detail::rel_index_map_type<uint32_t> m_map32;
detail::rel_index_map_type<uint64_t> m_map64;
bool m_small;
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:
RelationsMapIndex() = delete;
RelationsMapIndex(const RelationsMapIndex&) = delete;
RelationsMapIndex& operator=(const RelationsMapIndex&) = delete;
RelationsMapIndex(RelationsMapIndex&& /*other*/) noexcept;
RelationsMapIndex& operator=(RelationsMapIndex&& /*other*/) noexcept;
~RelationsMapIndex() noexcept = default;
template <typename TFunc>
void for_each(const osmium::unsigned_object_id_type id, TFunc&& func) const {
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);
}
}
}
bool empty() const noexcept {
return m_small ? m_map32.empty() : m_map64.empty();
}
std::size_t size() const noexcept {
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 = default; // NOLINT(readability-redundant-inline-specifier)
inline RelationsMapIndex& RelationsMapIndex::operator=(RelationsMapIndex&&) noexcept = default; // NOLINT(readability-redundant-inline-specifier)
class RelationsMapIndexes {
friend class RelationsMapStash;
RelationsMapIndex m_member_to_parent;
RelationsMapIndex m_parent_to_member;
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)) {
}
public:
const RelationsMapIndex& member_to_parent() const noexcept {
return m_member_to_parent;
}
const RelationsMapIndex& parent_to_member() const noexcept {
return m_parent_to_member;
}
bool empty() const noexcept {
return m_member_to_parent.empty();
}
std::size_t size() const noexcept {
return m_member_to_parent.size();
}
}; // class RelationsMapIndexes
class RelationsMapStash {
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;
RelationsMapStash(const RelationsMapStash&) = delete;
RelationsMapStash& operator=(const RelationsMapStash&) = delete;
RelationsMapStash(RelationsMapStash&& /*other*/) noexcept;
RelationsMapStash& operator=(RelationsMapStash&& /*other*/) noexcept;
~RelationsMapStash() noexcept = default;
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()");
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);
}
}
void add_members(const osmium::Relation& relation) {
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) {
add(member.positive_ref(), relation.positive_id());
}
}
}
bool empty() const noexcept {
assert(m_valid && "You can't use the RelationsMap any more after calling build_index()");
return m_map32.empty() && m_map64.empty();
}
std::size_t size() const noexcept {
assert(m_valid && "You can't use the RelationsMap any more after calling build_index()");
return m_map32.size() + m_map64.size();
}
std::pair<std::size_t, std::size_t> sizes() const noexcept {
return std::make_pair(m_map32.size(), m_map64.size());
}
RelationsMapIndex build_member_to_parent_index() {
assert(m_valid && "You can't use the RelationsMap any more after calling build_member_to_parent_index()");
#ifndef NDEBUG
m_valid = false;
#endif
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)};
}
RelationsMapIndex build_parent_to_member_index() {
assert(m_valid && "You can't use the RelationsMap any more after calling build_parent_to_member_index()");
#ifndef NDEBUG
m_valid = false;
#endif
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)};
}
RelationsMapIndexes build_indexes() {
assert(m_valid && "You can't use the RelationsMap any more after calling build_indexes()");
#ifndef NDEBUG
m_valid = false;
#endif
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 = default; // NOLINT(readability-redundant-inline-specifier)
inline RelationsMapStash& RelationsMapStash::operator=(RelationsMapStash&&) noexcept = default; // NOLINT(readability-redundant-inline-specifier)
} // namespace index
} // namespace osmium
#endif // OSMIUM_INDEX_RELATIONS_MAP_HPP
osmium::Relation
Definition relation.hpp:161
osmium::index::RelationsMapIndex
Definition relations_map.hpp:187
osmium::index::RelationsMapIndex::RelationsMapIndex
RelationsMapIndex(const RelationsMapIndex &)=delete
osmium::index::RelationsMapIndex::RelationsMapIndex
RelationsMapIndex(detail::rel_index_map_type< uint64_t > &&map)
Definition relations_map.hpp:201
osmium::index::RelationsMapIndex::size
std::size_t size() const noexcept
Definition relations_map.hpp:260
osmium::index::RelationsMapIndex::m_map64
detail::rel_index_map_type< uint64_t > m_map64
Definition relations_map.hpp:193
osmium::index::RelationsMapIndex::for_each
void for_each(const osmium::unsigned_object_id_type id, TFunc &&func) const
Definition relations_map.hpp:232
osmium::index::RelationsMapIndex::RelationsMapIndex
RelationsMapIndex(detail::rel_index_map_type< uint32_t > &&map)
Definition relations_map.hpp:197
osmium::index::RelationsMapIndex::RelationsMapIndex
RelationsMapIndex()=delete
osmium::index::RelationsMapIndex::operator=
RelationsMapIndex & operator=(const RelationsMapIndex &)=delete
osmium::index::RelationsMapIndex::RelationsMapIndex
RelationsMapIndex(RelationsMapIndex &&) noexcept
osmium::index::RelationsMapIndex::empty
bool empty() const noexcept
Definition relations_map.hpp:251
osmium::index::RelationsMapIndex::m_map32
detail::rel_index_map_type< uint32_t > m_map32
Definition relations_map.hpp:192
osmium::index::RelationsMapIndex::m_small
bool m_small
Definition relations_map.hpp:195
osmium::index::RelationsMapIndexes
Definition relations_map.hpp:271
osmium::index::RelationsMapIndexes::parent_to_member
const RelationsMapIndex & parent_to_member() const noexcept
Definition relations_map.hpp:294
osmium::index::RelationsMapIndexes::member_to_parent
const RelationsMapIndex & member_to_parent() const noexcept
Definition relations_map.hpp:290
osmium::index::RelationsMapIndexes::size
std::size_t size() const noexcept
Definition relations_map.hpp:312
osmium::index::RelationsMapIndexes::empty
bool empty() const noexcept
Definition relations_map.hpp:303
osmium::index::RelationsMapIndexes::m_member_to_parent
RelationsMapIndex m_member_to_parent
Definition relations_map.hpp:275
osmium::index::RelationsMapIndexes::RelationsMapIndexes
RelationsMapIndexes(detail::rel_index_map_type< uint32_t > &&map1, detail::rel_index_map_type< uint32_t > &&map2)
Definition relations_map.hpp:278
osmium::index::RelationsMapIndexes::RelationsMapIndexes
RelationsMapIndexes(detail::rel_index_map_type< uint64_t > &&map1, detail::rel_index_map_type< uint64_t > &&map2)
Definition relations_map.hpp:283
osmium::index::RelationsMapIndexes::m_parent_to_member
RelationsMapIndex m_parent_to_member
Definition relations_map.hpp:276
osmium::index::RelationsMapStash
Definition relations_map.hpp:323
osmium::index::RelationsMapStash::m_map32
detail::rel_index_map_type< uint32_t > m_map32
Definition relations_map.hpp:325
osmium::index::RelationsMapStash::build_member_to_parent_index
RelationsMapIndex build_member_to_parent_index()
Definition relations_map.hpp:415
osmium::index::RelationsMapStash::m_valid
bool m_valid
Definition relations_map.hpp:329
osmium::index::RelationsMapStash::size
std::size_t size() const noexcept
Definition relations_map.hpp:394
osmium::index::RelationsMapStash::build_indexes
RelationsMapIndexes build_indexes()
Definition relations_map.hpp:459
osmium::index::RelationsMapStash::build_parent_to_member_index
RelationsMapIndex build_parent_to_member_index()
Definition relations_map.hpp:436
osmium::index::RelationsMapStash::append32to64
static void append32to64(detail::rel_index_map_type< uint32_t > &map32, detail::rel_index_map_type< uint64_t > &map64)
Definition relations_map.hpp:332
osmium::index::RelationsMapStash::m_map64
detail::rel_index_map_type< uint64_t > m_map64
Definition relations_map.hpp:326
osmium::index::RelationsMapStash::add_members
void add_members(const osmium::Relation &relation)
Definition relations_map.hpp:370
osmium::index::RelationsMapStash::operator=
RelationsMapStash & operator=(const RelationsMapStash &)=delete
osmium::index::RelationsMapStash::sizes
std::pair< std::size_t, std::size_t > sizes() const noexcept
Definition relations_map.hpp:405
osmium::index::RelationsMapStash::RelationsMapStash
RelationsMapStash(RelationsMapStash &&) noexcept
osmium::index::RelationsMapStash::empty
bool empty() const noexcept
Definition relations_map.hpp:384
osmium::index::RelationsMapStash::RelationsMapStash
RelationsMapStash(const RelationsMapStash &)=delete
osmium::index::RelationsMapStash::add
void add(const osmium::unsigned_object_id_type member_id, const osmium::unsigned_object_id_type relation_id)
Definition relations_map.hpp:357
osmium::index::RelationsMapStash::RelationsMapStash
RelationsMapStash()=default
item_type.hpp
detail
Definition attr.hpp:342
osmium::geom::operator==
bool operator==(const Coordinates &lhs, const Coordinates &rhs) noexcept
Definition coordinates.hpp:139
osmium::geom::operator<
bool operator<(const Tile &lhs, const Tile &rhs) noexcept
Definition tile.hpp:192
osmium::io::file_format::last
@ last
osmium::io::end
InputIterator< Reader > end(Reader &)
Definition reader_iterator.hpp:47
osmium::io::begin
InputIterator< Reader > begin(Reader &reader)
Definition reader_iterator.hpp:43
osmium
Namespace for everything in the Osmium library.
Definition assembler.hpp:53
osmium::item_type::relation
@ relation
osmium::unsigned_object_id_type
uint64_t unsigned_object_id_type
Type for OSM object (node, way, or relation) IDs where we only allow positive IDs.
Definition types.hpp:46
std
Definition location.hpp:555
relation.hpp
types.hpp