git-subtree-dir: third_party/immer git-subtree-split: ad3e3556d38bb75966dd24c61a774970a7c7957e
148 lines
3.8 KiB
C++
148 lines
3.8 KiB
C++
//
|
|
// immer: immutable data structures for C++
|
|
// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
|
|
//
|
|
// This software is distributed under the Boost Software License, Version 1.0.
|
|
// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
|
|
//
|
|
|
|
#pragma once
|
|
|
|
#include <immer/detail/hamts/champ.hpp>
|
|
#include <immer/detail/iterator_facade.hpp>
|
|
|
|
namespace immer {
|
|
namespace detail {
|
|
namespace hamts {
|
|
|
|
template <typename T, typename Hash, typename Eq, typename MP, bits_t B>
|
|
struct champ_iterator
|
|
: iterator_facade<champ_iterator<T, Hash, Eq, MP, B>,
|
|
std::forward_iterator_tag,
|
|
T,
|
|
const T&,
|
|
std::ptrdiff_t,
|
|
const T*>
|
|
{
|
|
using tree_t = champ<T, Hash, Eq, MP, B>;
|
|
using node_t = typename tree_t::node_t;
|
|
|
|
struct end_t
|
|
{};
|
|
|
|
champ_iterator() = default;
|
|
|
|
champ_iterator(const tree_t& v)
|
|
: depth_{0}
|
|
{
|
|
if (v.root->datamap()) {
|
|
cur_ = v.root->values();
|
|
end_ = v.root->values() + popcount(v.root->datamap());
|
|
} else {
|
|
cur_ = end_ = nullptr;
|
|
}
|
|
path_[0] = &v.root;
|
|
ensure_valid_();
|
|
}
|
|
|
|
champ_iterator(const tree_t& v, end_t)
|
|
: cur_{nullptr}
|
|
, end_{nullptr}
|
|
, depth_{0}
|
|
{
|
|
path_[0] = &v.root;
|
|
}
|
|
|
|
champ_iterator(const champ_iterator& other)
|
|
: cur_{other.cur_}
|
|
, end_{other.end_}
|
|
, depth_{other.depth_}
|
|
{
|
|
std::copy(other.path_, other.path_ + depth_ + 1, path_);
|
|
}
|
|
|
|
private:
|
|
friend iterator_core_access;
|
|
|
|
T* cur_;
|
|
T* end_;
|
|
count_t depth_;
|
|
node_t* const* path_[max_depth<B> + 1];
|
|
|
|
void increment()
|
|
{
|
|
++cur_;
|
|
ensure_valid_();
|
|
}
|
|
|
|
bool step_down()
|
|
{
|
|
if (depth_ < max_depth<B>) {
|
|
auto parent = *path_[depth_];
|
|
if (parent->nodemap()) {
|
|
++depth_;
|
|
path_[depth_] = parent->children();
|
|
auto child = *path_[depth_];
|
|
if (depth_ < max_depth<B>) {
|
|
if (child->datamap()) {
|
|
cur_ = child->values();
|
|
end_ = cur_ + popcount(child->datamap());
|
|
}
|
|
} else {
|
|
cur_ = child->collisions();
|
|
end_ = cur_ + child->collision_count();
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool step_right()
|
|
{
|
|
while (depth_ > 0) {
|
|
auto parent = *path_[depth_ - 1];
|
|
auto last = parent->children() + popcount(parent->nodemap());
|
|
auto next = path_[depth_] + 1;
|
|
if (next < last) {
|
|
path_[depth_] = next;
|
|
auto child = *path_[depth_];
|
|
if (depth_ < max_depth<B>) {
|
|
if (child->datamap()) {
|
|
cur_ = child->values();
|
|
end_ = cur_ + popcount(child->datamap());
|
|
}
|
|
} else {
|
|
cur_ = child->collisions();
|
|
end_ = cur_ + child->collision_count();
|
|
}
|
|
return true;
|
|
}
|
|
--depth_;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void ensure_valid_()
|
|
{
|
|
while (cur_ == end_) {
|
|
while (step_down())
|
|
if (cur_ != end_)
|
|
return;
|
|
if (!step_right()) {
|
|
// end of sequence
|
|
assert(depth_ == 0);
|
|
cur_ = end_ = nullptr;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool equal(const champ_iterator& other) const { return cur_ == other.cur_; }
|
|
|
|
const T& dereference() const { return *cur_; }
|
|
};
|
|
|
|
} // namespace hamts
|
|
} // namespace detail
|
|
} // namespace immer
|