Loading...
Searching...
No Matches
id_set.hpp
Go to the documentation of this file.
#ifndef OSMIUM_INDEX_ID_SET_HPP
#define OSMIUM_INDEX_ID_SET_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/types.hpp>
#include <algorithm>
#include <array>
#include <cassert>
#include <cstddef>
#include <cstring>
#include <iterator>
#include <memory>
#include <type_traits>
#include <vector>
namespace osmium {
namespace index {
template <typename T>
class IdSet {
public:
IdSet() = default;
IdSet(const IdSet&) = default;
IdSet& operator=(const IdSet&) = default;
IdSet(IdSet&&) noexcept = default;
IdSet& operator=(IdSet&&) noexcept = default;
virtual ~IdSet() noexcept = default;
virtual void set(T id) = 0;
virtual bool get(T id) const noexcept = 0;
virtual bool empty() const = 0;
virtual void clear() = 0;
virtual std::size_t used_memory() const noexcept = 0;
}; // class IdSet
namespace detail {
// This value is a compromise. For node Ids it could be bigger
// which would mean less (but larger) memory allocations. For
// relations Ids it could be smaller, because they would all fit
// into a smaller allocation.
enum : std::size_t {
default_chunk_bits = 22U
};
} // namespace detail
template <typename T, std::size_t chunk_bits = detail::default_chunk_bits>
class IdSetDense;
template <typename T, std::size_t chunk_bits>
class IdSetDenseIterator {
using id_set = IdSetDense<T, chunk_bits>;
const id_set* m_set;
T m_value;
T m_last;
void next() noexcept {
while (m_value != m_last && !m_set->get(m_value)) {
const T cid = id_set::chunk_id(m_value);
assert(cid < m_set->m_data.size());
if (!m_set->m_data[cid]) {
m_value = (cid + 1) << (chunk_bits + 3);
} else {
const auto slot = m_set->m_data[cid][id_set::offset(m_value)];
if (slot == 0) {
m_value += 8;
m_value &= ~0x7ULL;
} else {
++m_value;
}
}
}
}
public:
using iterator_category = std::forward_iterator_tag;
using value_type = T;
using pointer = value_type*;
using reference = value_type&;
IdSetDenseIterator(const id_set* set, T value, T last) noexcept :
m_set(set),
m_value(value),
m_last(last) {
next();
}
IdSetDenseIterator& operator++() noexcept {
if (m_value != m_last) {
++m_value;
next();
}
return *this;
}
IdSetDenseIterator operator++(int) noexcept {
IdSetDenseIterator tmp{*this};
operator++();
return tmp;
}
bool operator==(const IdSetDenseIterator& rhs) const noexcept {
return m_set == rhs.m_set && m_value == rhs.m_value;
}
bool operator!=(const IdSetDenseIterator& rhs) const noexcept {
return !(*this == rhs);
}
T operator*() const noexcept {
assert(m_value < m_last);
return m_value;
}
}; // class IdSetDenseIterator
template <typename T, std::size_t chunk_bits>
class IdSetDense : public IdSet<T> {
friend class IdSetDenseIterator<T, chunk_bits>;
enum : std::size_t {
chunk_size = 1U << chunk_bits
};
std::vector<std::unique_ptr<unsigned char[]>> m_data;
T m_size = 0;
static std::size_t chunk_id(T id) noexcept {
return id >> (chunk_bits + 3U);
}
static std::size_t offset(T id) noexcept {
return (id >> 3U) & ((1U << chunk_bits) - 1U);
}
static unsigned int bitmask(T id) noexcept {
return 1U << (id & 0x7U);
}
T last() const noexcept {
return static_cast<T>(m_data.size()) * chunk_size * 8;
}
unsigned char& get_element(T id) {
const auto cid = chunk_id(id);
if (cid >= m_data.size()) {
m_data.resize(cid + 1);
}
auto& chunk = m_data[cid];
if (!chunk) {
chunk.reset(new unsigned char[chunk_size]);
::memset(chunk.get(), 0, chunk_size);
}
return chunk[offset(id)];
}
public:
using const_iterator = IdSetDenseIterator<T, chunk_bits>;
friend void swap(IdSetDense& first, IdSetDense& second) noexcept {
using std::swap;
swap(first.m_data, second.m_data);
swap(first.m_size, second.m_size);
}
IdSetDense() = default;
IdSetDense(const IdSetDense& other) :
IdSet<T>(other),
m_size(other.m_size) {
m_data.reserve(other.m_data.size());
for (const auto& ptr : other.m_data) {
if (ptr) {
m_data.emplace_back(new unsigned char[chunk_size]);
::memcpy(m_data.back().get(), ptr.get(), chunk_size);
} else {
m_data.emplace_back();
}
}
}
IdSetDense& operator=(IdSetDense other) {
swap(*this, other);
return *this;
}
IdSetDense(IdSetDense&&) noexcept = default;
// This should really be noexcept, but GCC 4.8 doesn't like it.
// NOLINTNEXTLINE(hicpp-noexcept-move, performance-noexcept-move-constructor)
IdSetDense& operator=(IdSetDense&&) = default;
~IdSetDense() noexcept override = default;
bool check_and_set(T id) {
auto& element = get_element(id);
if ((element & bitmask(id)) == 0) {
element |= bitmask(id);
++m_size;
return true;
}
return false;
}
void set(T id) final {
(void)check_and_set(id);
}
void unset(T id) {
auto& element = get_element(id);
if ((element & bitmask(id)) != 0) {
element &= ~bitmask(id);
--m_size;
}
}
bool get(T id) const noexcept final {
if (chunk_id(id) >= m_data.size()) {
return false;
}
const auto* r = m_data[chunk_id(id)].get();
if (!r) {
return false;
}
return (r[offset(id)] & bitmask(id)) != 0;
}
bool empty() const noexcept final {
return m_size == 0;
}
T size() const noexcept {
return m_size;
}
void clear() final {
m_data.clear();
m_size = 0;
}
std::size_t used_memory() const noexcept final {
return m_data.size() * chunk_size;
}
const_iterator begin() const {
return {this, 0, last()};
}
const_iterator end() const {
return {this, last(), last()};
}
}; // class IdSetDense
template <typename T>
class IdSetSmall : public IdSet<T> {
std::vector<T> m_data;
public:
IdSetSmall() = default;
IdSetSmall(const IdSetSmall&) = default;
IdSetSmall& operator=(const IdSetSmall&) = default;
IdSetSmall(IdSetSmall&&) noexcept = default;
IdSetSmall& operator=(IdSetSmall&&) noexcept = default;
~IdSetSmall() noexcept override = default;
void set(T id) final {
if (m_data.empty() || m_data.back() != id) {
m_data.push_back(id);
}
}
bool get(T id) const noexcept final {
const auto it = std::find(m_data.cbegin(), m_data.cend(), id);
return it != m_data.cend();
}
bool get_binary_search(T id) const noexcept {
return std::binary_search(m_data.cbegin(), m_data.cend(), id);
}
bool empty() const noexcept final {
return m_data.empty();
}
void clear() final {
m_data.clear();
}
void sort_unique() {
std::sort(m_data.begin(), m_data.end());
const auto last = std::unique(m_data.begin(), m_data.end());
m_data.erase(last, m_data.end());
}
std::size_t size() const noexcept {
return m_data.size();
}
std::size_t used_memory() const noexcept final {
return m_data.capacity() * sizeof(T);
}
void merge_sorted(const IdSetSmall<T>& other) {
std::vector<T> new_data;
new_data.reserve(m_data.size() + other.m_data.size());
std::set_union(m_data.cbegin(), m_data.cend(),
other.m_data.cbegin(), other.m_data.cend(),
std::back_inserter(new_data));
using std::swap;
swap(new_data, m_data);
}
using const_iterator = typename std::vector<T>::const_iterator;
const_iterator begin() const noexcept {
return m_data.cbegin();
}
const_iterator end() const noexcept {
return m_data.cend();
}
const_iterator cbegin() const noexcept {
return m_data.cbegin();
}
const_iterator cend() const noexcept {
return m_data.cend();
}
}; // class IdSetSmall
} // namespace index
} // namespace osmium
#endif // OSMIUM_INDEX_ID_SET_HPP
osmium::index::IdSetDenseIterator
Definition id_set.hpp:118
osmium::index::IdSetDenseIterator::reference
value_type & reference
Definition id_set.hpp:150
osmium::index::IdSetDenseIterator::m_last
T m_last
Definition id_set.hpp:125
osmium::index::IdSetDenseIterator::next
void next() noexcept
Definition id_set.hpp:127
osmium::index::IdSetDenseIterator::operator++
IdSetDenseIterator operator++(int) noexcept
Definition id_set.hpp:167
osmium::index::IdSetDenseIterator::operator++
IdSetDenseIterator & operator++() noexcept
Definition id_set.hpp:159
osmium::index::IdSetDenseIterator::m_value
T m_value
Definition id_set.hpp:124
osmium::index::IdSetDenseIterator::IdSetDenseIterator
IdSetDenseIterator(const id_set *set, T value, T last) noexcept
Definition id_set.hpp:152
osmium::index::IdSetDenseIterator::m_set
const id_set * m_set
Definition id_set.hpp:123
osmium::index::IdSetDenseIterator::operator!=
bool operator!=(const IdSetDenseIterator &rhs) const noexcept
Definition id_set.hpp:177
osmium::index::IdSetDenseIterator::operator==
bool operator==(const IdSetDenseIterator &rhs) const noexcept
Definition id_set.hpp:173
osmium::index::IdSetDenseIterator::value_type
T value_type
Definition id_set.hpp:148
osmium::index::IdSetDenseIterator::iterator_category
std::forward_iterator_tag iterator_category
Definition id_set.hpp:147
osmium::index::IdSetDenseIterator::pointer
value_type * pointer
Definition id_set.hpp:149
osmium::index::IdSetDense
Definition id_set.hpp:196
osmium::index::IdSetDense::operator=
IdSetDense & operator=(IdSetDense other)
Definition id_set.hpp:265
osmium::index::IdSetDense::begin
const_iterator begin() const
Definition id_set.hpp:361
osmium::index::IdSetDense::IdSetDense
IdSetDense(const IdSetDense &other)
Definition id_set.hpp:251
osmium::index::IdSetDense::set
void set(T id) final
Definition id_set.hpp:301
osmium::index::IdSetDense::m_data
std::vector< std::unique_ptr< unsigned char[]> > m_data
Definition id_set.hpp:205
osmium::index::IdSetDense::IdSetDense
IdSetDense(IdSetDense &&) noexcept=default
osmium::index::IdSetDense::chunk_id
static std::size_t chunk_id(T id) noexcept
Definition id_set.hpp:208
osmium::index::IdSetDense::last
T last() const noexcept
Definition id_set.hpp:220
osmium::index::IdSetDense::swap
friend void swap(IdSetDense &first, IdSetDense &second) noexcept
Definition id_set.hpp:243
osmium::index::IdSetDense::size
T size() const noexcept
Definition id_set.hpp:345
osmium::index::IdSetDense::clear
void clear() final
Definition id_set.hpp:352
osmium::index::IdSetDense::end
const_iterator end() const
Definition id_set.hpp:365
osmium::index::IdSetDense::offset
static std::size_t offset(T id) noexcept
Definition id_set.hpp:212
osmium::index::IdSetDense::bitmask
static unsigned int bitmask(T id) noexcept
Definition id_set.hpp:216
osmium::index::IdSetDense::get_element
unsigned char & get_element(T id)
Definition id_set.hpp:224
osmium::index::IdSetDense::unset
void unset(T id)
Definition id_set.hpp:310
osmium::index::IdSetDense::IdSetDense
IdSetDense()=default
osmium::index::IdSetDense::used_memory
std::size_t used_memory() const noexcept final
Definition id_set.hpp:357
osmium::index::IdSetDense::get
bool get(T id) const noexcept final
Definition id_set.hpp:324
osmium::index::IdSetDense::empty
bool empty() const noexcept final
Definition id_set.hpp:338
osmium::index::IdSetSmall
Definition id_set.hpp:376
osmium::index::IdSetSmall::used_memory
std::size_t used_memory() const noexcept final
Definition id_set.hpp:461
osmium::index::IdSetSmall::const_iterator
typename std::vector< T >::const_iterator const_iterator
Iterator type. There is no non-const iterator.
Definition id_set.hpp:482
osmium::index::IdSetSmall::merge_sorted
void merge_sorted(const IdSetSmall< T > &other)
Definition id_set.hpp:471
osmium::index::IdSetSmall::cend
const_iterator cend() const noexcept
Definition id_set.hpp:496
osmium::index::IdSetSmall::begin
const_iterator begin() const noexcept
Definition id_set.hpp:484
osmium::index::IdSetSmall::IdSetSmall
IdSetSmall(const IdSetSmall &)=default
osmium::index::IdSetSmall::end
const_iterator end() const noexcept
Definition id_set.hpp:488
osmium::index::IdSetSmall::IdSetSmall
IdSetSmall()=default
osmium::index::IdSetSmall::cbegin
const_iterator cbegin() const noexcept
Definition id_set.hpp:492
osmium::index::IdSetSmall::m_data
std::vector< T > m_data
Definition id_set.hpp:378
osmium::index::IdSetSmall::get_binary_search
bool get_binary_search(T id) const noexcept
Definition id_set.hpp:421
osmium::index::IdSetSmall::empty
bool empty() const noexcept final
Definition id_set.hpp:428
osmium::index::IdSetSmall::get
bool get(T id) const noexcept final
Definition id_set.hpp:406
osmium::index::IdSetSmall::clear
void clear() final
Definition id_set.hpp:435
osmium::index::IdSetSmall::operator=
IdSetSmall & operator=(const IdSetSmall &)=default
osmium::index::IdSetSmall::sort_unique
void sort_unique()
Definition id_set.hpp:444
osmium::index::IdSetSmall::IdSetSmall
IdSetSmall(IdSetSmall &&) noexcept=default
osmium::index::IdSetSmall::size
std::size_t size() const noexcept
Definition id_set.hpp:457
osmium::index::IdSet
Definition id_set.hpp:58
osmium::index::IdSet::empty
virtual bool empty() const =0
osmium::index::IdSet::used_memory
virtual std::size_t used_memory() const noexcept=0
osmium::index::IdSet::IdSet
IdSet(const IdSet &)=default
osmium::index::IdSet::operator=
IdSet & operator=(const IdSet &)=default
osmium::index::IdSet::clear
virtual void clear()=0
osmium::index::IdSet::get
virtual bool get(T id) const noexcept=0
osmium::index::IdSet::set
virtual void set(T id)=0
osmium::index::IdSet::IdSet
IdSet()=default
osmium::index::IdSet::IdSet
IdSet(IdSet &&) noexcept=default
item_type.hpp
detail
Definition attr.hpp:342
osmium
Namespace for everything in the Osmium library.
Definition assembler.hpp:53
std
Definition location.hpp:555
types.hpp