// // 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 #include #include #include #include namespace immer { namespace detail { namespace rbts { template constexpr auto bits = std::decay_t::node_t::bits; template constexpr auto bits_leaf = std::decay_t::node_t::bits_leaf; template using node_type = typename std::decay::type::node_t; template using edit_type = typename std::decay::type::node_t::edit_t; template 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 void each(Visitor, Args&&...) {} template bool each_pred(Visitor, Args&&...) { return true; } template decltype(auto) visit(Visitor v, Args&&... args) { return Visitor::visit_regular(*this, std::forward(args)...); } }; template empty_regular_pos make_empty_regular_pos(NodeT* node) { return {node}; } template 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 decltype(auto) visit(Visitor v, Args&&... args) { return Visitor::visit_leaf(*this, std::forward(args)...); } }; template empty_leaf_pos make_empty_leaf_pos(NodeT* node) { assert(node); return {node}; } template 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; } count_t subindex(size_t idx) const { return idx; } template decltype(auto) visit(Visitor v, Args&&... args) { return Visitor::visit_leaf(*this, std::forward(args)...); } }; template leaf_pos make_leaf_pos(NodeT* node, size_t size) { assert(node); assert(size > 0); return {node, size}; } template 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; } count_t subindex(size_t idx) const { return idx; } template decltype(auto) visit(Visitor v, Args&&... args) { return Visitor::visit_leaf(*this, std::forward(args)...); } }; template leaf_sub_pos make_leaf_sub_pos(NodeT* node, count_t count) { assert(node); assert(count <= branches); return {node, count}; } template 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; } template decltype(auto) descend(Args&&...) {} template decltype(auto) visit(Visitor v, Args&&... args) { return Visitor::visit_leaf(*this, std::forward(args)...); } }; template leaf_descent_pos make_leaf_descent_pos(NodeT* node) { assert(node); return {node}; } template 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; } node_t* node() const { return node_; } size_t size() const { return branches; } shift_t shift() const { return 0; } count_t index(size_t idx) const { return idx & mask; } count_t subindex(size_t idx) const { return idx; } template decltype(auto) visit(Visitor v, Args&&... args) { return Visitor::visit_leaf(*this, std::forward(args)...); } }; template full_leaf_pos make_full_leaf_pos(NodeT* node) { assert(node); return {node}; } template 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; } count_t subindex(size_t idx) const { return idx >> shift_; } size_t this_size() const { return ((size_ - 1) & ~(~size_t{} << (shift_ + B))) + 1; } template void each(Visitor v, Args&&... args) { return each_regular(*this, v, args...); } template bool each_pred(Visitor v, Args&&... args) { return each_pred_regular(*this, v, args...); } template bool each_pred_zip(Visitor v, node_t* other, Args&&... args) { return each_pred_zip_regular(*this, v, other, args...); } template 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 bool each_pred_right(Visitor v, count_t start, Args&&... args) { return each_pred_right_regular(*this, v, start, args...); } template bool each_pred_left(Visitor v, count_t n, Args&&... args) { return each_pred_left_regular(*this, v, n, args...); } template void each_i(Visitor v, count_t i, count_t n, Args&&... args) { return each_i_regular(*this, v, i, n, args...); } template void each_right(Visitor v, count_t start, Args&&... args) { return each_right_regular(*this, v, start, args...); } template void each_left(Visitor v, count_t n, Args&&... args) { return each_left_regular(*this, v, n, args...); } template decltype(auto) towards(Visitor v, size_t idx, Args&&... args) { return towards_oh_ch_regular( *this, v, idx, index(idx), count(), args...); } template 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 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 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 decltype(auto) last_oh(Visitor v, count_t offset_hint, Args&&... args) { return last_oh_regular(*this, v, offset_hint, args...); } template decltype(auto) visit(Visitor v, Args&&... args) { return Visitor::visit_regular(*this, std::forward(args)...); } }; template void each_regular(Pos&& p, Visitor v, Args&&... args) { constexpr auto B = bits; constexpr auto BL = bits_leaf; 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 bool each_pred_regular(Pos&& p, Visitor v, Args&&... args) { constexpr auto B = bits; constexpr auto BL = bits_leaf; 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 bool each_pred_zip_regular(Pos&& p, Visitor v, node_type* other, Args&&... args) { constexpr auto B = bits; constexpr auto BL = bits_leaf; 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 bool each_pred_i_regular( Pos&& p, Visitor v, count_t f, count_t l, Args&&... args) { constexpr auto B = bits; constexpr auto BL = bits_leaf; 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 bool each_pred_left_regular(Pos&& p, Visitor v, count_t last, Args&&... args) { constexpr auto B = bits; constexpr auto BL = bits_leaf; 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 bool each_pred_right_regular(Pos&& p, Visitor v, count_t start, Args&&... args) { constexpr auto B = bits; constexpr auto BL = bits_leaf; 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 void each_i_regular(Pos&& p, Visitor v, count_t f, count_t l, Args&&... args) { constexpr auto B = bits; constexpr auto BL = bits_leaf; 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 void each_left_regular(Pos&& p, Visitor v, count_t last, Args&&... args) { constexpr auto B = bits; constexpr auto BL = bits_leaf; 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 void each_right_regular(Pos&& p, Visitor v, count_t start, Args&&... args) { constexpr auto B = bits; constexpr auto BL = bits_leaf; 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 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; constexpr auto BL = bits_leaf; 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 decltype(auto) towards_sub_oh_regular( Pos&& p, Visitor v, size_t idx, count_t offset_hint, Args&&... args) { constexpr auto B = bits; constexpr auto BL = bits_leaf; 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 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; constexpr auto BL = bits_leaf; 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 regular_pos 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 void each_sub(Visitor, Args&&...) {} template void each_right_sub(Visitor, Args&&...) {} template void each_left_sub(Visitor, Args&&...) {} template void visit(Visitor, Args&&...) {} }; template 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 void each_left_sub(Visitor v, Args&&... args) {} template void each(Visitor v, Args&&... args) {} template decltype(auto) last_sub(Visitor v, Args&&... args) { return make_leaf_sub_pos(leaf_, count_).visit(v, args...); } template decltype(auto) visit(Visitor v, Args&&... args) { return Visitor::visit_regular(*this, std::forward(args)...); } }; template 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{leaf, count}; } template 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; } 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 void each(Visitor v, Args&&... args) { return each_regular(*this, v, args...); } template bool each_pred(Visitor v, Args&&... args) { return each_pred_regular(*this, v, args...); } template bool each_pred_zip(Visitor v, node_t* other, Args&&... args) { return each_pred_zip_regular(*this, v, other, args...); } template 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 bool each_pred_right(Visitor v, count_t start, Args&&... args) { return each_pred_right_regular(*this, v, start, args...); } template bool each_pred_left(Visitor v, count_t last, Args&&... args) { return each_pred_left_regular(*this, v, last, args...); } template void each_i(Visitor v, count_t i, count_t n, Args&&... args) { return each_i_regular(*this, v, i, n, args...); } template void each_right(Visitor v, count_t start, Args&&... args) { return each_right_regular(*this, v, start, args...); } template void each_left(Visitor v, count_t last, Args&&... args) { return each_left_regular(*this, v, last, args...); } template 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 void each_sub(Visitor v, Args&&... args) { each_right_sub_(v, 0, args...); } template void each_right_sub(Visitor v, Args&&... args) { if (count() > 1) each_right_sub_(v, 1, args...); } template void each_left_sub(Visitor v, Args&&... args) { each_left(v, count() - 1, args...); } template decltype(auto) towards(Visitor v, size_t idx, Args&&... args) { return towards_oh_ch_regular( *this, v, idx, index(idx), count(), args...); } template 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 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 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 decltype(auto) last_oh(Visitor v, count_t offset_hint, Args&&... args) { return last_oh_regular(*this, v, offset_hint, args...); } template 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 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 decltype(auto) first_sub_leaf(Visitor v, Args&&... args) { assert(shift_ == BL); auto child = node_->inner()[0]; auto is_full = size_ >= branches; return is_full ? make_full_leaf_pos(child).visit(v, args...) : make_leaf_sub_pos(child, size_).visit(v, args...); } template decltype(auto) first_sub_inner(Visitor v, Args&&... args) { assert(shift_ >= BL); auto child = node_->inner()[0]; auto is_full = size_ >= branches; return is_full ? make_full_pos(child, shift_ - B).visit(v, args...) : make_regular_sub_pos(child, shift_ - B, size_) .visit(v, args...); } template 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 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 decltype(auto) visit(Visitor v, Args&&... args) { return Visitor::visit_regular(*this, std::forward(args)...); } }; template regular_sub_pos 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 << shift)); return {node, shift, size}; } template 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; #if !defined(_MSC_VER) #pragma GCC diagnostic pop #endif } template decltype(auto) descend(Visitor v, size_t idx) { auto offset = index(idx); auto child = node_->inner()[offset]; return regular_descent_pos{child}.visit(v, idx); } template decltype(auto) visit(Visitor v, Args&&... args) { return Visitor::visit_regular(*this, std::forward(args)...); } }; template struct regular_descent_pos { 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; } template 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 decltype(auto) visit(Visitor v, Args&&... args) { return Visitor::visit_regular(*this, std::forward(args)...); } }; template 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{node}.visit(v, idx); case BL + B * 1: return regular_descent_pos{node}.visit(v, idx); case BL + B * 2: return regular_descent_pos{node}.visit(v, idx); case BL + B * 3: return regular_descent_pos{node}.visit(v, idx); case BL + B * 4: return regular_descent_pos{node}.visit(v, idx); case BL + B * 5: return regular_descent_pos{node}.visit(v, idx); #if IMMER_DESCENT_DEEP default: for (auto level = shift; level != endshift; level -= B) node = node->inner()[(idx >> level) & mask]; return make_leaf_descent_pos(node).visit(v, idx); #endif // IMMER_DEEP_DESCENT } IMMER_UNREACHABLE; } template 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; } node_t* node() const { return node_; } size_t size() const { return branches << shift_; } shift_t shift() const { return shift_; } count_t index(size_t idx) const { return (idx >> shift_) & mask; } 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 void each(Visitor v, Args&&... args) { auto p = node_->inner(); auto e = p + branches; 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 bool each_pred(Visitor v, Args&&... args) { auto p = node_->inner(); auto e = p + branches; 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 bool each_pred_zip(Visitor v, node_t* other, Args&&... args) { auto p = node_->inner(); auto p2 = other->inner(); auto e = p + branches; 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 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 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 bool each_pred_right(Visitor v, count_t start, Args&&... args) { return each_pred_i(v, start, branches, args...); } template bool each_pred_left(Visitor v, count_t last, Args&&... args) { return each_pred_i(v, 0, last, args...); } template void each_sub(Visitor v, Args&&... args) { each(v, args...); } template void each_left_sub(Visitor v, Args&&... args) { each_i(v, 0, branches - 1, args...); } template void each_right_sub(Visitor v, Args&&... args) { each_i(v, 1, branches, args...); } template void each_right(Visitor v, count_t start, Args&&... args) { each_i(v, start, branches, args...); } template void each_left(Visitor v, count_t last, Args&&... args) { each_i(v, 0, last, args...); } template decltype(auto) towards(Visitor v, size_t idx, Args&&... args) { return towards_oh(v, idx, index(idx), args...); } template 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 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 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 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 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 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 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 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 decltype(auto) visit(Visitor v, Args&&... args) { return Visitor::visit_regular(*this, std::forward(args)...); } }; template full_pos make_full_pos(NodeT* node, shift_t shift) { assert(node); assert(shift >= NodeT::bits_leaf); return {node, shift}; } template 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 void each(Visitor v, Args&&... args) { each_left(v, relaxed_->d.count, args...); } template 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 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 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 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 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 void each_sub(Visitor v, Args&&... args) { each_left(v, relaxed_->d.count, args...); } template void each_left_sub(Visitor v, Args&&... args) { each_left(v, relaxed_->d.count - 1, args...); } template 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 void each_right_sub(Visitor v, Args&&... args) { each_right(v, 1, std::forward(args)...); } template 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 decltype(auto) towards(Visitor v, size_t idx, Args&&... args) { return towards_oh(v, idx, subindex(idx), args...); } template 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 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 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 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 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 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 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 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 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 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 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 decltype(auto) visit(Visitor v, Args&&... args) { return Visitor::visit_relaxed(*this, std::forward(args)...); } }; template using is_relaxed = std::is_same::node_t>, std::decay_t>; template constexpr auto is_relaxed_v = is_relaxed::value; template relaxed_pos 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 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)...); } else { return make_regular_sub_pos(node, shift, size) .visit(v, std::forward(args)...); } } template 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 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{child, r}.visit( v, next_idx) : regular_descent_pos{child}.visit(v, next_idx); } template decltype(auto) visit(Visitor v, Args&&... args) { return Visitor::visit_relaxed(*this, std::forward(args)...); } }; template struct relaxed_descent_pos { 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; while (relaxed_->d.sizes[offset] <= idx) ++offset; return offset; } template 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{child}.visit(v, next_idx); } template decltype(auto) visit(Visitor v, Args&&... args) { return Visitor::visit_relaxed(*this, std::forward(args)...); } }; template 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{node, r}.visit(v, idx); case BL + B * 1: return relaxed_descent_pos{node, r}.visit(v, idx); case BL + B * 2: return relaxed_descent_pos{node, r}.visit(v, idx); case BL + B * 3: return relaxed_descent_pos{node, r}.visit(v, idx); case BL + B * 4: return relaxed_descent_pos{node, r}.visit(v, idx); case BL + B * 5: return relaxed_descent_pos{node, r}.visit(v, idx); #if IMMER_DESCENT_DEEP default: for (auto level = shift; level != endshift; level -= B) { auto r = node->relaxed(); if (r) { auto node_idx = (idx >> level) & mask; 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]; } while ((level -= B) != endshift); 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