1977 lines
63 KiB
C++
1977 lines
63 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/config.hpp>
|
|
#include <immer/detail/rbts/bits.hpp>
|
|
|
|
#include <cassert>
|
|
#include <type_traits>
|
|
#include <utility>
|
|
|
|
namespace immer {
|
|
namespace detail {
|
|
namespace rbts {
|
|
|
|
template <typename Pos>
|
|
constexpr auto bits = std::decay_t<Pos>::node_t::bits;
|
|
|
|
template <typename Pos>
|
|
constexpr auto bits_leaf = std::decay_t<Pos>::node_t::bits_leaf;
|
|
|
|
template <typename Pos>
|
|
using node_type = typename std::decay<Pos>::type::node_t;
|
|
|
|
template <typename Pos>
|
|
using edit_type = typename std::decay<Pos>::type::node_t::edit_t;
|
|
|
|
template <typename NodeT>
|
|
struct empty_regular_pos
|
|
{
|
|
using node_t = NodeT;
|
|
node_t* node_;
|
|
|
|
count_t count() const { return 0; }
|
|
node_t* node() const { return node_; }
|
|
shift_t shift() const { return 0; }
|
|
size_t size() const { return 0; }
|
|
|
|
template <typename Visitor, typename... Args>
|
|
void each(Visitor, Args&&...)
|
|
{}
|
|
template <typename Visitor, typename... Args>
|
|
bool each_pred(Visitor, Args&&...)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto) visit(Visitor v, Args&&... args)
|
|
{
|
|
return Visitor::visit_regular(*this, std::forward<Args>(args)...);
|
|
}
|
|
};
|
|
|
|
template <typename NodeT>
|
|
empty_regular_pos<NodeT> make_empty_regular_pos(NodeT* node)
|
|
{
|
|
return {node};
|
|
}
|
|
|
|
template <typename NodeT>
|
|
struct empty_leaf_pos
|
|
{
|
|
using node_t = NodeT;
|
|
node_t* node_;
|
|
|
|
count_t count() const { return 0; }
|
|
node_t* node() const { return node_; }
|
|
shift_t shift() const { return 0; }
|
|
size_t size() const { return 0; }
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto) visit(Visitor v, Args&&... args)
|
|
{
|
|
return Visitor::visit_leaf(*this, std::forward<Args>(args)...);
|
|
}
|
|
};
|
|
|
|
template <typename NodeT>
|
|
empty_leaf_pos<NodeT> make_empty_leaf_pos(NodeT* node)
|
|
{
|
|
assert(node);
|
|
return {node};
|
|
}
|
|
|
|
template <typename NodeT>
|
|
struct leaf_pos
|
|
{
|
|
static constexpr auto B = NodeT::bits;
|
|
static constexpr auto BL = NodeT::bits_leaf;
|
|
|
|
using node_t = NodeT;
|
|
node_t* node_;
|
|
size_t size_;
|
|
|
|
count_t count() const { return index(size_ - 1) + 1; }
|
|
node_t* node() const { return node_; }
|
|
size_t size() const { return size_; }
|
|
shift_t shift() const { return 0; }
|
|
count_t index(size_t idx) const { return idx & mask<BL>; }
|
|
count_t subindex(size_t idx) const { return idx; }
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto) visit(Visitor v, Args&&... args)
|
|
{
|
|
return Visitor::visit_leaf(*this, std::forward<Args>(args)...);
|
|
}
|
|
};
|
|
|
|
template <typename NodeT>
|
|
leaf_pos<NodeT> make_leaf_pos(NodeT* node, size_t size)
|
|
{
|
|
assert(node);
|
|
assert(size > 0);
|
|
return {node, size};
|
|
}
|
|
|
|
template <typename NodeT>
|
|
struct leaf_sub_pos
|
|
{
|
|
static constexpr auto B = NodeT::bits;
|
|
static constexpr auto BL = NodeT::bits_leaf;
|
|
|
|
using node_t = NodeT;
|
|
node_t* node_;
|
|
count_t count_;
|
|
|
|
count_t count() const { return count_; }
|
|
node_t* node() const { return node_; }
|
|
size_t size() const { return count_; }
|
|
shift_t shift() const { return 0; }
|
|
count_t index(size_t idx) const { return idx & mask<BL>; }
|
|
count_t subindex(size_t idx) const { return idx; }
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto) visit(Visitor v, Args&&... args)
|
|
{
|
|
return Visitor::visit_leaf(*this, std::forward<Args>(args)...);
|
|
}
|
|
};
|
|
|
|
template <typename NodeT>
|
|
leaf_sub_pos<NodeT> make_leaf_sub_pos(NodeT* node, count_t count)
|
|
{
|
|
assert(node);
|
|
assert(count <= branches<NodeT::bits_leaf>);
|
|
return {node, count};
|
|
}
|
|
|
|
template <typename NodeT>
|
|
struct leaf_descent_pos
|
|
{
|
|
static constexpr auto B = NodeT::bits;
|
|
static constexpr auto BL = NodeT::bits_leaf;
|
|
|
|
using node_t = NodeT;
|
|
node_t* node_;
|
|
|
|
node_t* node() const { return node_; }
|
|
shift_t shift() const { return 0; }
|
|
count_t index(size_t idx) const { return idx & mask<BL>; }
|
|
|
|
template <typename... Args>
|
|
decltype(auto) descend(Args&&...)
|
|
{}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto) visit(Visitor v, Args&&... args)
|
|
{
|
|
return Visitor::visit_leaf(*this, std::forward<Args>(args)...);
|
|
}
|
|
};
|
|
|
|
template <typename NodeT>
|
|
leaf_descent_pos<NodeT> make_leaf_descent_pos(NodeT* node)
|
|
{
|
|
assert(node);
|
|
return {node};
|
|
}
|
|
|
|
template <typename NodeT>
|
|
struct full_leaf_pos
|
|
{
|
|
static constexpr auto B = NodeT::bits;
|
|
static constexpr auto BL = NodeT::bits_leaf;
|
|
|
|
using node_t = NodeT;
|
|
node_t* node_;
|
|
|
|
count_t count() const { return branches<BL>; }
|
|
node_t* node() const { return node_; }
|
|
size_t size() const { return branches<BL>; }
|
|
shift_t shift() const { return 0; }
|
|
count_t index(size_t idx) const { return idx & mask<BL>; }
|
|
count_t subindex(size_t idx) const { return idx; }
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto) visit(Visitor v, Args&&... args)
|
|
{
|
|
return Visitor::visit_leaf(*this, std::forward<Args>(args)...);
|
|
}
|
|
};
|
|
|
|
template <typename NodeT>
|
|
full_leaf_pos<NodeT> make_full_leaf_pos(NodeT* node)
|
|
{
|
|
assert(node);
|
|
return {node};
|
|
}
|
|
|
|
template <typename NodeT>
|
|
struct regular_pos
|
|
{
|
|
static constexpr auto B = NodeT::bits;
|
|
static constexpr auto BL = NodeT::bits_leaf;
|
|
|
|
using node_t = NodeT;
|
|
node_t* node_;
|
|
shift_t shift_;
|
|
size_t size_;
|
|
|
|
count_t count() const { return index(size_ - 1) + 1; }
|
|
node_t* node() const { return node_; }
|
|
size_t size() const { return size_; }
|
|
shift_t shift() const { return shift_; }
|
|
count_t index(size_t idx) const { return (idx >> shift_) & mask<B>; }
|
|
count_t subindex(size_t idx) const { return idx >> shift_; }
|
|
size_t this_size() const
|
|
{
|
|
return ((size_ - 1) & ~(~size_t{} << (shift_ + B))) + 1;
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
void each(Visitor v, Args&&... args)
|
|
{
|
|
return each_regular(*this, v, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
bool each_pred(Visitor v, Args&&... args)
|
|
{
|
|
return each_pred_regular(*this, v, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
bool each_pred_zip(Visitor v, node_t* other, Args&&... args)
|
|
{
|
|
return each_pred_zip_regular(*this, v, other, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
bool each_pred_i(Visitor v, count_t i, count_t n, Args&&... args)
|
|
{
|
|
return each_pred_i_regular(*this, v, i, n, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
bool each_pred_right(Visitor v, count_t start, Args&&... args)
|
|
{
|
|
return each_pred_right_regular(*this, v, start, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
bool each_pred_left(Visitor v, count_t n, Args&&... args)
|
|
{
|
|
return each_pred_left_regular(*this, v, n, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
void each_i(Visitor v, count_t i, count_t n, Args&&... args)
|
|
{
|
|
return each_i_regular(*this, v, i, n, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
void each_right(Visitor v, count_t start, Args&&... args)
|
|
{
|
|
return each_right_regular(*this, v, start, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
void each_left(Visitor v, count_t n, Args&&... args)
|
|
{
|
|
return each_left_regular(*this, v, n, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto) towards(Visitor v, size_t idx, Args&&... args)
|
|
{
|
|
return towards_oh_ch_regular(
|
|
*this, v, idx, index(idx), count(), args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto)
|
|
towards_oh(Visitor v, size_t idx, count_t offset_hint, Args&&... args)
|
|
{
|
|
return towards_oh_ch_regular(
|
|
*this, v, idx, offset_hint, count(), args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto) towards_oh_ch(Visitor v,
|
|
size_t idx,
|
|
count_t offset_hint,
|
|
count_t count_hint,
|
|
Args&&... args)
|
|
{
|
|
return towards_oh_ch_regular(
|
|
*this, v, idx, offset_hint, count(), args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto)
|
|
towards_sub_oh(Visitor v, size_t idx, count_t offset_hint, Args&&... args)
|
|
{
|
|
return towards_sub_oh_regular(*this, v, idx, offset_hint, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto) last_oh(Visitor v, count_t offset_hint, Args&&... args)
|
|
{
|
|
return last_oh_regular(*this, v, offset_hint, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto) visit(Visitor v, Args&&... args)
|
|
{
|
|
return Visitor::visit_regular(*this, std::forward<Args>(args)...);
|
|
}
|
|
};
|
|
|
|
template <typename Pos, typename Visitor, typename... Args>
|
|
void each_regular(Pos&& p, Visitor v, Args&&... args)
|
|
{
|
|
constexpr auto B = bits<Pos>;
|
|
constexpr auto BL = bits_leaf<Pos>;
|
|
auto n = p.node()->inner();
|
|
auto last = p.count() - 1;
|
|
auto e = n + last;
|
|
if (p.shift() == BL) {
|
|
for (; n != e; ++n) {
|
|
IMMER_PREFETCH(n + 1);
|
|
make_full_leaf_pos(*n).visit(v, args...);
|
|
}
|
|
make_leaf_pos(*n, p.size()).visit(v, args...);
|
|
} else {
|
|
auto ss = p.shift() - B;
|
|
for (; n != e; ++n)
|
|
make_full_pos(*n, ss).visit(v, args...);
|
|
make_regular_pos(*n, ss, p.size()).visit(v, args...);
|
|
}
|
|
}
|
|
|
|
template <typename Pos, typename Visitor, typename... Args>
|
|
bool each_pred_regular(Pos&& p, Visitor v, Args&&... args)
|
|
{
|
|
constexpr auto B = bits<Pos>;
|
|
constexpr auto BL = bits_leaf<Pos>;
|
|
auto n = p.node()->inner();
|
|
auto last = p.count() - 1;
|
|
auto e = n + last;
|
|
if (p.shift() == BL) {
|
|
for (; n != e; ++n) {
|
|
IMMER_PREFETCH(n + 1);
|
|
if (!make_full_leaf_pos(*n).visit(v, args...))
|
|
return false;
|
|
}
|
|
return make_leaf_pos(*n, p.size()).visit(v, args...);
|
|
} else {
|
|
auto ss = p.shift() - B;
|
|
for (; n != e; ++n)
|
|
if (!make_full_pos(*n, ss).visit(v, args...))
|
|
return false;
|
|
return make_regular_pos(*n, ss, p.size()).visit(v, args...);
|
|
}
|
|
}
|
|
|
|
template <typename Pos, typename Visitor, typename... Args>
|
|
bool each_pred_zip_regular(Pos&& p,
|
|
Visitor v,
|
|
node_type<Pos>* other,
|
|
Args&&... args)
|
|
{
|
|
constexpr auto B = bits<Pos>;
|
|
constexpr auto BL = bits_leaf<Pos>;
|
|
|
|
auto n = p.node()->inner();
|
|
auto n2 = other->inner();
|
|
auto last = p.count() - 1;
|
|
auto e = n + last;
|
|
if (p.shift() == BL) {
|
|
for (; n != e; ++n, ++n2) {
|
|
IMMER_PREFETCH(n + 1);
|
|
IMMER_PREFETCH(n2 + 1);
|
|
if (!make_full_leaf_pos(*n).visit(v, *n2, args...))
|
|
return false;
|
|
}
|
|
return make_leaf_pos(*n, p.size()).visit(v, *n2, args...);
|
|
} else {
|
|
auto ss = p.shift() - B;
|
|
for (; n != e; ++n, ++n2)
|
|
if (!make_full_pos(*n, ss).visit(v, *n2, args...))
|
|
return false;
|
|
return make_regular_pos(*n, ss, p.size()).visit(v, *n2, args...);
|
|
}
|
|
}
|
|
|
|
template <typename Pos, typename Visitor, typename... Args>
|
|
bool each_pred_i_regular(
|
|
Pos&& p, Visitor v, count_t f, count_t l, Args&&... args)
|
|
{
|
|
constexpr auto B = bits<Pos>;
|
|
constexpr auto BL = bits_leaf<Pos>;
|
|
|
|
if (p.shift() == BL) {
|
|
if (l > f) {
|
|
if (l < p.count()) {
|
|
auto n = p.node()->inner() + f;
|
|
auto e = p.node()->inner() + l;
|
|
for (; n < e; ++n) {
|
|
IMMER_PREFETCH(n + 1);
|
|
if (!make_full_leaf_pos(*n).visit(v, args...))
|
|
return false;
|
|
}
|
|
} else {
|
|
auto n = p.node()->inner() + f;
|
|
auto e = p.node()->inner() + l - 1;
|
|
for (; n < e; ++n) {
|
|
IMMER_PREFETCH(n + 1);
|
|
if (!make_full_leaf_pos(*n).visit(v, args...))
|
|
return false;
|
|
}
|
|
if (!make_leaf_pos(*n, p.size()).visit(v, args...))
|
|
return false;
|
|
}
|
|
}
|
|
} else {
|
|
if (l > f) {
|
|
auto ss = p.shift() - B;
|
|
if (l < p.count()) {
|
|
auto n = p.node()->inner() + f;
|
|
auto e = p.node()->inner() + l;
|
|
for (; n < e; ++n)
|
|
if (!make_full_pos(*n, ss).visit(v, args...))
|
|
return false;
|
|
} else {
|
|
auto n = p.node()->inner() + f;
|
|
auto e = p.node()->inner() + l - 1;
|
|
for (; n < e; ++n)
|
|
if (!make_full_pos(*n, ss).visit(v, args...))
|
|
return false;
|
|
if (!make_regular_pos(*n, ss, p.size()).visit(v, args...))
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
template <typename Pos, typename Visitor, typename... Args>
|
|
bool each_pred_left_regular(Pos&& p, Visitor v, count_t last, Args&&... args)
|
|
{
|
|
constexpr auto B = bits<Pos>;
|
|
constexpr auto BL = bits_leaf<Pos>;
|
|
assert(last < p.count());
|
|
if (p.shift() == BL) {
|
|
auto n = p.node()->inner();
|
|
auto e = n + last;
|
|
for (; n != e; ++n) {
|
|
IMMER_PREFETCH(n + 1);
|
|
if (!make_full_leaf_pos(*n).visit(v, args...))
|
|
return false;
|
|
}
|
|
} else {
|
|
auto n = p.node()->inner();
|
|
auto e = n + last;
|
|
auto ss = p.shift() - B;
|
|
for (; n != e; ++n)
|
|
if (!make_full_pos(*n, ss).visit(v, args...))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
template <typename Pos, typename Visitor, typename... Args>
|
|
bool each_pred_right_regular(Pos&& p, Visitor v, count_t start, Args&&... args)
|
|
{
|
|
constexpr auto B = bits<Pos>;
|
|
constexpr auto BL = bits_leaf<Pos>;
|
|
|
|
if (p.shift() == BL) {
|
|
auto n = p.node()->inner() + start;
|
|
auto last = p.count() - 1;
|
|
auto e = p.node()->inner() + last;
|
|
if (n <= e) {
|
|
for (; n != e; ++n) {
|
|
IMMER_PREFETCH(n + 1);
|
|
if (!make_full_leaf_pos(*n).visit(v, args...))
|
|
return false;
|
|
}
|
|
if (!make_leaf_pos(*n, p.size()).visit(v, args...))
|
|
return false;
|
|
}
|
|
} else {
|
|
auto n = p.node()->inner() + start;
|
|
auto last = p.count() - 1;
|
|
auto e = p.node()->inner() + last;
|
|
auto ss = p.shift() - B;
|
|
if (n <= e) {
|
|
for (; n != e; ++n)
|
|
if (!make_full_pos(*n, ss).visit(v, args...))
|
|
return false;
|
|
if (!make_regular_pos(*n, ss, p.size()).visit(v, args...))
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
template <typename Pos, typename Visitor, typename... Args>
|
|
void each_i_regular(Pos&& p, Visitor v, count_t f, count_t l, Args&&... args)
|
|
{
|
|
constexpr auto B = bits<Pos>;
|
|
constexpr auto BL = bits_leaf<Pos>;
|
|
|
|
if (p.shift() == BL) {
|
|
if (l > f) {
|
|
if (l < p.count()) {
|
|
auto n = p.node()->inner() + f;
|
|
auto e = p.node()->inner() + l;
|
|
for (; n < e; ++n) {
|
|
IMMER_PREFETCH(n + 1);
|
|
make_full_leaf_pos(*n).visit(v, args...);
|
|
}
|
|
} else {
|
|
auto n = p.node()->inner() + f;
|
|
auto e = p.node()->inner() + l - 1;
|
|
for (; n < e; ++n) {
|
|
IMMER_PREFETCH(n + 1);
|
|
make_full_leaf_pos(*n).visit(v, args...);
|
|
}
|
|
make_leaf_pos(*n, p.size()).visit(v, args...);
|
|
}
|
|
}
|
|
} else {
|
|
if (l > f) {
|
|
auto ss = p.shift() - B;
|
|
if (l < p.count()) {
|
|
auto n = p.node()->inner() + f;
|
|
auto e = p.node()->inner() + l;
|
|
for (; n < e; ++n)
|
|
make_full_pos(*n, ss).visit(v, args...);
|
|
} else {
|
|
auto n = p.node()->inner() + f;
|
|
auto e = p.node()->inner() + l - 1;
|
|
for (; n < e; ++n)
|
|
make_full_pos(*n, ss).visit(v, args...);
|
|
make_regular_pos(*n, ss, p.size()).visit(v, args...);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
template <typename Pos, typename Visitor, typename... Args>
|
|
void each_left_regular(Pos&& p, Visitor v, count_t last, Args&&... args)
|
|
{
|
|
constexpr auto B = bits<Pos>;
|
|
constexpr auto BL = bits_leaf<Pos>;
|
|
assert(last < p.count());
|
|
if (p.shift() == BL) {
|
|
auto n = p.node()->inner();
|
|
auto e = n + last;
|
|
for (; n != e; ++n) {
|
|
IMMER_PREFETCH(n + 1);
|
|
make_full_leaf_pos(*n).visit(v, args...);
|
|
}
|
|
} else {
|
|
auto n = p.node()->inner();
|
|
auto e = n + last;
|
|
auto ss = p.shift() - B;
|
|
for (; n != e; ++n)
|
|
make_full_pos(*n, ss).visit(v, args...);
|
|
}
|
|
}
|
|
|
|
template <typename Pos, typename Visitor, typename... Args>
|
|
void each_right_regular(Pos&& p, Visitor v, count_t start, Args&&... args)
|
|
{
|
|
constexpr auto B = bits<Pos>;
|
|
constexpr auto BL = bits_leaf<Pos>;
|
|
|
|
if (p.shift() == BL) {
|
|
auto n = p.node()->inner() + start;
|
|
auto last = p.count() - 1;
|
|
auto e = p.node()->inner() + last;
|
|
if (n <= e) {
|
|
for (; n != e; ++n) {
|
|
IMMER_PREFETCH(n + 1);
|
|
make_full_leaf_pos(*n).visit(v, args...);
|
|
}
|
|
make_leaf_pos(*n, p.size()).visit(v, args...);
|
|
}
|
|
} else {
|
|
auto n = p.node()->inner() + start;
|
|
auto last = p.count() - 1;
|
|
auto e = p.node()->inner() + last;
|
|
auto ss = p.shift() - B;
|
|
if (n <= e) {
|
|
for (; n != e; ++n)
|
|
make_full_pos(*n, ss).visit(v, args...);
|
|
make_regular_pos(*n, ss, p.size()).visit(v, args...);
|
|
}
|
|
}
|
|
}
|
|
|
|
template <typename Pos, typename Visitor, typename... Args>
|
|
decltype(auto) towards_oh_ch_regular(Pos&& p,
|
|
Visitor v,
|
|
size_t idx,
|
|
count_t offset_hint,
|
|
count_t count_hint,
|
|
Args&&... args)
|
|
{
|
|
constexpr auto B = bits<Pos>;
|
|
constexpr auto BL = bits_leaf<Pos>;
|
|
assert(offset_hint == p.index(idx));
|
|
assert(count_hint == p.count());
|
|
auto is_leaf = p.shift() == BL;
|
|
auto child = p.node()->inner()[offset_hint];
|
|
auto is_full = offset_hint + 1 != count_hint;
|
|
return is_full
|
|
? (is_leaf ? make_full_leaf_pos(child).visit(v, idx, args...)
|
|
: make_full_pos(child, p.shift() - B)
|
|
.visit(v, idx, args...))
|
|
: (is_leaf
|
|
? make_leaf_pos(child, p.size()).visit(v, idx, args...)
|
|
: make_regular_pos(child, p.shift() - B, p.size())
|
|
.visit(v, idx, args...));
|
|
}
|
|
|
|
template <typename Pos, typename Visitor, typename... Args>
|
|
decltype(auto) towards_sub_oh_regular(
|
|
Pos&& p, Visitor v, size_t idx, count_t offset_hint, Args&&... args)
|
|
{
|
|
constexpr auto B = bits<Pos>;
|
|
constexpr auto BL = bits_leaf<Pos>;
|
|
assert(offset_hint == p.index(idx));
|
|
auto is_leaf = p.shift() == BL;
|
|
auto child = p.node()->inner()[offset_hint];
|
|
auto lsize = offset_hint << p.shift();
|
|
auto size = p.this_size();
|
|
auto is_full = (size - lsize) >= (size_t{1} << p.shift());
|
|
return is_full
|
|
? (is_leaf
|
|
? make_full_leaf_pos(child).visit(v, idx - lsize, args...)
|
|
: make_full_pos(child, p.shift() - B)
|
|
.visit(v, idx - lsize, args...))
|
|
: (is_leaf
|
|
? make_leaf_sub_pos(child, size - lsize)
|
|
.visit(v, idx - lsize, args...)
|
|
: make_regular_sub_pos(child, p.shift() - B, size - lsize)
|
|
.visit(v, idx - lsize, args...));
|
|
}
|
|
|
|
template <typename Pos, typename Visitor, typename... Args>
|
|
decltype(auto)
|
|
last_oh_regular(Pos&& p, Visitor v, count_t offset_hint, Args&&... args)
|
|
{
|
|
assert(offset_hint == p.count() - 1);
|
|
constexpr auto B = bits<Pos>;
|
|
constexpr auto BL = bits_leaf<Pos>;
|
|
auto child = p.node()->inner()[offset_hint];
|
|
auto is_leaf = p.shift() == BL;
|
|
return is_leaf ? make_leaf_pos(child, p.size()).visit(v, args...)
|
|
: make_regular_pos(child, p.shift() - B, p.size())
|
|
.visit(v, args...);
|
|
}
|
|
|
|
template <typename NodeT>
|
|
regular_pos<NodeT> make_regular_pos(NodeT* node, shift_t shift, size_t size)
|
|
{
|
|
assert(node);
|
|
assert(shift >= NodeT::bits_leaf);
|
|
assert(size > 0);
|
|
return {node, shift, size};
|
|
}
|
|
|
|
struct null_sub_pos
|
|
{
|
|
auto node() const { return nullptr; }
|
|
|
|
template <typename Visitor, typename... Args>
|
|
void each_sub(Visitor, Args&&...)
|
|
{}
|
|
template <typename Visitor, typename... Args>
|
|
void each_right_sub(Visitor, Args&&...)
|
|
{}
|
|
template <typename Visitor, typename... Args>
|
|
void each_left_sub(Visitor, Args&&...)
|
|
{}
|
|
template <typename Visitor, typename... Args>
|
|
void visit(Visitor, Args&&...)
|
|
{}
|
|
};
|
|
|
|
template <typename NodeT>
|
|
struct singleton_regular_sub_pos
|
|
{
|
|
// this is a fake regular pos made out of a single child... useful
|
|
// to treat a single leaf node as a whole tree
|
|
|
|
static constexpr auto B = NodeT::bits;
|
|
static constexpr auto BL = NodeT::bits_leaf;
|
|
|
|
using node_t = NodeT;
|
|
node_t* leaf_;
|
|
count_t count_;
|
|
|
|
count_t count() const { return 1; }
|
|
node_t* node() const { return nullptr; }
|
|
size_t size() const { return count_; }
|
|
shift_t shift() const { return BL; }
|
|
count_t index(size_t idx) const { return 0; }
|
|
count_t subindex(size_t idx) const { return 0; }
|
|
size_t size_before(count_t offset) const { return 0; }
|
|
size_t this_size() const { return count_; }
|
|
size_t size(count_t offset) { return count_; }
|
|
|
|
template <typename Visitor, typename... Args>
|
|
void each_left_sub(Visitor v, Args&&... args)
|
|
{}
|
|
template <typename Visitor, typename... Args>
|
|
void each(Visitor v, Args&&... args)
|
|
{}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto) last_sub(Visitor v, Args&&... args)
|
|
{
|
|
return make_leaf_sub_pos(leaf_, count_).visit(v, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto) visit(Visitor v, Args&&... args)
|
|
{
|
|
return Visitor::visit_regular(*this, std::forward<Args>(args)...);
|
|
}
|
|
};
|
|
|
|
template <typename NodeT>
|
|
auto make_singleton_regular_sub_pos(NodeT* leaf, count_t count)
|
|
{
|
|
assert(leaf);
|
|
IMMER_ASSERT_TAGGED(leaf->kind() == NodeT::kind_t::leaf);
|
|
assert(count > 0);
|
|
return singleton_regular_sub_pos<NodeT>{leaf, count};
|
|
}
|
|
|
|
template <typename NodeT>
|
|
struct regular_sub_pos
|
|
{
|
|
static constexpr auto B = NodeT::bits;
|
|
static constexpr auto BL = NodeT::bits_leaf;
|
|
|
|
using node_t = NodeT;
|
|
node_t* node_;
|
|
shift_t shift_;
|
|
size_t size_;
|
|
|
|
count_t count() const { return subindex(size_ - 1) + 1; }
|
|
node_t* node() const { return node_; }
|
|
size_t size() const { return size_; }
|
|
shift_t shift() const { return shift_; }
|
|
count_t index(size_t idx) const { return (idx >> shift_) & mask<B>; }
|
|
count_t subindex(size_t idx) const { return idx >> shift_; }
|
|
size_t size_before(count_t offset) const { return offset << shift_; }
|
|
size_t this_size() const { return size_; }
|
|
|
|
auto size(count_t offset)
|
|
{
|
|
return offset == subindex(size_ - 1) ? size_ - size_before(offset)
|
|
: size_t{1} << shift_;
|
|
}
|
|
|
|
auto size_sbh(count_t offset, size_t size_before_hint)
|
|
{
|
|
assert(size_before_hint == size_before(offset));
|
|
return offset == subindex(size_ - 1) ? size_ - size_before_hint
|
|
: size_t{1} << shift_;
|
|
}
|
|
|
|
void copy_sizes(count_t offset, count_t n, size_t init, size_t* sizes)
|
|
{
|
|
if (n) {
|
|
auto last = offset + n - 1;
|
|
auto e = sizes + n - 1;
|
|
for (; sizes != e; ++sizes)
|
|
init = *sizes = init + (size_t{1} << shift_);
|
|
*sizes = init + size(last);
|
|
}
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
void each(Visitor v, Args&&... args)
|
|
{
|
|
return each_regular(*this, v, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
bool each_pred(Visitor v, Args&&... args)
|
|
{
|
|
return each_pred_regular(*this, v, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
bool each_pred_zip(Visitor v, node_t* other, Args&&... args)
|
|
{
|
|
return each_pred_zip_regular(*this, v, other, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
bool each_pred_i(Visitor v, count_t i, count_t n, Args&&... args)
|
|
{
|
|
return each_pred_i_regular(*this, v, i, n, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
bool each_pred_right(Visitor v, count_t start, Args&&... args)
|
|
{
|
|
return each_pred_right_regular(*this, v, start, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
bool each_pred_left(Visitor v, count_t last, Args&&... args)
|
|
{
|
|
return each_pred_left_regular(*this, v, last, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
void each_i(Visitor v, count_t i, count_t n, Args&&... args)
|
|
{
|
|
return each_i_regular(*this, v, i, n, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
void each_right(Visitor v, count_t start, Args&&... args)
|
|
{
|
|
return each_right_regular(*this, v, start, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
void each_left(Visitor v, count_t last, Args&&... args)
|
|
{
|
|
return each_left_regular(*this, v, last, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
void each_right_sub_(Visitor v, count_t i, Args&&... args)
|
|
{
|
|
auto last = count() - 1;
|
|
auto lsize = size_ - (last << shift_);
|
|
auto n = node()->inner() + i;
|
|
auto e = node()->inner() + last;
|
|
if (shift() == BL) {
|
|
for (; n != e; ++n) {
|
|
IMMER_PREFETCH(n + 1);
|
|
make_full_leaf_pos(*n).visit(v, args...);
|
|
}
|
|
make_leaf_sub_pos(*n, lsize).visit(v, args...);
|
|
} else {
|
|
auto ss = shift_ - B;
|
|
for (; n != e; ++n)
|
|
make_full_pos(*n, ss).visit(v, args...);
|
|
make_regular_sub_pos(*n, ss, lsize).visit(v, args...);
|
|
}
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
void each_sub(Visitor v, Args&&... args)
|
|
{
|
|
each_right_sub_(v, 0, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
void each_right_sub(Visitor v, Args&&... args)
|
|
{
|
|
if (count() > 1)
|
|
each_right_sub_(v, 1, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
void each_left_sub(Visitor v, Args&&... args)
|
|
{
|
|
each_left(v, count() - 1, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto) towards(Visitor v, size_t idx, Args&&... args)
|
|
{
|
|
return towards_oh_ch_regular(
|
|
*this, v, idx, index(idx), count(), args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto)
|
|
towards_oh(Visitor v, size_t idx, count_t offset_hint, Args&&... args)
|
|
{
|
|
return towards_oh_ch_regular(
|
|
*this, v, idx, offset_hint, count(), args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto) towards_oh_ch(Visitor v,
|
|
size_t idx,
|
|
count_t offset_hint,
|
|
count_t count_hint,
|
|
Args&&... args)
|
|
{
|
|
return towards_oh_ch_regular(
|
|
*this, v, idx, offset_hint, count(), args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto)
|
|
towards_sub_oh(Visitor v, size_t idx, count_t offset_hint, Args&&... args)
|
|
{
|
|
return towards_sub_oh_regular(*this, v, idx, offset_hint, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto) last_oh(Visitor v, count_t offset_hint, Args&&... args)
|
|
{
|
|
return last_oh_regular(*this, v, offset_hint, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto) last_sub(Visitor v, Args&&... args)
|
|
{
|
|
auto offset = count() - 1;
|
|
auto child = node_->inner()[offset];
|
|
auto is_leaf = shift_ == BL;
|
|
auto lsize = size_ - (offset << shift_);
|
|
return is_leaf ? make_leaf_sub_pos(child, lsize).visit(v, args...)
|
|
: make_regular_sub_pos(child, shift_ - B, lsize)
|
|
.visit(v, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto) first_sub(Visitor v, Args&&... args)
|
|
{
|
|
auto is_leaf = shift_ == BL;
|
|
auto child = node_->inner()[0];
|
|
auto is_full = size_ >= (size_t{1} << shift_);
|
|
return is_full
|
|
? (is_leaf
|
|
? make_full_leaf_pos(child).visit(v, args...)
|
|
: make_full_pos(child, shift_ - B).visit(v, args...))
|
|
: (is_leaf
|
|
? make_leaf_sub_pos(child, size_).visit(v, args...)
|
|
: make_regular_sub_pos(child, shift_ - B, size_)
|
|
.visit(v, args...));
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto) first_sub_leaf(Visitor v, Args&&... args)
|
|
{
|
|
assert(shift_ == BL);
|
|
auto child = node_->inner()[0];
|
|
auto is_full = size_ >= branches<BL>;
|
|
return is_full ? make_full_leaf_pos(child).visit(v, args...)
|
|
: make_leaf_sub_pos(child, size_).visit(v, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto) first_sub_inner(Visitor v, Args&&... args)
|
|
{
|
|
assert(shift_ >= BL);
|
|
auto child = node_->inner()[0];
|
|
auto is_full = size_ >= branches<BL>;
|
|
return is_full ? make_full_pos(child, shift_ - B).visit(v, args...)
|
|
: make_regular_sub_pos(child, shift_ - B, size_)
|
|
.visit(v, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto) nth_sub(count_t idx, Visitor v, Args&&... args)
|
|
{
|
|
assert(idx < count());
|
|
auto is_leaf = shift_ == BL;
|
|
auto child = node_->inner()[idx];
|
|
auto lsize = size(idx);
|
|
auto is_full = idx + 1 < count();
|
|
return is_full
|
|
? (is_leaf
|
|
? make_full_leaf_pos(child).visit(v, args...)
|
|
: make_full_pos(child, shift_ - B).visit(v, args...))
|
|
: (is_leaf
|
|
? make_leaf_sub_pos(child, lsize).visit(v, args...)
|
|
: make_regular_sub_pos(child, shift_ - B, lsize)
|
|
.visit(v, args...));
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto) nth_sub_leaf(count_t idx, Visitor v, Args&&... args)
|
|
{
|
|
assert(shift_ == BL);
|
|
auto child = node_->inner()[idx];
|
|
auto lsize = size(idx);
|
|
auto is_full = idx + 1 < count();
|
|
return is_full ? make_full_leaf_pos(child).visit(v, args...)
|
|
: make_leaf_sub_pos(child, lsize).visit(v, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto) visit(Visitor v, Args&&... args)
|
|
{
|
|
return Visitor::visit_regular(*this, std::forward<Args>(args)...);
|
|
}
|
|
};
|
|
|
|
template <typename NodeT>
|
|
regular_sub_pos<NodeT>
|
|
make_regular_sub_pos(NodeT* node, shift_t shift, size_t size)
|
|
{
|
|
assert(node);
|
|
assert(shift >= NodeT::bits_leaf);
|
|
assert(size > 0);
|
|
assert(size <= (branches<NodeT::bits, size_t> << shift));
|
|
return {node, shift, size};
|
|
}
|
|
|
|
template <typename NodeT,
|
|
shift_t Shift,
|
|
bits_t B = NodeT::bits,
|
|
bits_t BL = NodeT::bits_leaf>
|
|
struct regular_descent_pos
|
|
{
|
|
static_assert(Shift > 0, "not leaf...");
|
|
|
|
using node_t = NodeT;
|
|
node_t* node_;
|
|
|
|
node_t* node() const { return node_; }
|
|
shift_t shift() const { return Shift; }
|
|
count_t index(size_t idx) const
|
|
{
|
|
#if !defined(_MSC_VER)
|
|
#pragma GCC diagnostic push
|
|
#pragma GCC diagnostic ignored "-Wshift-count-overflow"
|
|
#endif
|
|
return (idx >> Shift) & mask<B>;
|
|
#if !defined(_MSC_VER)
|
|
#pragma GCC diagnostic pop
|
|
#endif
|
|
}
|
|
|
|
template <typename Visitor>
|
|
decltype(auto) descend(Visitor v, size_t idx)
|
|
{
|
|
auto offset = index(idx);
|
|
auto child = node_->inner()[offset];
|
|
return regular_descent_pos<NodeT, Shift - B>{child}.visit(v, idx);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto) visit(Visitor v, Args&&... args)
|
|
{
|
|
return Visitor::visit_regular(*this, std::forward<Args>(args)...);
|
|
}
|
|
};
|
|
|
|
template <typename NodeT, bits_t B, bits_t BL>
|
|
struct regular_descent_pos<NodeT, BL, B, BL>
|
|
{
|
|
using node_t = NodeT;
|
|
node_t* node_;
|
|
|
|
node_t* node() const { return node_; }
|
|
shift_t shift() const { return BL; }
|
|
count_t index(size_t idx) const { return (idx >> BL) & mask<B>; }
|
|
|
|
template <typename Visitor>
|
|
decltype(auto) descend(Visitor v, size_t idx)
|
|
{
|
|
auto offset = index(idx);
|
|
auto child = node_->inner()[offset];
|
|
return make_leaf_descent_pos(child).visit(v, idx);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto) visit(Visitor v, Args&&... args)
|
|
{
|
|
return Visitor::visit_regular(*this, std::forward<Args>(args)...);
|
|
}
|
|
};
|
|
|
|
template <typename NodeT, typename Visitor>
|
|
decltype(auto)
|
|
visit_regular_descent(NodeT* node, shift_t shift, Visitor v, size_t idx)
|
|
{
|
|
constexpr auto B = NodeT::bits;
|
|
constexpr auto BL = NodeT::bits_leaf;
|
|
assert(node);
|
|
assert(shift >= BL);
|
|
switch (shift) {
|
|
case BL + B * 0:
|
|
return regular_descent_pos<NodeT, BL + B * 0>{node}.visit(v, idx);
|
|
case BL + B * 1:
|
|
return regular_descent_pos<NodeT, BL + B * 1>{node}.visit(v, idx);
|
|
case BL + B * 2:
|
|
return regular_descent_pos<NodeT, BL + B * 2>{node}.visit(v, idx);
|
|
case BL + B * 3:
|
|
return regular_descent_pos<NodeT, BL + B * 3>{node}.visit(v, idx);
|
|
case BL + B * 4:
|
|
return regular_descent_pos<NodeT, BL + B * 4>{node}.visit(v, idx);
|
|
case BL + B * 5:
|
|
return regular_descent_pos<NodeT, BL + B * 5>{node}.visit(v, idx);
|
|
#if IMMER_DESCENT_DEEP
|
|
default:
|
|
for (auto level = shift; level != endshift<B, BL>; level -= B)
|
|
node = node->inner()[(idx >> level) & mask<B>];
|
|
return make_leaf_descent_pos(node).visit(v, idx);
|
|
#endif // IMMER_DEEP_DESCENT
|
|
}
|
|
IMMER_UNREACHABLE;
|
|
}
|
|
|
|
template <typename NodeT>
|
|
struct full_pos
|
|
{
|
|
static constexpr auto B = NodeT::bits;
|
|
static constexpr auto BL = NodeT::bits_leaf;
|
|
|
|
using node_t = NodeT;
|
|
node_t* node_;
|
|
shift_t shift_;
|
|
|
|
count_t count() const { return branches<B>; }
|
|
node_t* node() const { return node_; }
|
|
size_t size() const { return branches<B> << shift_; }
|
|
shift_t shift() const { return shift_; }
|
|
count_t index(size_t idx) const { return (idx >> shift_) & mask<B>; }
|
|
count_t subindex(size_t idx) const { return idx >> shift_; }
|
|
size_t size(count_t offset) const { return size_t{1} << shift_; }
|
|
size_t size_sbh(count_t offset, size_t) const
|
|
{
|
|
return size_t{1} << shift_;
|
|
}
|
|
size_t size_before(count_t offset) const { return offset << shift_; }
|
|
|
|
void copy_sizes(count_t offset, count_t n, size_t init, size_t* sizes)
|
|
{
|
|
auto e = sizes + n;
|
|
for (; sizes != e; ++sizes)
|
|
init = *sizes = init + (size_t{1} << shift_);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
void each(Visitor v, Args&&... args)
|
|
{
|
|
auto p = node_->inner();
|
|
auto e = p + branches<B>;
|
|
if (shift_ == BL) {
|
|
for (; p != e; ++p) {
|
|
IMMER_PREFETCH(p + 1);
|
|
make_full_leaf_pos(*p).visit(v, args...);
|
|
}
|
|
} else {
|
|
auto ss = shift_ - B;
|
|
for (; p != e; ++p)
|
|
make_full_pos(*p, ss).visit(v, args...);
|
|
}
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
bool each_pred(Visitor v, Args&&... args)
|
|
{
|
|
auto p = node_->inner();
|
|
auto e = p + branches<B>;
|
|
if (shift_ == BL) {
|
|
for (; p != e; ++p) {
|
|
IMMER_PREFETCH(p + 1);
|
|
if (!make_full_leaf_pos(*p).visit(v, args...))
|
|
return false;
|
|
}
|
|
} else {
|
|
auto ss = shift_ - B;
|
|
for (; p != e; ++p)
|
|
if (!make_full_pos(*p, ss).visit(v, args...))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
bool each_pred_zip(Visitor v, node_t* other, Args&&... args)
|
|
{
|
|
auto p = node_->inner();
|
|
auto p2 = other->inner();
|
|
auto e = p + branches<B>;
|
|
if (shift_ == BL) {
|
|
for (; p != e; ++p, ++p2) {
|
|
IMMER_PREFETCH(p + 1);
|
|
if (!make_full_leaf_pos(*p).visit(v, *p2, args...))
|
|
return false;
|
|
}
|
|
} else {
|
|
auto ss = shift_ - B;
|
|
for (; p != e; ++p, ++p2)
|
|
if (!make_full_pos(*p, ss).visit(v, *p2, args...))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
bool each_pred_i(Visitor v, count_t i, count_t n, Args&&... args)
|
|
{
|
|
auto p = node_->inner() + i;
|
|
auto e = node_->inner() + n;
|
|
if (shift_ == BL) {
|
|
for (; p != e; ++p) {
|
|
IMMER_PREFETCH(p + 1);
|
|
if (!make_full_leaf_pos(*p).visit(v, args...))
|
|
return false;
|
|
}
|
|
} else {
|
|
auto ss = shift_ - B;
|
|
for (; p != e; ++p)
|
|
if (!make_full_pos(*p, ss).visit(v, args...))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
void each_i(Visitor v, count_t i, count_t n, Args&&... args)
|
|
{
|
|
auto p = node_->inner() + i;
|
|
auto e = node_->inner() + n;
|
|
if (shift_ == BL) {
|
|
for (; p != e; ++p) {
|
|
IMMER_PREFETCH(p + 1);
|
|
make_full_leaf_pos(*p).visit(v, args...);
|
|
}
|
|
} else {
|
|
auto ss = shift_ - B;
|
|
for (; p != e; ++p)
|
|
make_full_pos(*p, ss).visit(v, args...);
|
|
}
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
bool each_pred_right(Visitor v, count_t start, Args&&... args)
|
|
{
|
|
return each_pred_i(v, start, branches<B>, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
bool each_pred_left(Visitor v, count_t last, Args&&... args)
|
|
{
|
|
return each_pred_i(v, 0, last, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
void each_sub(Visitor v, Args&&... args)
|
|
{
|
|
each(v, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
void each_left_sub(Visitor v, Args&&... args)
|
|
{
|
|
each_i(v, 0, branches<B> - 1, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
void each_right_sub(Visitor v, Args&&... args)
|
|
{
|
|
each_i(v, 1, branches<B>, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
void each_right(Visitor v, count_t start, Args&&... args)
|
|
{
|
|
each_i(v, start, branches<B>, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
void each_left(Visitor v, count_t last, Args&&... args)
|
|
{
|
|
each_i(v, 0, last, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto) towards(Visitor v, size_t idx, Args&&... args)
|
|
{
|
|
return towards_oh(v, idx, index(idx), args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto) towards_oh_ch(
|
|
Visitor v, size_t idx, count_t offset_hint, count_t, Args&&... args)
|
|
{
|
|
return towards_oh(v, idx, offset_hint, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto)
|
|
towards_oh(Visitor v, size_t idx, count_t offset_hint, Args&&... args)
|
|
{
|
|
assert(offset_hint == index(idx));
|
|
auto is_leaf = shift_ == BL;
|
|
auto child = node_->inner()[offset_hint];
|
|
return is_leaf
|
|
? make_full_leaf_pos(child).visit(v, idx, args...)
|
|
: make_full_pos(child, shift_ - B).visit(v, idx, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto)
|
|
towards_sub_oh(Visitor v, size_t idx, count_t offset_hint, Args&&... args)
|
|
{
|
|
assert(offset_hint == index(idx));
|
|
auto is_leaf = shift_ == BL;
|
|
auto child = node_->inner()[offset_hint];
|
|
auto lsize = offset_hint << shift_;
|
|
return is_leaf
|
|
? make_full_leaf_pos(child).visit(v, idx - lsize, args...)
|
|
: make_full_pos(child, shift_ - B)
|
|
.visit(v, idx - lsize, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto) first_sub(Visitor v, Args&&... args)
|
|
{
|
|
auto is_leaf = shift_ == BL;
|
|
auto child = node_->inner()[0];
|
|
return is_leaf ? make_full_leaf_pos(child).visit(v, args...)
|
|
: make_full_pos(child, shift_ - B).visit(v, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto) first_sub_leaf(Visitor v, Args&&... args)
|
|
{
|
|
assert(shift_ == BL);
|
|
auto child = node_->inner()[0];
|
|
return make_full_leaf_pos(child).visit(v, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto) first_sub_inner(Visitor v, Args&&... args)
|
|
{
|
|
assert(shift_ >= BL);
|
|
auto child = node_->inner()[0];
|
|
return make_full_pos(child, shift_ - B).visit(v, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto) nth_sub(count_t idx, Visitor v, Args&&... args)
|
|
{
|
|
assert(idx < count());
|
|
auto is_leaf = shift_ == BL;
|
|
auto child = node_->inner()[idx];
|
|
return is_leaf ? make_full_leaf_pos(child).visit(v, args...)
|
|
: make_full_pos(child, shift_ - B).visit(v, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto) nth_sub_leaf(count_t idx, Visitor v, Args&&... args)
|
|
{
|
|
assert(shift_ == BL);
|
|
assert(idx < count());
|
|
auto child = node_->inner()[idx];
|
|
return make_full_leaf_pos(child).visit(v, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto) visit(Visitor v, Args&&... args)
|
|
{
|
|
return Visitor::visit_regular(*this, std::forward<Args>(args)...);
|
|
}
|
|
};
|
|
|
|
template <typename NodeT>
|
|
full_pos<NodeT> make_full_pos(NodeT* node, shift_t shift)
|
|
{
|
|
assert(node);
|
|
assert(shift >= NodeT::bits_leaf);
|
|
return {node, shift};
|
|
}
|
|
|
|
template <typename NodeT>
|
|
struct relaxed_pos
|
|
{
|
|
static constexpr auto B = NodeT::bits;
|
|
static constexpr auto BL = NodeT::bits_leaf;
|
|
|
|
using node_t = NodeT;
|
|
using relaxed_t = typename NodeT::relaxed_t;
|
|
node_t* node_;
|
|
shift_t shift_;
|
|
relaxed_t* relaxed_;
|
|
|
|
count_t count() const { return relaxed_->d.count; }
|
|
node_t* node() const { return node_; }
|
|
size_t size() const { return relaxed_->d.sizes[relaxed_->d.count - 1]; }
|
|
shift_t shift() const { return shift_; }
|
|
count_t subindex(size_t idx) const { return index(idx); }
|
|
relaxed_t* relaxed() const { return relaxed_; }
|
|
|
|
size_t size_before(count_t offset) const
|
|
{
|
|
return offset ? relaxed_->d.sizes[offset - 1] : 0;
|
|
}
|
|
|
|
size_t size(count_t offset) const
|
|
{
|
|
return size_sbh(offset, size_before(offset));
|
|
}
|
|
|
|
size_t size_sbh(count_t offset, size_t size_before_hint) const
|
|
{
|
|
assert(size_before_hint == size_before(offset));
|
|
return relaxed_->d.sizes[offset] - size_before_hint;
|
|
}
|
|
|
|
count_t index(size_t idx) const
|
|
{
|
|
auto offset = idx >> shift_;
|
|
while (relaxed_->d.sizes[offset] <= idx)
|
|
++offset;
|
|
return offset;
|
|
}
|
|
|
|
void copy_sizes(count_t offset, count_t n, size_t init, size_t* sizes)
|
|
{
|
|
auto e = sizes + n;
|
|
auto prev = size_before(offset);
|
|
auto these = relaxed_->d.sizes + offset;
|
|
for (; sizes != e; ++sizes, ++these) {
|
|
auto this_size = *these;
|
|
init = *sizes = init + (this_size - prev);
|
|
prev = this_size;
|
|
}
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
void each(Visitor v, Args&&... args)
|
|
{
|
|
each_left(v, relaxed_->d.count, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
bool each_pred(Visitor v, Args&&... args)
|
|
{
|
|
auto p = node_->inner();
|
|
auto s = size_t{};
|
|
auto n = count();
|
|
if (shift_ == BL) {
|
|
for (auto i = count_t{0}; i < n; ++i) {
|
|
IMMER_PREFETCH(p + i + 1);
|
|
if (!make_leaf_sub_pos(p[i], relaxed_->d.sizes[i] - s)
|
|
.visit(v, args...))
|
|
return false;
|
|
s = relaxed_->d.sizes[i];
|
|
}
|
|
} else {
|
|
auto ss = shift_ - B;
|
|
for (auto i = count_t{0}; i < n; ++i) {
|
|
if (!visit_maybe_relaxed_sub(
|
|
p[i], ss, relaxed_->d.sizes[i] - s, v, args...))
|
|
return false;
|
|
s = relaxed_->d.sizes[i];
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
bool each_pred_i(Visitor v, count_t i, count_t n, Args&&... args)
|
|
{
|
|
if (shift_ == BL) {
|
|
auto p = node_->inner();
|
|
auto s = i > 0 ? relaxed_->d.sizes[i - 1] : 0;
|
|
for (; i < n; ++i) {
|
|
IMMER_PREFETCH(p + i + 1);
|
|
if (!make_leaf_sub_pos(p[i], relaxed_->d.sizes[i] - s)
|
|
.visit(v, args...))
|
|
return false;
|
|
s = relaxed_->d.sizes[i];
|
|
}
|
|
} else {
|
|
auto p = node_->inner();
|
|
auto s = i > 0 ? relaxed_->d.sizes[i - 1] : 0;
|
|
auto ss = shift_ - B;
|
|
for (; i < n; ++i) {
|
|
if (!visit_maybe_relaxed_sub(
|
|
p[i], ss, relaxed_->d.sizes[i] - s, v, args...))
|
|
return false;
|
|
s = relaxed_->d.sizes[i];
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
bool each_pred_left(Visitor v, count_t n, Args&&... args)
|
|
{
|
|
auto p = node_->inner();
|
|
auto s = size_t{};
|
|
if (shift_ == BL) {
|
|
for (auto i = count_t{0}; i < n; ++i) {
|
|
IMMER_PREFETCH(p + i + 1);
|
|
if (!make_leaf_sub_pos(p[i], relaxed_->d.sizes[i] - s)
|
|
.visit(v, args...))
|
|
return false;
|
|
s = relaxed_->d.sizes[i];
|
|
}
|
|
} else {
|
|
auto ss = shift_ - B;
|
|
for (auto i = count_t{0}; i < n; ++i) {
|
|
if (!visit_maybe_relaxed_sub(
|
|
p[i], ss, relaxed_->d.sizes[i] - s, v, args...))
|
|
return false;
|
|
s = relaxed_->d.sizes[i];
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
bool each_pred_right(Visitor v, count_t start, Args&&... args)
|
|
{
|
|
assert(start > 0);
|
|
assert(start <= relaxed_->d.count);
|
|
auto s = relaxed_->d.sizes[start - 1];
|
|
auto p = node_->inner();
|
|
if (shift_ == BL) {
|
|
for (auto i = start; i < relaxed_->d.count; ++i) {
|
|
IMMER_PREFETCH(p + i + 1);
|
|
if (!make_leaf_sub_pos(p[i], relaxed_->d.sizes[i] - s)
|
|
.visit(v, args...))
|
|
return false;
|
|
s = relaxed_->d.sizes[i];
|
|
}
|
|
} else {
|
|
auto ss = shift_ - B;
|
|
for (auto i = start; i < relaxed_->d.count; ++i) {
|
|
if (!visit_maybe_relaxed_sub(
|
|
p[i], ss, relaxed_->d.sizes[i] - s, v, args...))
|
|
return false;
|
|
s = relaxed_->d.sizes[i];
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
void each_i(Visitor v, count_t i, count_t n, Args&&... args)
|
|
{
|
|
if (shift_ == BL) {
|
|
auto p = node_->inner();
|
|
auto s = i > 0 ? relaxed_->d.sizes[i - 1] : 0;
|
|
for (; i < n; ++i) {
|
|
IMMER_PREFETCH(p + i + 1);
|
|
make_leaf_sub_pos(p[i], relaxed_->d.sizes[i] - s)
|
|
.visit(v, args...);
|
|
s = relaxed_->d.sizes[i];
|
|
}
|
|
} else {
|
|
auto p = node_->inner();
|
|
auto s = i > 0 ? relaxed_->d.sizes[i - 1] : 0;
|
|
auto ss = shift_ - B;
|
|
for (; i < n; ++i) {
|
|
visit_maybe_relaxed_sub(
|
|
p[i], ss, relaxed_->d.sizes[i] - s, v, args...);
|
|
s = relaxed_->d.sizes[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
void each_sub(Visitor v, Args&&... args)
|
|
{
|
|
each_left(v, relaxed_->d.count, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
void each_left_sub(Visitor v, Args&&... args)
|
|
{
|
|
each_left(v, relaxed_->d.count - 1, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
void each_left(Visitor v, count_t n, Args&&... args)
|
|
{
|
|
auto p = node_->inner();
|
|
auto s = size_t{};
|
|
if (shift_ == BL) {
|
|
for (auto i = count_t{0}; i < n; ++i) {
|
|
IMMER_PREFETCH(p + i + 1);
|
|
make_leaf_sub_pos(p[i], relaxed_->d.sizes[i] - s)
|
|
.visit(v, args...);
|
|
s = relaxed_->d.sizes[i];
|
|
}
|
|
} else {
|
|
auto ss = shift_ - B;
|
|
for (auto i = count_t{0}; i < n; ++i) {
|
|
visit_maybe_relaxed_sub(
|
|
p[i], ss, relaxed_->d.sizes[i] - s, v, args...);
|
|
s = relaxed_->d.sizes[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
void each_right_sub(Visitor v, Args&&... args)
|
|
{
|
|
each_right(v, 1, std::forward<Args>(args)...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
void each_right(Visitor v, count_t start, Args&&... args)
|
|
{
|
|
assert(start > 0);
|
|
assert(start <= relaxed_->d.count);
|
|
auto s = relaxed_->d.sizes[start - 1];
|
|
auto p = node_->inner();
|
|
if (shift_ == BL) {
|
|
for (auto i = start; i < relaxed_->d.count; ++i) {
|
|
IMMER_PREFETCH(p + i + 1);
|
|
make_leaf_sub_pos(p[i], relaxed_->d.sizes[i] - s)
|
|
.visit(v, args...);
|
|
s = relaxed_->d.sizes[i];
|
|
}
|
|
} else {
|
|
auto ss = shift_ - B;
|
|
for (auto i = start; i < relaxed_->d.count; ++i) {
|
|
visit_maybe_relaxed_sub(
|
|
p[i], ss, relaxed_->d.sizes[i] - s, v, args...);
|
|
s = relaxed_->d.sizes[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto) towards(Visitor v, size_t idx, Args&&... args)
|
|
{
|
|
return towards_oh(v, idx, subindex(idx), args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto)
|
|
towards_oh(Visitor v, size_t idx, count_t offset_hint, Args&&... args)
|
|
{
|
|
assert(offset_hint == index(idx));
|
|
auto left_size = offset_hint ? relaxed_->d.sizes[offset_hint - 1] : 0;
|
|
return towards_oh_sbh(v, idx, offset_hint, left_size, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto) towards_oh_sbh(Visitor v,
|
|
size_t idx,
|
|
count_t offset_hint,
|
|
size_t left_size_hint,
|
|
Args&&... args)
|
|
{
|
|
return towards_sub_oh_sbh(v, idx, offset_hint, left_size_hint, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto)
|
|
towards_sub_oh(Visitor v, size_t idx, count_t offset_hint, Args&&... args)
|
|
{
|
|
assert(offset_hint == index(idx));
|
|
auto left_size = offset_hint ? relaxed_->d.sizes[offset_hint - 1] : 0;
|
|
return towards_sub_oh_sbh(v, idx, offset_hint, left_size, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto) towards_sub_oh_sbh(Visitor v,
|
|
size_t idx,
|
|
count_t offset_hint,
|
|
size_t left_size_hint,
|
|
Args&&... args)
|
|
{
|
|
assert(offset_hint == index(idx));
|
|
assert(left_size_hint ==
|
|
(offset_hint ? relaxed_->d.sizes[offset_hint - 1] : 0));
|
|
auto child = node_->inner()[offset_hint];
|
|
auto is_leaf = shift_ == BL;
|
|
auto next_size = relaxed_->d.sizes[offset_hint] - left_size_hint;
|
|
auto next_idx = idx - left_size_hint;
|
|
return is_leaf
|
|
? make_leaf_sub_pos(child, next_size)
|
|
.visit(v, next_idx, args...)
|
|
: visit_maybe_relaxed_sub(
|
|
child, shift_ - B, next_size, v, next_idx, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto) last_oh_csh(Visitor v,
|
|
count_t offset_hint,
|
|
size_t child_size_hint,
|
|
Args&&... args)
|
|
{
|
|
assert(offset_hint == count() - 1);
|
|
assert(child_size_hint == size(offset_hint));
|
|
auto child = node_->inner()[offset_hint];
|
|
auto is_leaf = shift_ == BL;
|
|
return is_leaf
|
|
? make_leaf_sub_pos(child, child_size_hint).visit(v, args...)
|
|
: visit_maybe_relaxed_sub(
|
|
child, shift_ - B, child_size_hint, v, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto) last_sub(Visitor v, Args&&... args)
|
|
{
|
|
auto offset = relaxed_->d.count - 1;
|
|
auto child = node_->inner()[offset];
|
|
auto child_size = size(offset);
|
|
auto is_leaf = shift_ == BL;
|
|
return is_leaf ? make_leaf_sub_pos(child, child_size).visit(v, args...)
|
|
: visit_maybe_relaxed_sub(
|
|
child, shift_ - B, child_size, v, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto) first_sub(Visitor v, Args&&... args)
|
|
{
|
|
auto child = node_->inner()[0];
|
|
auto child_size = relaxed_->d.sizes[0];
|
|
auto is_leaf = shift_ == BL;
|
|
return is_leaf ? make_leaf_sub_pos(child, child_size).visit(v, args...)
|
|
: visit_maybe_relaxed_sub(
|
|
child, shift_ - B, child_size, v, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto) first_sub_leaf(Visitor v, Args&&... args)
|
|
{
|
|
assert(shift_ == BL);
|
|
auto child = node_->inner()[0];
|
|
auto child_size = relaxed_->d.sizes[0];
|
|
return make_leaf_sub_pos(child, child_size).visit(v, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto) first_sub_inner(Visitor v, Args&&... args)
|
|
{
|
|
assert(shift_ > BL);
|
|
auto child = node_->inner()[0];
|
|
auto child_size = relaxed_->d.sizes[0];
|
|
return visit_maybe_relaxed_sub(
|
|
child, shift_ - B, child_size, v, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto) nth_sub(count_t offset, Visitor v, Args&&... args)
|
|
{
|
|
auto child = node_->inner()[offset];
|
|
auto child_size = size(offset);
|
|
auto is_leaf = shift_ == BL;
|
|
return is_leaf ? make_leaf_sub_pos(child, child_size).visit(v, args...)
|
|
: visit_maybe_relaxed_sub(
|
|
child, shift_ - B, child_size, v, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto) nth_sub_leaf(count_t offset, Visitor v, Args&&... args)
|
|
{
|
|
assert(shift_ == BL);
|
|
auto child = node_->inner()[offset];
|
|
auto child_size = size(offset);
|
|
return make_leaf_sub_pos(child, child_size).visit(v, args...);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto) visit(Visitor v, Args&&... args)
|
|
{
|
|
return Visitor::visit_relaxed(*this, std::forward<Args>(args)...);
|
|
}
|
|
};
|
|
|
|
template <typename Pos>
|
|
using is_relaxed = std::is_same<relaxed_pos<typename std::decay_t<Pos>::node_t>,
|
|
std::decay_t<Pos>>;
|
|
|
|
template <typename Pos>
|
|
constexpr auto is_relaxed_v = is_relaxed<Pos>::value;
|
|
|
|
template <typename NodeT>
|
|
relaxed_pos<NodeT>
|
|
make_relaxed_pos(NodeT* node, shift_t shift, typename NodeT::relaxed_t* relaxed)
|
|
{
|
|
assert(node);
|
|
assert(relaxed);
|
|
assert(shift >= NodeT::bits_leaf);
|
|
return {node, shift, relaxed};
|
|
}
|
|
|
|
template <typename NodeT, typename Visitor, typename... Args>
|
|
decltype(auto) visit_maybe_relaxed_sub(
|
|
NodeT* node, shift_t shift, size_t size, Visitor v, Args&&... args)
|
|
{
|
|
assert(node);
|
|
auto relaxed = node->relaxed();
|
|
if (relaxed) {
|
|
assert(size == relaxed->d.sizes[relaxed->d.count - 1]);
|
|
return make_relaxed_pos(node, shift, relaxed)
|
|
.visit(v, std::forward<Args>(args)...);
|
|
} else {
|
|
return make_regular_sub_pos(node, shift, size)
|
|
.visit(v, std::forward<Args>(args)...);
|
|
}
|
|
}
|
|
|
|
template <typename NodeT,
|
|
shift_t Shift,
|
|
bits_t B = NodeT::bits,
|
|
bits_t BL = NodeT::bits_leaf>
|
|
struct relaxed_descent_pos
|
|
{
|
|
static_assert(Shift > 0, "not leaf...");
|
|
|
|
using node_t = NodeT;
|
|
using relaxed_t = typename NodeT::relaxed_t;
|
|
node_t* node_;
|
|
relaxed_t* relaxed_;
|
|
|
|
count_t count() const { return relaxed_->d.count; }
|
|
node_t* node() const { return node_; }
|
|
shift_t shift() const { return Shift; }
|
|
size_t size() const { return relaxed_->d.sizes[relaxed_->d.count - 1]; }
|
|
|
|
count_t index(size_t idx) const
|
|
{
|
|
// make gcc happy
|
|
#if !defined(_MSC_VER)
|
|
#pragma GCC diagnostic push
|
|
#pragma GCC diagnostic ignored "-Wshift-count-overflow"
|
|
#endif
|
|
auto offset = idx >> Shift;
|
|
#if !defined(_MSC_VER)
|
|
#pragma GCC diagnostic pop
|
|
#endif
|
|
while (relaxed_->d.sizes[offset] <= idx)
|
|
++offset;
|
|
return offset;
|
|
}
|
|
|
|
template <typename Visitor>
|
|
decltype(auto) descend(Visitor v, size_t idx)
|
|
{
|
|
auto offset = index(idx);
|
|
auto child = node_->inner()[offset];
|
|
auto left_size = offset ? relaxed_->d.sizes[offset - 1] : 0;
|
|
auto next_idx = idx - left_size;
|
|
auto r = child->relaxed();
|
|
return r ? relaxed_descent_pos<NodeT, Shift - B>{child, r}.visit(
|
|
v, next_idx)
|
|
: regular_descent_pos<NodeT, Shift - B>{child}.visit(v,
|
|
next_idx);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto) visit(Visitor v, Args&&... args)
|
|
{
|
|
return Visitor::visit_relaxed(*this, std::forward<Args>(args)...);
|
|
}
|
|
};
|
|
|
|
template <typename NodeT, bits_t B, bits_t BL>
|
|
struct relaxed_descent_pos<NodeT, BL, B, BL>
|
|
{
|
|
using node_t = NodeT;
|
|
using relaxed_t = typename NodeT::relaxed_t;
|
|
node_t* node_;
|
|
relaxed_t* relaxed_;
|
|
|
|
count_t count() const { return relaxed_->d.count; }
|
|
node_t* node() const { return node_; }
|
|
shift_t shift() const { return BL; }
|
|
size_t size() const { return relaxed_->d.sizes[relaxed_->d.count - 1]; }
|
|
|
|
count_t index(size_t idx) const
|
|
{
|
|
auto offset = (idx >> BL) & mask<B>;
|
|
while (relaxed_->d.sizes[offset] <= idx)
|
|
++offset;
|
|
return offset;
|
|
}
|
|
|
|
template <typename Visitor>
|
|
decltype(auto) descend(Visitor v, size_t idx)
|
|
{
|
|
auto offset = index(idx);
|
|
auto child = node_->inner()[offset];
|
|
auto left_size = offset ? relaxed_->d.sizes[offset - 1] : 0;
|
|
auto next_idx = idx - left_size;
|
|
return leaf_descent_pos<NodeT>{child}.visit(v, next_idx);
|
|
}
|
|
|
|
template <typename Visitor, typename... Args>
|
|
decltype(auto) visit(Visitor v, Args&&... args)
|
|
{
|
|
return Visitor::visit_relaxed(*this, std::forward<Args>(args)...);
|
|
}
|
|
};
|
|
|
|
template <typename NodeT, typename Visitor, typename... Args>
|
|
decltype(auto)
|
|
visit_maybe_relaxed_descent(NodeT* node, shift_t shift, Visitor v, size_t idx)
|
|
{
|
|
constexpr auto B = NodeT::bits;
|
|
constexpr auto BL = NodeT::bits_leaf;
|
|
assert(node);
|
|
assert(shift >= BL);
|
|
auto r = node->relaxed();
|
|
if (r) {
|
|
switch (shift) {
|
|
case BL + B * 0:
|
|
return relaxed_descent_pos<NodeT, BL + B * 0>{node, r}.visit(v,
|
|
idx);
|
|
case BL + B * 1:
|
|
return relaxed_descent_pos<NodeT, BL + B * 1>{node, r}.visit(v,
|
|
idx);
|
|
case BL + B * 2:
|
|
return relaxed_descent_pos<NodeT, BL + B * 2>{node, r}.visit(v,
|
|
idx);
|
|
case BL + B * 3:
|
|
return relaxed_descent_pos<NodeT, BL + B * 3>{node, r}.visit(v,
|
|
idx);
|
|
case BL + B * 4:
|
|
return relaxed_descent_pos<NodeT, BL + B * 4>{node, r}.visit(v,
|
|
idx);
|
|
case BL + B * 5:
|
|
return relaxed_descent_pos<NodeT, BL + B * 5>{node, r}.visit(v,
|
|
idx);
|
|
#if IMMER_DESCENT_DEEP
|
|
default:
|
|
for (auto level = shift; level != endshift<B, BL>; level -= B) {
|
|
auto r = node->relaxed();
|
|
if (r) {
|
|
auto node_idx = (idx >> level) & mask<B>;
|
|
while (r->d.sizes[node_idx] <= idx)
|
|
++node_idx;
|
|
if (node_idx)
|
|
idx -= r->d.sizes[node_idx - 1];
|
|
node = node->inner()[node_idx];
|
|
} else {
|
|
do {
|
|
node = node->inner()[(idx >> level) & mask<B>];
|
|
} while ((level -= B) != endshift<B, BL>);
|
|
return make_leaf_descent_pos(node).visit(v, idx);
|
|
}
|
|
}
|
|
return make_leaf_descent_pos(node).visit(v, idx);
|
|
#endif // IMMER_DESCENT_DEEP
|
|
}
|
|
IMMER_UNREACHABLE;
|
|
} else {
|
|
return visit_regular_descent(node, shift, v, idx);
|
|
}
|
|
}
|
|
|
|
} // namespace rbts
|
|
} // namespace detail
|
|
} // namespace immer
|