3#include <pixie/permutations/detail/tree_policy.h>
17template <std::
size_t Fanout,
class Order>
19 static_assert(Order::capacity == Fanout);
20 static_assert(std::is_nothrow_constructible_v<Order, std::size_t> &&
21 std::is_trivially_destructible_v<Order>);
28 static constexpr bool supports_bias =
false;
30 std::size_t count : std::bit_width(Fanout) = 0;
31 std::size_t regular_prefix : std::bit_width(Fanout) = 0;
32 std::size_t mapped : 1 = 0;
35 std::size_t slot(
const Node& node,
37 std::size_t height)
const noexcept {
38 return height == 1 && node.mapped ? storage_.value[i] : i;
41 void reset(Node& node)
noexcept {
44 template <
class Tree,
class Node>
45 std::size_t rotate(Node& node,
49 std::size_t height)
noexcept {
51 return permutations::detail::DirectChildOrder<Fanout>::template rotate<
52 Tree>(node, begin, middle, end, height);
55 std::construct_at(&storage_.value, std::size_t(node.count));
57#ifdef PIXIE_SEQUENCE_TREE_TESTING
58 ++Tree::test_counters.order_materializations;
61 return storage_.value.rotate_children(node.children, begin, end,
65 bool valid(
const Node& node, std::size_t height)
const noexcept {
66 return !node.mapped ||
67 (height == 1 && storage_.value.size() == node.count &&
68 storage_.value.valid());
75template <
class Node,
class Allocator, std::
size_t Limit>
76struct BoundedNodeReserve {
77 Node* nodes =
nullptr;
78 std::size_t count = 0;
79 BoundedNodeReserve() =
default;
80 BoundedNodeReserve(
const BoundedNodeReserve&) =
delete;
81 BoundedNodeReserve& operator=(
const BoundedNodeReserve&) =
delete;
82 BoundedNodeReserve(BoundedNodeReserve&& other) noexcept
83 : nodes(std::exchange(other.nodes,
nullptr)),
84 count(std::exchange(other.count, 0)) {}
85 BoundedNodeReserve& operator=(BoundedNodeReserve&& other)
noexcept {
88 nodes = std::exchange(other.nodes,
nullptr);
89 count = std::exchange(other.count, 0);
93 ~BoundedNodeReserve() { clear(); }
94 void clear() noexcept {
96 auto* next =
static_cast<Node*
>(nodes->children[0]);
97 Allocator::dispose(nodes);
102 BoundedNodeReserve* for_rotation(std::size_t size,
103 std::size_t value_bytes)
noexcept {
104 return size >= (std::size_t{1} << 20) / value_bytes ?
this : nullptr;
106 void trim(std::size_t size, std::size_t value_bytes)
noexcept {
107 if (!for_rotation(size, value_bytes)) {
111 std::size_t node_count() const noexcept {
return count; }
114template <
class Node,
class Owner,
class Allocator, std::
size_t Limit>
115class RetainedNodePool
116 :
public permutations::detail::SequenceNodePool<Node, Owner, Allocator> {
117 using Base = permutations::detail::SequenceNodePool<Node, Owner, Allocator>;
118 using Reserve = BoundedNodeReserve<Node, Allocator, Limit>;
119 Reserve* retained_ =
nullptr;
120 std::size_t borrowed_ = 0;
121 std::size_t retain_limit_ = 0;
124 explicit RetainedNodePool(Reserve* reserve =
nullptr) noexcept
125 : retained_(reserve) {
127 this->nodes = std::exchange(retained_->nodes,
nullptr);
128 borrowed_ = std::exchange(retained_->count, 0);
129 retain_limit_ = borrowed_;
132 void commit() noexcept { retain_limit_ = Limit; }
133 ~RetainedNodePool() {
135 while (this->nodes && retained_->count < retain_limit_) {
136 auto* next =
static_cast<Node*
>(this->nodes->children[0]);
137 this->nodes->children[0] = retained_->nodes;
138 retained_->nodes = this->nodes;
144 void reserve(std::size_t count, std::size_t leaf_spares) {
145 const auto available = std::exchange(borrowed_, 0);
146 Base::reserve(count > available ? count - available : 0, leaf_spares);
150template <std::
size_t ReservedNodes,
class LeafOrder =
void>
151struct SequenceTreePolicy {
152 template <std::
size_t Fanout>
154 std::conditional_t<std::is_void_v<LeafOrder>,
155 permutations::detail::DirectChildOrder<Fanout>,
156 LeafChildOrder<Fanout, LeafOrder>>;
157 template <
class Node,
class Allocator>
159 std::conditional_t<ReservedNodes == 0,
160 permutations::detail::NoNodeReserve<Node>,
161 BoundedNodeReserve<Node, Allocator, ReservedNodes>>;
162 template <
class Node,
class Owner,
class Allocator>
163 using Pool = std::conditional_t<
165 permutations::detail::SequenceNodePool<Node, Owner, Allocator>,
166 RetainedNodePool<Node, Owner, Allocator, ReservedNodes>>;
167 struct TestCounters {
168 std::size_t order_materializations = 0;