44 :
public PermutationBase<Permutation<Index, StorageBits, Fanout, Layout>,
47 using block_type = permutations::detail::PackedValueBlock<Index, StorageBits>;
49 permutations::detail::SequenceTree<block_type, Fanout, Layout, true>;
50 static_assert(std::is_integral_v<Index> && std::is_unsigned_v<Index> &&
51 !std::is_same_v<Index, bool> &&
52 std::numeric_limits<Index>::digits <= 64);
89 return tree_.lower_bound(pred);
128 permutations::detail::SequenceTree<block_type, Fanout, Layout>;
129 const auto tree = tree_.memory_usage();
131 result.blocks = tree.blocks;
132 result.nodes = tree.nodes;
133 result.payload_capacity_bytes = tree_type::saturated_multiply(
134 tree.blocks, block_type{}.payload_capacity_bytes());
135 result.block_metadata_bytes = tree_type::saturated_multiply(
136 tree.blocks, block_type{}.metadata_bytes());
137 result.ordering_tree_bytes =
138 tree_type::saturated_multiply(tree.nodes, Untagged::node_storage_bytes);
139 result.tag_padding_bytes = tree_type::saturated_add(
140 tree_type::saturated_multiply(
141 tree.blocks, tree_type::block_storage_bytes -
sizeof(block_type)),
142 tree_type::saturated_multiply(
144 tree_type::node_storage_bytes - Untagged::node_storage_bytes));
145 result.total_bytes = tree_type::saturated_add(
147 tree_type::saturated_add(tree.block_bytes, tree.node_bytes));
150#ifdef PIXIE_SEQUENCE_TREE_TESTING
157 const tree_type& test_tree() const noexcept {
return tree_; }
164 n / block_type::capacity + (n % block_type::capacity != 0);
166 std::views::iota(std::size_t{0}, count) |
167 std::views::transform([n](std::size_t block) {
168 std::array<Index, block_type::capacity> fields;
169 const auto start = block * block_type::capacity;
170 const auto length = std::min(block_type::capacity, n - start);
171 for (std::size_t i = 0; i < length; ++i) {
172 fields[i] =
static_cast<Index
>(start + i);
174 return block_type(std::span<const Index>(fields.data(), length));
177 result.tree_ = tree_type::from_blocks(blocks);
180 std::size_t size_impl() const noexcept {
return tree_.size(); }
181 Index value_at_impl(std::size_t position)
const {
return tree_[position]; }
193 void insert_at_impl(std::size_t position) {
194 if (position > tree_.size()) {
195 throw std::out_of_range(
"Permutation: insert position");
197 check_domain(tree_.size() + 1);
198 tree_.insert_at(position,
static_cast<Index
>(tree_.size()));
200 void rotate_left_impl(std::size_t left,
202 std::size_t distance) {
203 tree_.rotate_left(left, right, distance);
207 if (
this == &donor || donor.empty()) {
210 if (donor.size() > std::numeric_limits<std::size_t>::max() - this->size()) {
211 throw std::length_error(
"Permutation: concatenation size");
213 check_domain(this->
size() + donor.size());
214 tree_.merge_rebased(donor.tree_);
216 std::size_t memory_usage_bytes_impl() const noexcept {
219 static void check_domain(std::size_t n) {
220 if (n != 0 && n - 1 > std::numeric_limits<Index>::max()) {
221 throw std::length_error(
"Permutation: index domain");