40 static constexpr std::array<std::uint8_t, 8> kSerializationMagic = {
41 'P',
'I',
'X',
'I',
'E',
'R',
'M',
'M'};
42 static constexpr std::uint32_t kSerializationVersion = 1;
43 static constexpr std::size_t kSerializationHeaderBytes = 32;
46 std::span<const std::uint64_t> bits;
50 size_t block_bits = 64;
51 size_t leaf_count = 0;
58 std::vector<uint32_t> segment_size_bits;
64 std::vector<int32_t> node_total_excess;
69 std::vector<int32_t> node_min_prefix_excess;
73 std::vector<int32_t> node_max_prefix_excess;
77 std::vector<uint32_t> node_min_count;
81 std::vector<uint32_t> node_pattern10_count;
86 std::vector<uint8_t> node_first_bit, node_last_bit;
92 static constexpr size_t npos = std::numeric_limits<size_t>::max();
95 float built_overhead = 0.0;
118 explicit RmMTree(std::span<const std::uint64_t> words,
120 const size_t& leaf_block_bits = 0,
121 const float& max_overhead = -1.0) {
122 build_from_words(words, bit_count, leaf_block_bits, max_overhead);
135 const std::size_t artifact_begin = writer.
size_bytes();
136 detail::write_magic(writer, kSerializationMagic);
138 writer.
write_u8(detail::kLittleEndianMarker);
139 writer.
write_u8(
sizeof(std::uint64_t));
148 detail::write_vector(writer,
149 std::span<const std::uint32_t>(segment_size_bits));
150 detail::write_vector(writer,
151 std::span<const std::int32_t>(node_total_excess));
152 detail::write_vector(writer,
153 std::span<const std::int32_t>(node_min_prefix_excess));
154 detail::write_vector(writer,
155 std::span<const std::int32_t>(node_max_prefix_excess));
156 detail::write_vector(writer,
157 std::span<const std::uint32_t>(node_min_count));
158 detail::write_vector(writer,
159 std::span<const std::uint32_t>(node_pattern10_count));
160 detail::write_vector(writer, std::span<const std::uint8_t>(node_first_bit));
161 detail::write_vector(writer, std::span<const std::uint8_t>(node_last_bit));
163 const std::size_t unpadded_size = writer.
size_bytes() - artifact_begin;
165 (
sizeof(std::uint64_t) - unpadded_size %
sizeof(std::uint64_t)) %
166 sizeof(std::uint64_t));
167 const std::size_t artifact_size = writer.
size_bytes() - artifact_begin;
169 static_cast<std::uint64_t
>(artifact_size));
190 std::span<const std::uint64_t> words,
194 const std::size_t available_size = candidate.
remaining();
195 detail::require_magic(candidate, kSerializationMagic);
196 if (candidate.
read_u32() != kSerializationVersion ||
197 candidate.
read_u8() != detail::kLittleEndianMarker ||
198 candidate.
read_u8() !=
sizeof(std::uint64_t) ||
200 throw std::invalid_argument(
"Incompatible serialized RmM artifact");
202 const std::size_t artifact_size = detail::checked_artifact_size(
203 candidate.
read_u64(), kSerializationHeaderBytes, available_size);
204 const std::size_t source_bit_count = candidate.
read_size();
207 candidate.
read_subreader(artifact_size - kSerializationHeaderBytes);
213 result.first_leaf_index = payload.
read_size();
214 result.segment_size_bits = detail::read_vector<std::uint32_t>(payload);
215 result.node_total_excess = detail::read_vector<std::int32_t>(payload);
216 result.node_min_prefix_excess = detail::read_vector<std::int32_t>(payload);
217 result.node_max_prefix_excess = detail::read_vector<std::int32_t>(payload);
218 result.node_min_count = detail::read_vector<std::uint32_t>(payload);
219 result.node_pattern10_count = detail::read_vector<std::uint32_t>(payload);
220 result.node_first_bit = detail::read_vector<std::uint8_t>(payload);
221 result.node_last_bit = detail::read_vector<std::uint8_t>(payload);
224 if (source_bit_count != result.num_bits) {
225 throw std::invalid_argument(
226 "Serialized RmM source bit count is inconsistent");
228 result.validate_serialized_state(validation);
233 size_t size_impl()
const {
return num_bits; }
242 if (end_position == 0) {
245 const size_t block_index = block_of(end_position - 1);
246 size_t ones_count = 0;
247 if (block_index > 0) {
248 size_t nodes_buffer[64];
249 const size_t node_count =
250 cover_blocks_collect(0, block_index - 1, nodes_buffer);
251 for (
size_t j = 0; j < node_count; ++j) {
252 ones_count += ones_in_node(nodes_buffer[j]);
255 const size_t block_begin = block_index * block_bits;
256 const size_t block_end = std::min(num_bits, block_begin + block_bits);
258 rank1_in_block(block_begin, std::min(end_position, block_end));
267 return end_position -
rank1_impl(end_position);
275 if (target_one_rank == 0 || num_bits == 0) {
278 size_t node_index = 1;
279 if (ones_in_node(node_index) < target_one_rank) {
282 size_t segment_base = 0;
283 while (node_index < first_leaf_index) {
284 const size_t left_child = node_index << 1;
285 const size_t right_child = left_child | 1;
286 const uint32_t ones_in_left_child = ones_in_node(left_child);
287 if (ones_in_left_child >= target_one_rank) {
288 node_index = left_child;
290 target_one_rank -= ones_in_left_child;
291 segment_base += segment_size_bits[left_child];
292 node_index = right_child;
295 return select1_in_block(
297 std::min(segment_base + segment_size_bits[node_index], num_bits),
306 if (target_zero_rank == 0 || num_bits == 0) {
309 size_t node_index = 1;
310 const auto zeros_in_node = [&](
const size_t& node)
noexcept {
311 return segment_size_bits[node] - ones_in_node(node);
313 if (zeros_in_node(node_index) < target_zero_rank) {
316 size_t segment_base = 0;
317 while (node_index < first_leaf_index) {
318 const size_t left_child = node_index << 1;
319 const size_t right_child = left_child | 1;
320 const size_t zeros_in_left_child = zeros_in_node(left_child);
321 if (zeros_in_left_child >= target_zero_rank) {
322 node_index = left_child;
324 target_zero_rank -= zeros_in_left_child;
325 segment_base += segment_size_bits[left_child];
326 node_index = right_child;
329 return select0_in_block(
331 std::min(segment_base + segment_size_bits[node_index], num_bits),
341 if (end_position <= 1) {
344 const size_t block_index = block_of(end_position - 1);
345 size_t pattern_count = 0;
346 int previous_last_bit = -1;
348 if (block_index > 0) {
349 const auto covered_nodes = cover_blocks(0, block_index - 1);
350 for (
const size_t& node_index : covered_nodes) {
351 pattern_count += node_pattern10_count[node_index];
352 if (previous_last_bit != -1 && previous_last_bit == 1 &&
353 node_first_bit[node_index] == 0) {
356 previous_last_bit = node_last_bit[node_index];
359 const size_t block_begin = block_index * block_bits;
360 pattern_count += rr_in_block(block_begin, end_position);
362 if (block_index > 0 && end_position > block_begin &&
363 previous_last_bit == 1 &&
bit(block_begin) == 0) {
366 return pattern_count;
374 if (target_pattern_rank == 0 || num_bits == 0) {
377 size_t node_index = 1;
378 if (node_pattern10_count[node_index] < target_pattern_rank) {
381 const size_t tree_size = segment_size_bits.size() - 1;
382 size_t segment_base = 0;
383 while (node_index < first_leaf_index) {
384 const size_t left_child = node_index << 1;
385 const size_t left_segment_size =
386 (left_child <= tree_size) ? segment_size_bits[left_child] : 0;
387 if (left_segment_size == 0) {
391 const size_t left_count = node_pattern10_count[left_child];
392 if (left_count >= target_pattern_rank) {
393 node_index = left_child;
397 size_t remaining_rank = target_pattern_rank - left_count;
398 const size_t right_child = left_child | 1;
399 const bool has_right =
400 (right_child <= tree_size) && (segment_size_bits[right_child] != 0);
405 const size_t crossing_pattern =
406 (node_last_bit[left_child] == 1 && node_first_bit[right_child] == 0)
409 if (crossing_pattern) {
410 if (remaining_rank == 1) {
411 return segment_base + left_segment_size - 1;
415 segment_base += left_segment_size;
416 node_index = right_child;
417 target_pattern_rank = remaining_rank;
419 return select10_in_block(
421 std::min(segment_base + segment_size_bits[node_index], num_bits),
422 target_pattern_rank);
429 return int64_t(
rank1_impl(end_position)) * 2 - int64_t(end_position);
439 if (start_position >= num_bits) {
444 const size_t leaf_block_index = block_of(start_position);
445 const size_t block_begin = leaf_block_index * block_bits;
446 const size_t block_end = std::min(num_bits, block_begin + block_bits);
448 const size_t leaf_result = leaf_fwd_bp_simd(
449 leaf_block_index, block_begin, start_position, delta, leaf_delta);
450 if (leaf_result !=
npos) {
454 int remaining_delta = delta - leaf_delta;
455 size_t segment_base = block_end;
456 if (remaining_delta == 0) {
463 size_t node_index = leaf_index_of(block_begin);
464 const size_t tree_size = segment_size_bits.size() - 1;
468 if (segment_base >= num_bits || leaf_block_index + 1 >= leaf_count) {
472 while (node_index > 1) {
473 const bool is_left_child = ((node_index & 1u) == 0u);
475 const size_t sibling = node_index | 1u;
476 if (sibling <= tree_size && segment_size_bits[sibling]) {
479 if (node_min_prefix_excess[sibling] <= remaining_delta &&
480 remaining_delta <= node_max_prefix_excess[sibling]) {
481 return descend_fwd(sibling, remaining_delta, segment_base);
484 remaining_delta -= node_total_excess[sibling];
485 segment_base += segment_size_bits[sibling];
486 if (remaining_delta == 0) {
503 if (start_position > num_bits || start_position == 0) {
508 const size_t leaf_block_index = block_of(start_position - 1);
509 const size_t block_begin = leaf_block_index * block_bits;
512 const size_t leaf_result = leaf_bwd_bp_simd(
513 leaf_block_index, block_begin, start_position, delta, leaf_delta);
514 if (leaf_result !=
npos) {
520 int remaining_delta = leaf_delta + delta;
521 size_t node_index = leaf_index_of(block_begin);
522 size_t segment_base = block_begin;
523 while (node_index > 1) {
524 if (node_index & 1) {
525 const size_t sibling_index = node_index ^ 1;
526 const size_t sibling_border =
528 const int needed_inside_sibling =
530 node_total_excess[sibling_index];
532 const bool allow_right_border =
533 (sibling_border != start_position);
536 if (needed_inside_sibling == 0 ||
537 (node_min_prefix_excess[sibling_index] <= needed_inside_sibling &&
538 needed_inside_sibling <= node_max_prefix_excess[sibling_index])) {
539 const size_t result = descend_bwd(
540 sibling_index, sibling_border - segment_size_bits[sibling_index],
541 needed_inside_sibling, sibling_border, allow_right_border);
542 if (result !=
npos) {
547 if (needed_inside_sibling == node_total_excess[sibling_index] &&
548 sibling_border < start_position) {
549 return sibling_border;
553 remaining_delta += node_total_excess[sibling_index];
554 segment_base -= segment_size_bits[sibling_index];
568 const size_t& range_end)
const {
569 if (range_begin > range_end || range_end >= num_bits) {
573 const size_t begin_block_index = block_of(range_begin);
574 const size_t begin_block_start = begin_block_index * block_bits;
575 const size_t begin_block_end =
576 std::min(num_bits, begin_block_start + block_bits);
577 const size_t end_block_index = block_of(range_end);
578 const size_t end_block_start = end_block_index * block_bits;
580 int best_value = INT_MAX;
581 size_t best_position =
npos;
582 size_t chosen_node_index = 0;
583 int prefix_excess = 0, prefix_at_choice = 0;
586 int min_prefix_first_chunk = INT_MAX;
587 size_t first_chunk_position =
npos;
588 const size_t end_of_first_chunk = std::min(
589 range_end, (
size_t)(begin_block_end ? begin_block_end - 1 : 0));
590 if (range_begin <= end_of_first_chunk) {
591 first_min_value_pos8(range_begin, end_of_first_chunk,
592 min_prefix_first_chunk, first_chunk_position);
594 (int64_t)rank1_in_block(range_begin, end_of_first_chunk + 1) * 2 -
595 int64_t(end_of_first_chunk + 1 - range_begin);
596 best_value = min_prefix_first_chunk;
597 best_position = first_chunk_position;
598 chosen_node_index = 0;
602 if (begin_block_index + 1 <= end_block_index - 1) {
603 size_t left_index = first_leaf_index + (begin_block_index + 1);
604 size_t right_index = first_leaf_index + (end_block_index - 1);
605 size_t right_nodes[64];
606 int right_nodes_count = 0;
608 while (left_index <= right_index) {
609 if (left_index & 1) {
610 const size_t node_index = left_index++;
611 const int candidate =
612 prefix_excess + node_min_prefix_excess[node_index];
613 if (candidate < best_value) {
614 best_value = candidate;
615 best_position =
npos;
616 chosen_node_index = node_index;
617 prefix_at_choice = prefix_excess;
619 prefix_excess += node_total_excess[node_index];
621 if ((right_index & 1) == 0) {
622 right_nodes[right_nodes_count++] = right_index--;
627 while (right_nodes_count--) {
628 const size_t node_index = right_nodes[right_nodes_count];
629 const int candidate =
630 prefix_excess + node_min_prefix_excess[node_index];
631 if (candidate < best_value) {
632 best_value = candidate;
633 best_position =
npos;
634 chosen_node_index = node_index;
635 prefix_at_choice = prefix_excess;
637 prefix_excess += node_total_excess[node_index];
642 if (end_block_index != begin_block_index) {
643 int min_prefix_last_chunk;
644 size_t last_chunk_position;
645 first_min_value_pos8(end_block_start, range_end, min_prefix_last_chunk,
646 last_chunk_position);
647 const int candidate = prefix_excess + min_prefix_last_chunk;
648 if (candidate < best_value) {
649 best_value = candidate;
650 best_position = last_chunk_position;
651 chosen_node_index = 0;
655 if (best_position !=
npos) {
656 return best_position;
659 return descend_first_min(chosen_node_index, best_value - prefix_at_choice,
660 node_base(chosen_node_index));
670 const size_t& range_end)
const {
671 if (range_begin > range_end || range_end >= num_bits) {
675 if (min_position ==
npos) {
688 const size_t& range_end)
const {
689 if (range_begin > range_end || range_end >= num_bits) {
693 const size_t begin_block_index = block_of(range_begin);
694 const size_t begin_block_start = begin_block_index * block_bits;
695 const size_t begin_block_end =
696 std::min(num_bits, begin_block_start + block_bits);
697 const size_t end_block_index = block_of(range_end);
698 const size_t end_block_start = end_block_index * block_bits;
700 int best_value = INT_MIN;
701 size_t best_position =
npos;
702 size_t chosen_node_index = 0;
703 int prefix_excess = 0, prefix_at_choice = 0;
706 int max_prefix_first_chunk = INT_MIN;
707 size_t first_chunk_position =
npos;
708 const size_t end_of_first_chunk = std::min(
709 range_end, (
size_t)(begin_block_end ? begin_block_end - 1 : 0));
710 if (range_begin <= end_of_first_chunk) {
711 first_max_value_pos8(range_begin, end_of_first_chunk,
712 max_prefix_first_chunk, first_chunk_position);
714 (int64_t)rank1_in_block(range_begin, end_of_first_chunk + 1) * 2 -
715 int64_t(end_of_first_chunk + 1 - range_begin);
716 best_value = max_prefix_first_chunk;
717 best_position = first_chunk_position;
718 chosen_node_index = 0;
722 if (begin_block_index + 1 <= end_block_index - 1) {
723 size_t left_index = first_leaf_index + (begin_block_index + 1);
724 size_t right_index = first_leaf_index + (end_block_index - 1);
725 size_t right_nodes[64];
726 int right_nodes_count = 0;
728 while (left_index <= right_index) {
729 if (left_index & 1) {
730 const size_t node_index = left_index++;
731 const int candidate =
732 prefix_excess + node_max_prefix_excess[node_index];
733 if (candidate > best_value) {
734 best_value = candidate;
735 best_position =
npos;
736 chosen_node_index = node_index;
737 prefix_at_choice = prefix_excess;
739 prefix_excess += node_total_excess[node_index];
741 if ((right_index & 1) == 0) {
742 right_nodes[right_nodes_count++] = right_index--;
747 while (right_nodes_count--) {
748 const size_t node_index = right_nodes[right_nodes_count];
749 const int candidate =
750 prefix_excess + node_max_prefix_excess[node_index];
751 if (candidate > best_value) {
752 best_value = candidate;
753 best_position =
npos;
754 chosen_node_index = node_index;
755 prefix_at_choice = prefix_excess;
757 prefix_excess += node_total_excess[node_index];
762 if (end_block_index != begin_block_index) {
763 int max_prefix_last_chunk;
764 size_t last_chunk_position;
765 first_max_value_pos8(end_block_start, range_end, max_prefix_last_chunk,
766 last_chunk_position);
767 const int candidate = prefix_excess + max_prefix_last_chunk;
768 if (candidate > best_value) {
769 best_value = candidate;
770 best_position = last_chunk_position;
771 chosen_node_index = 0;
775 if (best_position !=
npos) {
776 return best_position;
779 return descend_first_max(chosen_node_index, best_value - prefix_at_choice,
780 node_base(chosen_node_index));
788 const size_t& range_end)
const {
789 if (range_begin > range_end || range_end >= num_bits) {
793 if (max_position ==
npos) {
804 const size_t& range_end)
const {
805 if (range_begin > range_end || range_end >= num_bits) {
809 const size_t begin_block_index = block_of(range_begin);
810 const size_t begin_block_start = begin_block_index * block_bits;
811 const size_t begin_block_end =
812 std::min(num_bits, begin_block_start + block_bits);
813 const size_t end_block_index = block_of(range_end);
814 const size_t end_block_start = end_block_index * block_bits;
816 int best_value = INT_MAX;
817 size_t min_count = 0;
818 int prefix_excess = 0;
822 int current_excess = 0, min_value = INT_MAX, local_count = 0;
823 const size_t end_of_first_chunk =
824 std::min(range_end, begin_block_end - 1);
825 for (
size_t position = range_begin; position <= end_of_first_chunk;
827 current_excess +=
bit(position) ? +1 : -1;
828 if (current_excess < min_value) {
829 min_value = current_excess;
831 }
else if (current_excess == min_value) {
835 best_value = min_value;
836 min_count = local_count;
837 prefix_excess = current_excess;
841 if (begin_block_index + 1 <= end_block_index - 1) {
842 const auto middle_nodes =
843 cover_blocks(begin_block_index + 1, end_block_index - 1);
844 for (
const size_t& node_index : middle_nodes) {
845 const int candidate =
846 prefix_excess + node_min_prefix_excess[node_index];
847 if (candidate < best_value) {
848 best_value = candidate;
849 min_count = node_min_count[node_index];
850 }
else if (candidate == best_value) {
851 min_count += node_min_count[node_index];
853 prefix_excess += node_total_excess[node_index];
858 if (end_block_index != begin_block_index) {
859 int current_excess = 0, min_value = INT_MAX, local_count = 0;
860 for (
size_t position = end_block_start; position <= range_end;
862 current_excess +=
bit(position) ? +1 : -1;
863 if (current_excess < min_value) {
864 min_value = current_excess;
866 }
else if (current_excess == min_value) {
870 const int candidate = prefix_excess + min_value;
871 if (candidate < best_value) {
872 best_value = candidate;
873 min_count = local_count;
874 }
else if (candidate == best_value) {
875 min_count += local_count;
888 const size_t& range_end,
889 size_t target_min_rank)
const {
890 if (range_begin > range_end || range_end >= num_bits ||
891 target_min_rank == 0) {
895 const size_t begin_block_index = block_of(range_begin);
896 const size_t begin_block_start = begin_block_index * block_bits;
897 const size_t begin_block_end =
898 std::min(num_bits, begin_block_start + block_bits);
899 const size_t end_block_index = block_of(range_end);
900 const size_t end_block_start = end_block_index * block_bits;
903 const size_t end_of_first_chunk = std::min(range_end, begin_block_end - 1);
904 int current_first_chunk_excess = 0, min_first_chunk = 0;
905 uint32_t count_first_chunk = 0;
907 if (range_begin <= end_of_first_chunk) {
908 scan_range_min_count8(range_begin, end_of_first_chunk,
909 current_first_chunk_excess, min_first_chunk,
912 current_first_chunk_excess = 0;
913 min_first_chunk = INT_MAX;
914 count_first_chunk = 0;
917 int best_value = (min_first_chunk == INT_MAX ? INT_MAX : min_first_chunk);
919 (min_first_chunk == INT_MAX ? 0u : (size_t)count_first_chunk);
920 int prefix_excess = current_first_chunk_excess;
922 size_t left_index = first_leaf_index + begin_block_index + 1;
923 size_t right_index = first_leaf_index + end_block_index - 1;
924 size_t right_nodes[64];
925 int right_nodes_count = 0;
928 if (begin_block_index + 1 <= end_block_index - 1) {
929 while (left_index <= right_index) {
930 if (left_index & 1) {
931 const int candidate =
932 prefix_excess + node_min_prefix_excess[left_index];
933 if (candidate < best_value) {
934 best_value = candidate;
935 total_count = node_min_count[left_index];
936 }
else if (candidate == best_value) {
937 total_count += node_min_count[left_index];
939 prefix_excess += node_total_excess[left_index++];
941 if ((right_index & 1) == 0) {
942 right_nodes[right_nodes_count++] = right_index--;
947 while (right_nodes_count--) {
948 const size_t node_index = right_nodes[right_nodes_count];
949 const int candidate =
950 prefix_excess + node_min_prefix_excess[node_index];
951 if (candidate < best_value) {
952 best_value = candidate;
953 total_count = node_min_count[node_index];
954 }
else if (candidate == best_value) {
955 total_count += node_min_count[node_index];
957 prefix_excess += node_total_excess[node_index];
962 int current_last_chunk_excess = 0, min_last_chunk = INT_MAX;
963 uint32_t count_last_chunk = 0;
964 if (end_block_index != begin_block_index) {
965 scan_range_min_count8(end_block_start, range_end,
966 current_last_chunk_excess, min_last_chunk,
968 const int candidate = prefix_excess + min_last_chunk;
969 if (candidate < best_value) {
970 best_value = candidate;
971 total_count = count_last_chunk;
972 }
else if (candidate == best_value) {
973 total_count += count_last_chunk;
977 if (target_min_rank > total_count) {
982 if (min_first_chunk == best_value && count_first_chunk) {
983 if (target_min_rank <= count_first_chunk) {
984 return qth_min_in_block(range_begin, end_of_first_chunk,
987 target_min_rank -= count_first_chunk;
991 prefix_excess = current_first_chunk_excess;
992 if (begin_block_index + 1 <= end_block_index - 1) {
993 left_index = first_leaf_index + (begin_block_index + 1);
994 right_index = first_leaf_index + (end_block_index - 1);
995 right_nodes_count = 0;
996 while (left_index <= right_index) {
997 if (left_index & 1) {
998 const size_t node_index = left_index++;
999 const int candidate =
1000 prefix_excess + node_min_prefix_excess[node_index];
1001 if (candidate == best_value) {
1002 if (target_min_rank <= node_min_count[node_index]) {
1003 return descend_qth_min(node_index, best_value - prefix_excess,
1004 target_min_rank, node_base(node_index));
1006 target_min_rank -= node_min_count[node_index];
1008 prefix_excess += node_total_excess[node_index];
1010 if (!(right_index & 1)) {
1011 right_nodes[right_nodes_count++] = right_index--;
1016 while (right_nodes_count--) {
1017 const size_t node_index = right_nodes[right_nodes_count];
1018 const int candidate =
1019 prefix_excess + node_min_prefix_excess[node_index];
1020 if (candidate == best_value) {
1021 if (target_min_rank <= node_min_count[node_index]) {
1022 return descend_qth_min(node_index, best_value - prefix_excess,
1023 target_min_rank, node_base(node_index));
1025 target_min_rank -= node_min_count[node_index];
1027 prefix_excess += node_total_excess[node_index];
1032 if (end_block_index != begin_block_index &&
1033 (prefix_excess + min_last_chunk) == best_value) {
1034 return qth_min_in_block(end_block_start, range_end, target_min_rank);
1048 if (open_position >= num_bits) {
1051 if (!
bit(open_position)) {
1052 return open_position;
1062 inline size_t open_impl(
const size_t& close_position)
const {
1063 if (close_position >= num_bits) {
1066 if (
bit(close_position)) {
1067 return close_position;
1078 if (position >= num_bits) {
1081 if (!
bit(position)) {
1090 inline int bit(
const size_t& position)
const noexcept {
1091 return (bits[position >> 6] >> (position & 63)) & 1u;
1096 const std::size_t required_words =
1097 num_bits == 0 ? 0 : 1 + (num_bits - 1) / 64;
1098 if (required_words > bits.size()) {
1099 throw std::invalid_argument(
"RmM source word span is too small");
1101 if (block_bits == 0 || !std::has_single_bit(block_bits) ||
1102 block_bits > std::numeric_limits<std::uint32_t>::max()) {
1103 throw std::invalid_argument(
"Invalid serialized RmM block size");
1106 const std::size_t expected_leaf_count =
1107 num_bits == 0 ? 0 : 1 + (num_bits - 1) / block_bits;
1108 if (leaf_count != expected_leaf_count ||
1109 leaf_count > std::bit_floor(std::numeric_limits<std::size_t>::max())) {
1110 throw std::invalid_argument(
"Invalid serialized RmM leaf count");
1112 const std::size_t expected_first_leaf =
1113 std::bit_ceil(std::max<std::size_t>(1, leaf_count));
1114 if (first_leaf_index != expected_first_leaf ||
1116 std::numeric_limits<std::size_t>::max() - first_leaf_index) {
1117 throw std::invalid_argument(
"Invalid serialized RmM tree shape");
1120 const std::size_t expected_node_count = num_bits == 0
1121 ? segment_size_bits.size()
1122 : first_leaf_index + leaf_count;
1123 const bool supported_empty_shape =
1124 num_bits != 0 || expected_node_count == 0 || expected_node_count == 1;
1125 if (!supported_empty_shape ||
1126 (num_bits != 0 && segment_size_bits.size() != expected_node_count) ||
1127 node_total_excess.size() != segment_size_bits.size() ||
1128 node_min_prefix_excess.size() != segment_size_bits.size() ||
1129 node_max_prefix_excess.size() != segment_size_bits.size() ||
1130 node_min_count.size() != segment_size_bits.size() ||
1131 node_pattern10_count.size() != segment_size_bits.size() ||
1132 node_first_bit.size() != segment_size_bits.size() ||
1133 node_last_bit.size() != segment_size_bits.size()) {
1134 throw std::invalid_argument(
1135 "Invalid serialized RmM metadata vector sizes");
1138 const std::size_t node_count = segment_size_bits.size();
1139 const auto node_is_zero = [&](std::size_t node) {
1140 return segment_size_bits[node] == 0 && node_total_excess[node] == 0 &&
1141 node_min_prefix_excess[node] == 0 &&
1142 node_max_prefix_excess[node] == 0 && node_min_count[node] == 0 &&
1143 node_pattern10_count[node] == 0 && node_first_bit[node] == 0 &&
1144 node_last_bit[node] == 0;
1146 if (node_count != 0 && !node_is_zero(0)) {
1147 throw std::invalid_argument(
"Invalid serialized RmM sentinel metadata");
1149 if (num_bits == 0) {
1150 if (node_count == 1 && !node_is_zero(0)) {
1151 throw std::invalid_argument(
"Invalid serialized empty RmM metadata");
1156 const auto signed_magnitude = [](std::int64_t value) {
1158 ?
static_cast<std::uint64_t
>(-(value + 1)) + std::uint64_t{1}
1159 :
static_cast<std::uint64_t
>(value);
1162 for (std::size_t leaf = 0; leaf < leaf_count; ++leaf) {
1163 const std::size_t node = first_leaf_index + leaf;
1164 const std::size_t begin = leaf * block_bits;
1165 const std::size_t expected_size = std::min(block_bits, num_bits - begin);
1166 if (validation == DeserializationValidation::kFull) {
1167 std::int64_t total = 0;
1168 std::int64_t minimum = std::numeric_limits<std::int64_t>::max();
1169 std::int64_t maximum = std::numeric_limits<std::int64_t>::min();
1170 std::uint64_t minimum_count = 0;
1171 std::uint64_t pattern10_count = 0;
1172 std::uint8_t previous_bit = 0;
1173 for (std::size_t position = begin; position < begin + expected_size;
1175 const std::uint8_t current_bit =
1176 static_cast<std::uint8_t
>(
bit(position));
1177 if (position != begin && previous_bit == 1 && current_bit == 0) {
1180 total += current_bit != 0 ? 1 : -1;
1181 if (total < minimum) {
1184 }
else if (total == minimum) {
1187 maximum = std::max(maximum, total);
1188 previous_bit = current_bit;
1190 if (segment_size_bits[node] != expected_size ||
1191 node_total_excess[node] != total ||
1192 node_min_prefix_excess[node] != minimum ||
1193 node_max_prefix_excess[node] != maximum ||
1194 node_min_count[node] != minimum_count ||
1195 node_pattern10_count[node] != pattern10_count ||
1196 node_first_bit[node] !=
bit(begin) ||
1197 node_last_bit[node] != previous_bit) {
1198 throw std::invalid_argument(
1199 "Serialized RmM leaf metadata disagrees with source");
1203 const std::int64_t total = node_total_excess[node];
1204 const std::int64_t minimum = node_min_prefix_excess[node];
1205 const std::int64_t maximum = node_max_prefix_excess[node];
1206 const std::int64_t expected_signed_size =
1207 static_cast<std::int64_t
>(expected_size);
1208 if (segment_size_bits[node] != expected_size ||
1209 signed_magnitude(total) > expected_size ||
1210 ((expected_signed_size + total) & 1) != 0 || minimum > total ||
1211 maximum < total || minimum < -expected_signed_size ||
1212 maximum > expected_signed_size || node_min_count[node] == 0 ||
1213 node_min_count[node] > expected_size ||
1214 node_pattern10_count[node] >= expected_size ||
1215 node_first_bit[node] > 1 || node_last_bit[node] > 1) {
1216 throw std::invalid_argument(
"Invalid serialized RmM leaf metadata");
1220 for (std::size_t node = first_leaf_index; node-- > 1;) {
1221 if (validation == DeserializationValidation::kQuick) {
1222 const std::size_t
size = segment_size_bits[node];
1223 const std::int64_t minimum = node_min_prefix_excess[node];
1224 const std::int64_t maximum = node_max_prefix_excess[node];
1225 if (
size > num_bits ||
1226 signed_magnitude(node_total_excess[node]) >
size ||
1227 (minimum < 0 && signed_magnitude(minimum) >
size) ||
1228 (maximum > 0 &&
static_cast<std::uint64_t
>(maximum) >
size) ||
1229 node_min_prefix_excess[node] > node_max_prefix_excess[node] ||
1230 node_min_count[node] > segment_size_bits[node] ||
1231 node_pattern10_count[node] > segment_size_bits[node] ||
1232 node_first_bit[node] > 1 || node_last_bit[node] > 1) {
1233 throw std::invalid_argument(
1234 "Invalid serialized RmM internal metadata");
1238 const std::size_t left = node << 1;
1239 const std::size_t right = left | 1;
1240 const bool has_left = left < node_count && segment_size_bits[left] != 0;
1241 const bool has_right =
1242 right < node_count && segment_size_bits[right] != 0;
1243 if (!has_left && !has_right) {
1244 if (!node_is_zero(node)) {
1245 throw std::invalid_argument(
1246 "Invalid serialized empty RmM internal node");
1251 const std::size_t first = has_left ? left : right;
1252 if (has_left != has_right) {
1253 if (segment_size_bits[node] != segment_size_bits[first] ||
1254 node_total_excess[node] != node_total_excess[first] ||
1255 node_min_prefix_excess[node] != node_min_prefix_excess[first] ||
1256 node_max_prefix_excess[node] != node_max_prefix_excess[first] ||
1257 node_min_count[node] != node_min_count[first] ||
1258 node_pattern10_count[node] != node_pattern10_count[first] ||
1259 node_first_bit[node] != node_first_bit[first] ||
1260 node_last_bit[node] != node_last_bit[first]) {
1261 throw std::invalid_argument(
1262 "Invalid serialized unary RmM internal node");
1267 const std::uint64_t expected_size =
1268 static_cast<std::uint64_t
>(segment_size_bits[left]) +
1269 segment_size_bits[right];
1270 const std::int64_t expected_total =
1271 static_cast<std::int64_t
>(node_total_excess[left]) +
1272 node_total_excess[right];
1273 const std::int64_t right_min =
1274 static_cast<std::int64_t
>(node_total_excess[left]) +
1275 node_min_prefix_excess[right];
1276 const std::int64_t right_max =
1277 static_cast<std::int64_t
>(node_total_excess[left]) +
1278 node_max_prefix_excess[right];
1279 const std::int64_t expected_min =
1280 std::min<std::int64_t>(node_min_prefix_excess[left], right_min);
1281 const std::int64_t expected_max =
1282 std::max<std::int64_t>(node_max_prefix_excess[left], right_max);
1283 const std::uint64_t expected_min_count =
1284 (node_min_prefix_excess[left] == expected_min ? node_min_count[left]
1286 (right_min == expected_min ? node_min_count[right] : 0);
1287 const std::uint64_t expected_pattern_count =
1288 static_cast<std::uint64_t
>(node_pattern10_count[left]) +
1289 node_pattern10_count[right] +
1290 (node_last_bit[left] == 1 && node_first_bit[right] == 0 ? 1 : 0);
1291 if (segment_size_bits[node] != expected_size ||
1292 node_total_excess[node] != expected_total ||
1293 node_min_prefix_excess[node] != expected_min ||
1294 node_max_prefix_excess[node] != expected_max ||
1295 node_min_count[node] != expected_min_count ||
1296 node_pattern10_count[node] != expected_pattern_count ||
1297 node_first_bit[node] != node_first_bit[left] ||
1298 node_last_bit[node] != node_last_bit[right]) {
1299 throw std::invalid_argument(
1300 "Invalid serialized binary RmM internal node");
1303 if (segment_size_bits[1] != num_bits) {
1304 throw std::invalid_argument(
1305 "Serialized RmM root does not cover the source");
1314 static inline size_t pop10_in_slice64(
const std::uint64_t& slice,
1315 const int& length)
noexcept {
1319 std::uint64_t pattern_mask = slice & ~(slice >> 1);
1321 pattern_mask &= ((std::uint64_t(1) << (length - 1)) - 1);
1323 pattern_mask &= 0x7FFFFFFFFFFFFFFFull;
1325 return (
size_t)std::popcount(pattern_mask);
1332 size_t rank1_in_block(
const size_t& block_begin,
1333 const size_t& block_end)
const noexcept {
1334 if (block_end <= block_begin) {
1337 size_t left_word_index = block_begin >> 6;
1338 const size_t right_word_index = block_end >> 6;
1339 size_t left_offset = block_begin & 63;
1340 const size_t right_offset = block_end & 63;
1342 if (left_word_index == right_word_index) {
1343 const std::uint64_t mask =
1344 ((right_offset == 0) ? 0 : ((std::uint64_t(1) << right_offset) - 1)) &
1345 (~std::uint64_t(0) << left_offset);
1346 return (
size_t)std::popcount(bits[left_word_index] & mask);
1349 count += (size_t)std::popcount(bits[left_word_index] &
1350 (~std::uint64_t(0) << left_offset));
1353 while (left_word_index < right_word_index) {
1354 count += (size_t)std::popcount(bits[left_word_index]);
1358 count += (size_t)std::popcount(bits[right_word_index] &
1359 ((std::uint64_t(1) << right_offset) - 1));
1368 size_t rr_in_block(
const size_t& block_begin,
1369 const size_t& block_end)
const noexcept {
1370 if (block_end <= block_begin + 1) {
1373 size_t left_word_index = block_begin >> 6;
1374 const size_t right_word_index = (block_end - 1) >> 6;
1375 const int left_offset = block_begin & 63;
1376 const int right_offset = (block_end - 1) & 63;
1379 if (left_word_index == right_word_index) {
1380 const int length = right_offset - left_offset + 1;
1381 const std::uint64_t slice = bits[left_word_index] >> left_offset;
1382 return pop10_in_slice64(slice, length);
1387 const int length = 64 - left_offset;
1388 const std::uint64_t slice = bits[left_word_index] >> left_offset;
1389 count += pop10_in_slice64(slice, length);
1392 for (
size_t word_index = left_word_index + 1; word_index < right_word_index;
1394 const std::uint64_t word = bits[word_index];
1395 count += pop10_in_slice64(word, 64);
1399 const int length = right_offset + 1;
1400 const std::uint64_t mask = (length == 64)
1402 : ((std::uint64_t(1) << length) - 1);
1403 const std::uint64_t slice = bits[right_word_index] & mask;
1404 count += pop10_in_slice64(slice, length);
1407 for (
size_t word_index = left_word_index; word_index < right_word_index;
1409 if (((bits[word_index] >> 63) & 1u) &&
1410 ((bits[word_index + 1] & 1u) == 0)) {
1422 size_t select10_in_block(
const size_t& block_begin,
1423 const size_t& block_end,
1424 size_t target_pattern_rank)
const noexcept {
1425 if (block_end <= block_begin + 1) {
1428 size_t left_word_index = block_begin >> 6;
1429 const size_t right_word_index = (block_end - 1) >> 6;
1430 const int left_offset = block_begin & 63;
1431 const int right_offset = (block_end - 1) & 63;
1433 const auto select_in_masked_slice =
1434 [&](
const std::uint64_t& slice,
const int& length,
1435 const size_t& target_index)
noexcept ->
int {
1439 std::uint64_t pattern_mask = slice & ~(slice >> 1);
1441 pattern_mask &= ((std::uint64_t(1) << (length - 1)) - 1);
1443 pattern_mask &= 0x7FFFFFFFFFFFFFFFull;
1445 return select_in_word(pattern_mask, target_index);
1448 if (left_word_index == right_word_index) {
1449 const int length = right_offset - left_offset + 1;
1450 const std::uint64_t slice = bits[left_word_index] >> left_offset;
1452 select_in_masked_slice(slice, length, target_pattern_rank);
1453 return offset >= 0 ? (block_begin + (size_t)offset) :
npos;
1458 const int length = 64 - left_offset;
1459 const std::uint64_t slice = bits[left_word_index] >> left_offset;
1460 std::uint64_t pattern_mask = slice & ~(slice >> 1);
1461 pattern_mask &= ((std::uint64_t(1) << (length - 1)) - 1);
1462 const int count = std::popcount(pattern_mask);
1463 if (target_pattern_rank <= (
size_t)count) {
1465 select_in_masked_slice(slice, length, target_pattern_rank);
1466 return block_begin + (size_t)offset;
1468 target_pattern_rank -= count;
1472 for (
size_t word_index = left_word_index; word_index + 1 < right_word_index;
1475 if (((bits[word_index] >> 63) & 1u) &&
1476 ((bits[word_index + 1] & 1u) == 0)) {
1477 if (--target_pattern_rank == 0) {
1478 return (word_index << 6) + 63;
1482 const std::uint64_t next_word = bits[word_index + 1];
1483 const std::uint64_t pattern_mask =
1484 (next_word & ~(next_word >> 1)) & 0x7FFFFFFFFFFFFFFFull;
1485 const int count = std::popcount(pattern_mask);
1486 if (target_pattern_rank <= (
size_t)count) {
1487 const int offset = select_in_word(pattern_mask, target_pattern_rank);
1491 return ((word_index + 1) << 6) + (size_t)offset;
1493 target_pattern_rank -= count;
1497 if (((bits[right_word_index - 1] >> 63) & 1u) &&
1498 ((bits[right_word_index] & 1u) == 0)) {
1499 if (--target_pattern_rank == 0) {
1500 return ((right_word_index - 1) << 6) + 63;
1506 const int length = right_offset + 1;
1507 const std::uint64_t mask = (length == 64)
1509 : ((std::uint64_t(1) << length) - 1);
1510 const std::uint64_t slice = bits[right_word_index] & mask;
1512 select_in_masked_slice(slice, length, target_pattern_rank);
1514 return (right_word_index << 6) + (size_t)offset;
1521 int8_t excess_total;
1525 uint8_t pattern10_count;
1528 uint8_t pos_first_min;
1529 uint8_t pos_first_max;
1533 std::array<ByteAgg, 256> agg;
1538 std::array<std::array<int8_t, 17>, 256> fwd_pos;
1543 std::array<std::array<int8_t, 17>, 256> bwd_pos;
1549 static inline const LUT8Tables& LUT8_ALL() noexcept {
1550 static const LUT8Tables tables = [] {
1551 LUT8Tables lookup_tables{};
1552 for (
int byte_value = 0; byte_value < 256; ++byte_value) {
1553 int current_excess = 0, min_prefix = INT_MAX, max_prefix = INT_MIN,
1554 min_count = 0, pattern10_count = 0;
1555 int first_min_position = 0, first_max_position = 0;
1557 const auto bit_at = [&](
const int& bit_index) {
1558 return (byte_value >> bit_index) & 1;
1560 for (
int bit_index = 0; bit_index < 8; ++bit_index) {
1561 int bit_value = bit_at(bit_index);
1562 if (bit_index + 1 < 8 && bit_value && bit_at(bit_index + 1) == 0) {
1565 current_excess += bit_value ? +1 : -1;
1566 prefixes[bit_index] = current_excess;
1567 if (current_excess < min_prefix) {
1568 min_prefix = current_excess;
1570 first_min_position = bit_index;
1571 }
else if (current_excess == min_prefix) {
1574 if (current_excess > max_prefix) {
1575 max_prefix = current_excess;
1576 first_max_position = bit_index;
1579 ByteAgg aggregates{};
1580 aggregates.excess_total = current_excess;
1581 aggregates.min_prefix = (min_prefix == INT_MAX ? 0 : min_prefix);
1582 aggregates.max_prefix = (max_prefix == INT_MIN ? 0 : max_prefix);
1583 aggregates.min_count = min_count;
1584 aggregates.pattern10_count = pattern10_count;
1585 aggregates.first_bit = bit_at(0);
1586 aggregates.last_bit = bit_at(7);
1587 aggregates.pos_first_min = first_min_position;
1588 aggregates.pos_first_max = first_max_position;
1589 lookup_tables.agg[byte_value] = aggregates;
1590 auto& forward_positions = lookup_tables.fwd_pos[byte_value];
1591 auto& backward_positions = lookup_tables.bwd_pos[byte_value];
1592 forward_positions.fill(-1);
1593 backward_positions.fill(-1);
1594 for (
int delta = -8; delta <= 8; ++delta) {
1595 for (
int bit_index = 0; bit_index < 8; ++bit_index) {
1596 if (prefixes[bit_index] == delta) {
1597 forward_positions[delta + 8] = bit_index;
1601 for (
int bit_index = 7; bit_index >= 0; --bit_index) {
1602 if (prefixes[bit_index] == delta) {
1603 backward_positions[delta + 8] = bit_index;
1609 return lookup_tables;
1617 static inline const std::array<ByteAgg, 256>& LUT8() noexcept {
1618 return LUT8_ALL().agg;
1624 static inline const std::array<std::array<int8_t, 17>, 256>&
1625 LUT8_FWD_POS() noexcept {
1626 return LUT8_ALL().fwd_pos;
1632 static inline const std::array<std::array<int8_t, 17>, 256>&
1633 LUT8_BWD_POS() noexcept {
1634 return LUT8_ALL().bwd_pos;
1640 inline uint16_t get_u16(
const size_t& position)
const noexcept {
1641 const size_t word_index = position >> 6;
1642 const unsigned offset = unsigned(position & 63);
1643 const std::uint64_t w0 =
1644 (word_index < bits.size()) ? bits[word_index] : 0ULL;
1646 return uint16_t(w0 & 0xFFFFu);
1648 const std::uint64_t w1 =
1649 (word_index + 1 < bits.size()) ? bits[word_index + 1] : 0ULL;
1650 const std::uint64_t v = (w0 >> offset) | (w1 << (64u - offset));
1651 return uint16_t(v & 0xFFFFu);
1654#if defined(PIXIE_AVX2_SUPPORT)
1655 static inline __m256i bit_masks_16x() noexcept {
1657 return _mm256_setr_epi16(0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020,
1658 0x0040, 0x0080, 0x0100, 0x0200, 0x0400, 0x0800,
1659 0x1000, 0x2000, 0x4000, (int16_t)0x8000);
1662 static inline __m256i prefix_sum_16x_i16(__m256i v)
noexcept {
1666 __m256i t = _mm256_slli_si256(x, 2);
1667 x = _mm256_add_epi16(x, t);
1668 t = _mm256_slli_si256(x, 4);
1669 x = _mm256_add_epi16(x, t);
1670 t = _mm256_slli_si256(x, 8);
1671 x = _mm256_add_epi16(x, t);
1673 __m128i lo = _mm256_extracti128_si256(x, 0);
1674 __m128i hi = _mm256_extracti128_si256(x, 1);
1675 const int16_t carry =
1676 (int16_t)_mm_extract_epi16(lo, 7);
1677 hi = _mm_add_epi16(hi, _mm_set1_epi16(carry));
1679 __m256i out = _mm256_castsi128_si256(lo);
1680 out = _mm256_inserti128_si256(out, hi, 1);
1684 static inline int16_t last_prefix_16x_i16(__m256i pref)
noexcept {
1685 __m128i hi = _mm256_extracti128_si256(pref, 1);
1686 return (int16_t)_mm_extract_epi16(hi, 7);
1695 inline size_t scan_leaf_fwd_simd(
const size_t& start,
1697 const int& required_delta,
1698 int* out_total)
const noexcept {
1705 if (required_delta < -32768 || required_delta > 32767) {
1707 const int len = int(end - start);
1708 const int ones = int(rank1_in_block(start, end));
1709 *out_total = ones * 2 - len;
1714 static const __m256i masks = bit_masks_16x();
1715 static const __m256i vzero = _mm256_setzero_si256();
1716 static const __m256i vallones = _mm256_cmpeq_epi16(vzero, vzero);
1717 static const __m256i vminus1 = _mm256_set1_epi16(-1);
1718 static const __m256i vtwo = _mm256_set1_epi16(2);
1719 const __m256i vtarget = _mm256_set1_epi16((int16_t)required_delta);
1723 while (pos + 16 <= end) {
1724 const uint16_t bits16 = get_u16(pos);
1725 const __m256i vb = _mm256_set1_epi16((int16_t)bits16);
1726 const __m256i m = _mm256_and_si256(vb, masks);
1727 const __m256i is_zero = _mm256_cmpeq_epi16(m, vzero);
1728 const __m256i is_set = _mm256_andnot_si256(is_zero, vallones);
1729 const __m256i steps =
1730 _mm256_add_epi16(vminus1, _mm256_and_si256(is_set, vtwo));
1732 const __m256i pref_rel = prefix_sum_16x_i16(steps);
1733 const __m256i base = _mm256_set1_epi16((int16_t)cur);
1734 const __m256i pref = _mm256_add_epi16(pref_rel, base);
1735 const __m256i cmp = _mm256_cmpeq_epi16(pref, vtarget);
1736 const uint32_t mask = (uint32_t)_mm256_movemask_epi8(cmp);
1738 const int lane = int(std::countr_zero(mask)) >> 1;
1739 return pos + (size_t)lane;
1741 cur += (int)last_prefix_16x_i16(pref_rel);
1745 cur +=
bit(pos) ? +1 : -1;
1746 if (cur == required_delta) {
1764 inline size_t scan_leaf_fwd_lut8_fast(
const size_t& start,
1766 const int& required_delta,
1767 int* out_total)
const noexcept {
1777 while (pos < end && (pos & 7)) {
1778 cur +=
bit(pos) ? +1 : -1;
1779 if (cur == required_delta) {
1791 const uint8_t* bytep =
1792 reinterpret_cast<const uint8_t*
>(bits.data()) + (pos >> 3);
1793 const auto& agg = LUT8();
1794 const auto& fwd = LUT8_FWD_POS();
1796 while (pos + 8 <= end) {
1797 const uint8_t bv = *bytep++;
1798 const auto& a = agg[bv];
1799 const int need = required_delta - cur;
1801 if ((
unsigned)(need + 8) <= 16u) {
1803 if (need >= a.min_prefix && need <= a.max_prefix) {
1804 const int8_t off = fwd[bv][need + 8];
1807 *out_total = cur + a.excess_total;
1810 return pos + (size_t)off;
1814 cur += a.excess_total;
1819 cur +=
bit(pos) ? +1 : -1;
1820 if (cur == required_delta) {
1841 inline size_t scan_leaf_fwd(
const size_t& search_start,
1842 const size_t& search_end,
1843 const int& required_delta)
const noexcept {
1844 if (search_start >= search_end) {
1847 const auto& aggregates_table = LUT8();
1848 const auto& forward_lookup = LUT8_FWD_POS();
1849 int current_excess = 0;
1850 size_t position = search_start;
1851 while (position + 8 <= search_end) {
1852 const uint8_t byte_value = get_byte(position);
1853 const auto& byte_aggregate = aggregates_table[byte_value];
1854 const int local_need = required_delta - current_excess;
1855 if (local_need >= byte_aggregate.min_prefix &&
1856 local_need <= byte_aggregate.max_prefix && local_need >= -8 &&
1858 const int8_t offset = forward_lookup[byte_value][local_need + 8];
1860 return position + size_t(offset);
1863 current_excess += byte_aggregate.excess_total;
1867 while (position < search_end) {
1868 current_excess +=
bit(position) ? 1 : -1;
1869 if (current_excess == required_delta) {
1886 inline size_t scan_leaf_bwd(
1887 const size_t& block_begin,
1888 const size_t& block_end,
1889 const int& required_delta,
1890 const bool& allow_right_boundary,
1891 const size_t& global_right_border,
1892 const int& prefix_at_boundary_max )
const noexcept {
1896 if (block_begin > block_end) {
1902 size_t boundary_max = block_end;
1903 if (!allow_right_boundary && boundary_max > block_begin) {
1908 if (block_begin >= boundary_max) {
1909 if ((block_begin < global_right_border || allow_right_boundary) &&
1910 required_delta == 0) {
1916 if (required_delta < -32768 || required_delta > 32767) {
1918 if ((block_begin < global_right_border || allow_right_boundary) &&
1919 required_delta == 0) {
1925#if defined(PIXIE_AVX2_SUPPORT)
1931 int prefix_end = prefix_at_boundary_max;
1932 if (prefix_end == kNoPrefixOverride) {
1933 const int len = int(boundary_max - block_begin);
1934 const int ones = int(rank1_in_block(block_begin, boundary_max));
1935 prefix_end = ones * 2 - len;
1938 const __m256i masks = bit_masks_16x();
1939 const __m256i vzero = _mm256_setzero_si256();
1940 const __m256i vallones = _mm256_cmpeq_epi16(vzero, vzero);
1941 const __m256i vminus1 = _mm256_set1_epi16(-1);
1942 const __m256i vtwo = _mm256_set1_epi16(2);
1943 const __m256i vtarget = _mm256_set1_epi16((int16_t)required_delta);
1945 size_t pos_end = boundary_max;
1946 int cur_end = prefix_end;
1949 while (pos_end >= block_begin + 16) {
1950 const size_t pos = pos_end - 16;
1951 const uint16_t bits16 = get_u16(pos);
1952 const __m256i vb = _mm256_set1_epi16((int16_t)bits16);
1953 const __m256i m = _mm256_and_si256(vb, masks);
1954 const __m256i is_zero = _mm256_cmpeq_epi16(m, vzero);
1955 const __m256i is_set = _mm256_andnot_si256(is_zero, vallones);
1956 const __m256i steps =
1957 _mm256_add_epi16(vminus1, _mm256_and_si256(is_set, vtwo));
1959 const __m256i pref_rel =
1960 prefix_sum_16x_i16(steps);
1961 const int16_t sum16 =
1962 last_prefix_16x_i16(pref_rel);
1963 const int cur_start =
1964 cur_end - (int)sum16;
1966 const __m256i base = _mm256_set1_epi16((int16_t)cur_start);
1967 const __m256i pref = _mm256_add_epi16(
1969 const __m256i cmp = _mm256_cmpeq_epi16(pref, vtarget);
1970 const uint32_t mask = (uint32_t)_mm256_movemask_epi8(cmp);
1972 const int bit_i = 31 - int(std::countl_zero(mask));
1973 const int lane = bit_i >> 1;
1974 const size_t boundary = pos + (size_t)lane + 1;
1975 if (boundary < global_right_border || allow_right_boundary) {
1981 cur_end = cur_start;
1985 while (pos_end > block_begin) {
1987 if (cur_end == required_delta) {
1988 if (pos_end < global_right_border || allow_right_boundary) {
1993 const size_t bit_pos = pos_end - 1;
1994 cur_end -=
bit(bit_pos) ? +1 : -1;
1998 size_t last_boundary =
npos;
2000 for (
size_t pos = block_begin; pos < boundary_max; ++pos) {
2001 cur +=
bit(pos) ? +1 : -1;
2002 if (cur == required_delta) {
2003 last_boundary = pos + 1;
2006 if (last_boundary !=
npos) {
2007 if (last_boundary < global_right_border || allow_right_boundary) {
2008 return last_boundary;
2015 if ((block_begin < global_right_border || allow_right_boundary) &&
2016 required_delta == 0) {
2025 inline uint8_t get_byte(
const size_t& position)
const noexcept {
2026 const size_t word_index = position >> 6;
2027 const size_t offset = position & 63;
2028 const std::uint64_t lower_word = bits[word_index] >> offset;
2030 return uint8_t(lower_word & 0xFFu);
2032 const std::uint64_t higher_word =
2033 (word_index + 1 < bits.size()) ? bits[word_index + 1] : 0;
2034 const std::uint64_t byte_value =
2035 (lower_word | (higher_word << (64 - offset))) & 0xFFu;
2036 return uint8_t(byte_value);
2047 size_t descend_first_max(
size_t node_index,
2049 size_t segment_base)
const noexcept {
2050 while (node_index < first_leaf_index) {
2051 const size_t left_child = node_index << 1, right_child = left_child | 1;
2052 const int left_max = node_max_prefix_excess[left_child];
2053 const int right_max =
2054 node_total_excess[left_child] + node_max_prefix_excess[right_child];
2055 if (left_max >= right_max && left_max == target_prefix) {
2056 node_index = left_child;
2057 }
else if (right_max == target_prefix) {
2058 segment_base += segment_size_bits[left_child];
2059 target_prefix -= node_total_excess[left_child];
2060 node_index = right_child;
2066 const size_t segment_begin = segment_base;
2067 const size_t segment_end =
2068 std::min(segment_base + segment_size_bits[node_index], num_bits);
2072 first_max_value_pos8(segment_begin,
2073 segment_end ? (segment_end - 1) : segment_begin,
2074 max_value, position);
2075 return (max_value == target_prefix ? position :
npos);
2081 size_t first_leaf_index = 1;
2087 static constexpr int kNoPrefixOverride = std::numeric_limits<int>::min();
2092 size_t block_of(
const size_t& position)
const noexcept {
2093 return position / block_bits;
2099 size_t leaf_index_of(
const size_t& block_start)
const noexcept {
2100 return first_leaf_index + block_of(block_start);
2107 size_t node_base(
size_t node_index)
const noexcept {
2108 if (node_index >= first_leaf_index) {
2109 return (node_index - first_leaf_index) * block_bits;
2113 for (; node_index > 1; node_index >>= 1) {
2114 if (node_index & 1) {
2115 base += segment_size_bits[node_index - 1];
2126 std::vector<size_t> cover_blocks(
const size_t& block_begin_index,
2127 const size_t& block_end_index)
const {
2128 size_t left_index = first_leaf_index + block_begin_index;
2129 size_t right_index = first_leaf_index + block_end_index;
2130 std::vector<size_t> left_nodes, right_nodes;
2131 while (left_index <= right_index) {
2132 if ((left_index & 1) == 1) {
2133 left_nodes.push_back(left_index++);
2135 if ((right_index & 1) == 0) {
2136 right_nodes.push_back(right_index--);
2141 std::reverse(right_nodes.begin(), right_nodes.end());
2142 left_nodes.insert(left_nodes.end(), right_nodes.begin(), right_nodes.end());
2150 size_t descend_fwd(
size_t node_index,
2152 size_t segment_base)
const noexcept {
2153 while (node_index < first_leaf_index) {
2154 const size_t left_child = node_index << 1;
2155 const size_t right_child = left_child | 1;
2156 if (node_min_prefix_excess[left_child] <= required_delta &&
2157 required_delta <= node_max_prefix_excess[left_child]) {
2158 node_index = left_child;
2160 required_delta -= node_total_excess[left_child];
2161 segment_base += segment_size_bits[left_child];
2162 node_index = right_child;
2165 const size_t seg_end =
2166 std::min(segment_base + segment_size_bits[node_index], num_bits);
2167#if defined(PIXIE_AVX2_SUPPORT)
2168 return scan_leaf_fwd_simd(segment_base, seg_end, required_delta,
nullptr);
2170 return scan_leaf_fwd(segment_base, seg_end, required_delta);
2183 size_t descend_bwd(
size_t node_index,
2184 const size_t& segment_base,
2185 const int& required_delta,
2186 const size_t& global_right_border,
2187 const bool& allow_right_boundary)
const noexcept {
2188 while (node_index < first_leaf_index) {
2189 const size_t left_child = node_index << 1;
2190 const size_t right_child = left_child | 1;
2191 const int required_in_right =
2192 required_delta - node_total_excess[left_child];
2195 if (node_min_prefix_excess[right_child] <= required_in_right &&
2196 required_in_right <= node_max_prefix_excess[right_child]) {
2197 const size_t result = descend_bwd(
2198 right_child, segment_base + segment_size_bits[left_child],
2199 required_in_right, global_right_border, allow_right_boundary);
2200 if (result !=
npos) {
2206 const size_t junction = segment_base + segment_size_bits[left_child];
2207 if (required_delta == node_total_excess[left_child] &&
2208 (junction < global_right_border || allow_right_boundary)) {
2213 if (node_min_prefix_excess[left_child] <= required_delta &&
2214 required_delta <= node_max_prefix_excess[left_child]) {
2215 node_index = left_child;
2221 if (required_delta == 0 &&
2222 (segment_base < global_right_border || allow_right_boundary)) {
2223 return segment_base;
2229 const size_t seg_end =
2230 std::min(segment_base + segment_size_bits[node_index], num_bits);
2231 const size_t block_end = std::min(global_right_border, seg_end);
2233 int prefix_override = kNoPrefixOverride;
2237 if (block_end == seg_end) {
2238 const int total = node_total_excess[node_index];
2239 if (!allow_right_boundary && block_end > segment_base) {
2240 prefix_override = total - (
bit(block_end - 1) ? +1 : -1);
2242 prefix_override = total;
2246 return scan_leaf_bwd(segment_base, block_end, required_delta,
2247 allow_right_boundary, global_right_border,
2255 size_t descend_first_min(
size_t node_index,
2257 size_t segment_base)
const noexcept {
2258 while (node_index < first_leaf_index) {
2259 const size_t left_child = node_index << 1, right_child = left_child | 1;
2260 const int left_min = node_min_prefix_excess[left_child];
2261 const int right_min =
2262 node_total_excess[left_child] + node_min_prefix_excess[right_child];
2263 if (left_min <= right_min && left_min == target_prefix) {
2264 node_index = left_child;
2265 }
else if (right_min == target_prefix) {
2266 segment_base += segment_size_bits[left_child];
2267 target_prefix -= node_total_excess[left_child];
2268 node_index = right_child;
2274 const size_t segment_begin = segment_base;
2275 const size_t segment_end =
2276 std::min(segment_base + segment_size_bits[node_index], num_bits);
2280 first_min_value_pos8(segment_begin,
2281 segment_end ? (segment_end - 1) : segment_begin,
2282 min_value, position);
2283 return (min_value == target_prefix ? position :
npos);
2290 size_t descend_qth_min(
size_t node_index,
2292 size_t target_min_rank,
2293 size_t segment_base)
const noexcept {
2294 while (node_index < first_leaf_index) {
2295 const size_t left_child = node_index << 1;
2296 const size_t right_child = left_child | 1;
2297 const int left_min = node_min_prefix_excess[left_child];
2298 const int right_min =
2299 node_total_excess[left_child] + node_min_prefix_excess[right_child];
2300 if (left_min == target_prefix) {
2301 if (node_min_count[left_child] >= target_min_rank) {
2302 node_index = left_child;
2305 target_min_rank -= node_min_count[left_child];
2307 if (right_min == target_prefix) {
2308 segment_base += segment_size_bits[left_child];
2309 target_prefix -= node_total_excess[left_child];
2310 node_index = right_child;
2315 return qth_min_in_block(
2317 std::min(segment_base + segment_size_bits[node_index], num_bits) - 1,
2325 size_t select1_in_block(
const size_t& block_begin,
2326 const size_t& block_end,
2327 size_t target_one_rank)
const noexcept {
2328 size_t left_word_index = block_begin >> 6;
2329 const size_t right_word_index = (block_end >> 6);
2330 const size_t left_offset = block_begin & 63;
2331 const std::uint64_t left_mask =
2332 (left_offset ? (~std::uint64_t(0) << left_offset) : ~std::uint64_t(0));
2333 if (left_word_index == right_word_index) {
2334 const std::uint64_t word =
2335 bits[left_word_index] & left_mask &
2336 ((block_end & 63) ? ((std::uint64_t(1) << (block_end & 63)) - 1)
2337 : ~std::uint64_t(0));
2338 return block_begin + select_in_word(word, target_one_rank);
2342 const std::uint64_t word = bits[left_word_index] & left_mask;
2343 const int count = std::popcount(word);
2344 if (target_one_rank <= (
size_t)count) {
2345 return block_begin + select_in_word(word, target_one_rank);
2347 target_one_rank -= count;
2351 while (left_word_index < right_word_index) {
2352 const std::uint64_t word = bits[left_word_index];
2353 const int count = std::popcount(word);
2354 if (target_one_rank <= (
size_t)count) {
2355 return (left_word_index << 6) + select_in_word(word, target_one_rank);
2357 target_one_rank -= count;
2361 const size_t right_offset = block_end & 63;
2363 const std::uint64_t word =
2364 bits[left_word_index] & ((std::uint64_t(1) << right_offset) - 1);
2365 const int count = std::popcount(word);
2366 if (target_one_rank <= (
size_t)count) {
2367 return (left_word_index << 6) + select_in_word(word, target_one_rank);
2377 size_t select0_in_block(
const size_t& block_begin,
2378 const size_t& block_end,
2379 size_t target_zero_rank)
const noexcept {
2380 if (block_end <= block_begin) {
2384 size_t left_word_index = block_begin >> 6;
2385 const size_t right_word_index = block_end >> 6;
2386 const size_t left_offset = block_begin & 63;
2388 if (left_word_index == right_word_index) {
2389 const std::uint64_t left_mask =
2390 (left_offset ? (~std::uint64_t(0) << left_offset)
2391 : ~std::uint64_t(0));
2392 const std::uint64_t right_mask =
2393 ((block_end & 63) ? ((std::uint64_t(1) << (block_end & 63)) - 1)
2394 : ~std::uint64_t(0));
2395 const std::uint64_t word =
2396 (~bits[left_word_index]) & left_mask & right_mask;
2397 const int offset = select_in_word(word, target_zero_rank);
2398 return (offset >= 0) ? (block_begin + (size_t)offset) :
npos;
2403 const std::uint64_t word =
2404 (~bits[left_word_index]) & (~std::uint64_t(0) << left_offset);
2405 const int count = std::popcount(word);
2406 if (target_zero_rank <= (
size_t)count) {
2407 const int offset = select_in_word(word, target_zero_rank);
2408 return (offset >= 0) ? (block_begin + (size_t)offset) :
npos;
2410 target_zero_rank -= count;
2415 while (left_word_index < right_word_index) {
2416 const std::uint64_t word = ~bits[left_word_index];
2417 const int count = std::popcount(word);
2418 if (target_zero_rank <= (
size_t)count) {
2419 const int offset = select_in_word(word, target_zero_rank);
2420 return (offset >= 0) ? ((left_word_index << 6) + (size_t)offset) :
npos;
2422 target_zero_rank -= count;
2427 const size_t right_offset = block_end & 63;
2429 const std::uint64_t word =
2430 (~bits[left_word_index]) & ((std::uint64_t(1) << right_offset) - 1);
2431 const int count = std::popcount(word);
2432 if (target_zero_rank <= (
size_t)count) {
2433 const int offset = select_in_word(word, target_zero_rank);
2434 return (offset >= 0) ? ((left_word_index << 6) + (size_t)offset) :
npos;
2444 static inline int select_in_word(std::uint64_t word,
2445 size_t target_rank)
noexcept {
2447 if (--target_rank == 0) {
2448 return std::countr_zero(word);
2458 static inline size_t ceil_div(
const size_t& numerator,
2459 const size_t& denominator)
noexcept {
2460 return (numerator + denominator - 1) / denominator;
2468 static inline size_t nodeslots_for(
const size_t& bit_count,
2469 const size_t& block_size_pow2)
noexcept {
2470 if (bit_count == 0) {
2473 size_t leaf_node_count = ceil_div(bit_count, block_size_pow2);
2474 return std::bit_ceil(std::max<size_t>(1, leaf_node_count)) +
2481 static inline float overhead_for(
const size_t& bit_count,
2482 const size_t& block_size_pow2)
noexcept {
2483 static constexpr size_t AUX_SLOT_BYTES =
2484 sizeof(uint32_t) +
sizeof(int32_t) +
sizeof(int32_t) +
sizeof(int32_t) +
2485 sizeof(uint32_t) +
sizeof(uint32_t) +
sizeof(uint8_t) +
sizeof(uint8_t);
2487 size_t bitvector_bytes = ceil_div(bit_count, 64) * 8;
2488 if (bitvector_bytes == 0) {
2491 size_t slot_count = nodeslots_for(bit_count, block_size_pow2);
2492 size_t aux_bytes = slot_count * AUX_SLOT_BYTES;
2493 return ((
float)aux_bytes) / ((float)bitvector_bytes);
2502 static inline size_t choose_block_bits_for_overhead(
2503 const size_t& bit_count,
2504 const float& overhead_cap)
noexcept {
2505 if (overhead_cap < 0.f) {
2509 const size_t max_block_bits = std::min<size_t>(bit_count, 16384);
2510 size_t candidate_block_bits = 64;
2511 while (candidate_block_bits < max_block_bits) {
2512 if (overhead_for(bit_count, candidate_block_bits) <= overhead_cap) {
2515 candidate_block_bits <<= 1;
2517 return candidate_block_bits;
2527 void build_from_words(std::span<const std::uint64_t> words,
2528 const size_t& bit_count,
2529 const size_t& leaf_block_bits = 0,
2530 const float& max_overhead = -1.0) {
2532 num_bits = bit_count;
2533 if (bits.size() * 64 < num_bits) {
2534 throw std::invalid_argument(
2535 "RmMTree bit_count exceeds the provided word span");
2537 build(leaf_block_bits, max_overhead);
2544 inline uint32_t ones_in_node(
const size_t& node_index)
const noexcept {
2545 return ((int64_t)segment_size_bits[node_index] +
2546 (int64_t)node_total_excess[node_index]) >>
2557 inline void scan_range_min_count8(
size_t range_begin,
2558 const size_t& range_end,
2559 int& current_excess,
2561 uint32_t& count)
const noexcept {
2563 min_value = INT_MAX;
2565 if (range_end < range_begin) {
2570 while (range_begin <= range_end && (range_begin & 7)) {
2571 current_excess +=
bit(range_begin) ? +1 : -1;
2572 if (current_excess < min_value) {
2573 min_value = current_excess;
2575 }
else if (current_excess == min_value) {
2581 const auto& aggregates_table = LUT8();
2582 while (range_begin + 7 <= range_end) {
2583 const auto& byte_aggregate = aggregates_table[get_byte(range_begin)];
2584 const int candidate = current_excess + byte_aggregate.min_prefix;
2585 if (candidate < min_value) {
2586 min_value = candidate;
2587 count = byte_aggregate.min_count;
2588 }
else if (candidate == min_value) {
2589 count += byte_aggregate.min_count;
2591 current_excess += byte_aggregate.excess_total;
2595 while (range_begin <= range_end) {
2596 current_excess +=
bit(range_begin) ? +1 : -1;
2597 if (current_excess < min_value) {
2598 min_value = current_excess;
2600 }
else if (current_excess == min_value) {
2605 if (min_value == INT_MAX) {
2606 min_value = count = 0;
2616 inline size_t cover_blocks_collect(
const size_t& block_begin_index,
2617 const size_t& block_end_index,
2618 size_t (&out_nodes)[64])
const noexcept {
2619 if (leaf_count == 0 || block_begin_index > block_end_index) {
2622 size_t left_index = first_leaf_index + block_begin_index;
2623 size_t right_index = first_leaf_index + block_end_index;
2624 size_t left_nodes[32];
2625 size_t right_nodes[32];
2626 size_t left_count = 0, right_count = 0;
2627 while (left_index <= right_index) {
2628 if (left_index & 1) {
2629 left_nodes[left_count++] = left_index++;
2631 if ((right_index & 1) == 0) {
2632 right_nodes[right_count++] = right_index--;
2637 size_t out_count = 0;
2638 for (
size_t i = 0; i < left_count; ++i) {
2639 out_nodes[out_count++] = left_nodes[i];
2641 while (right_count > 0) {
2642 out_nodes[out_count++] = right_nodes[--right_count];
2653 inline size_t qth_min_in_block(
const size_t& range_begin,
2654 const size_t& range_end,
2655 size_t target_min_rank)
const noexcept {
2656 if (range_end < range_begin || target_min_rank == 0) {
2660 const auto& aggregates_table = LUT8();
2662 int current_excess = 0, min_value = INT_MAX;
2663 size_t position = range_begin;
2665 while (position <= range_end && (position & 7)) {
2666 current_excess +=
bit(position) ? +1 : -1;
2667 if (current_excess < min_value) {
2668 min_value = current_excess;
2672 while (position + 7 <= range_end) {
2673 const auto& byte_aggregate = aggregates_table[get_byte(position)];
2675 std::min(min_value, current_excess + byte_aggregate.min_prefix);
2676 current_excess += byte_aggregate.excess_total;
2679 while (position <= range_end) {
2680 current_excess +=
bit(position) ? +1 : -1;
2681 if (current_excess < min_value) {
2682 min_value = current_excess;
2688 position = range_begin;
2691 while (position <= range_end && (position & 7)) {
2692 current_excess +=
bit(position) ? +1 : -1;
2693 if (current_excess == min_value) {
2694 if (--target_min_rank == 0) {
2702 while (position + 7 <= range_end) {
2703 const uint8_t byte_value = get_byte(position);
2704 const auto& byte_aggregate = aggregates_table[byte_value];
2705 const int candidate = current_excess + byte_aggregate.min_prefix;
2706 if (candidate == min_value) {
2708 for (
int k = 0; k < 8; ++k) {
2709 prefix_sum += ((byte_value >> k) & 1u) ? +1 : -1;
2710 if (prefix_sum == byte_aggregate.min_prefix) {
2711 if (--target_min_rank == 0) {
2712 return position + k;
2717 current_excess += byte_aggregate.excess_total;
2722 while (position <= range_end) {
2723 current_excess +=
bit(position) ? +1 : -1;
2724 if (current_excess == min_value) {
2725 if (--target_min_rank == 0) {
2745 inline size_t leaf_fwd_bp_simd(
const size_t& leaf_index,
2746 const size_t& leaf_block_begin,
2747 const size_t& start_position,
2749 int& leaf_delta)
const noexcept {
2750 const size_t leaf_length = segment_size_bits[first_leaf_index + leaf_index];
2751 const size_t leaf_end = std::min(num_bits, leaf_block_begin + leaf_length);
2752 if (start_position >= leaf_end) {
2756#if defined(PIXIE_AVX2_SUPPORT)
2761 const size_t tail_len = leaf_end - start_position;
2763 if (delta >= -8 && delta <= 8 && tail_len <= 256) {
2764 res = scan_leaf_fwd_lut8_fast(start_position, leaf_end, delta, &total);
2766 res = scan_leaf_fwd_simd(start_position, leaf_end, delta, &total);
2774 const size_t res = scan_leaf_fwd(start_position, leaf_end, delta);
2778 const int len = int(leaf_end - start_position);
2779 const int ones = int(rank1_in_block(start_position, leaf_end));
2780 leaf_delta = ones * 2 - len;
2793 inline size_t leaf_bwd_bp_simd(
const size_t& leaf_index,
2794 const size_t& leaf_block_begin,
2795 const size_t& start_position,
2797 int& leaf_delta)
const noexcept {
2798 const size_t leaf_length = segment_size_bits[first_leaf_index + leaf_index];
2799 const size_t leaf_end = std::min(num_bits, leaf_block_begin + leaf_length);
2800 if (start_position < leaf_block_begin || start_position > leaf_end) {
2807 const int len = int(start_position - leaf_block_begin);
2808 const int ones = int(rank1_in_block(leaf_block_begin, start_position));
2809 leaf_delta = ones * 2 - len;
2813 if (start_position == leaf_block_begin) {
2816 const int target_prefix = leaf_delta + delta;
2817 return scan_leaf_bwd(
2825 (start_position > leaf_block_begin
2826 ? (leaf_delta - (
bit(start_position - 1) ? +1 : -1))
2836 inline void first_min_value_pos8(
size_t range_begin,
2837 const size_t& range_end,
2839 size_t& first_position)
const noexcept {
2840 const auto& aggregates_table = LUT8();
2841 int current_excess = 0;
2842 int min_value = INT_MAX;
2843 first_position =
npos;
2846 while (range_begin <= range_end && (range_begin & 7)) {
2847 current_excess +=
bit(range_begin) ? +1 : -1;
2848 if (current_excess < min_value) {
2849 min_value = current_excess;
2850 first_position = range_begin;
2856 while (range_begin + 7 <= range_end) {
2857 const auto& byte_aggregate = aggregates_table[get_byte(range_begin)];
2858 const int candidate = current_excess + byte_aggregate.min_prefix;
2859 if (candidate < min_value) {
2860 min_value = candidate;
2861 first_position = range_begin + byte_aggregate.pos_first_min;
2863 current_excess += byte_aggregate.excess_total;
2868 while (range_begin <= range_end) {
2869 current_excess +=
bit(range_begin) ? +1 : -1;
2870 if (current_excess < min_value) {
2871 min_value = current_excess;
2872 first_position = range_begin;
2877 min_value_out = (min_value == INT_MAX ? 0 : min_value);
2886 inline void first_max_value_pos8(
size_t range_begin,
2887 const size_t& range_end,
2889 size_t& first_position)
const noexcept {
2890 const auto& aggregates_table = LUT8();
2891 int current_excess = 0;
2892 int max_value = INT_MIN;
2893 first_position =
npos;
2895 while (range_begin <= range_end && (range_begin & 7)) {
2896 current_excess +=
bit(range_begin) ? +1 : -1;
2897 if (current_excess > max_value) {
2898 max_value = current_excess;
2899 first_position = range_begin;
2904 while (range_begin + 7 <= range_end) {
2905 const auto& byte_aggregate = aggregates_table[get_byte(range_begin)];
2906 const int candidate = current_excess + byte_aggregate.max_prefix;
2907 if (candidate > max_value) {
2908 max_value = candidate;
2909 first_position = range_begin + byte_aggregate.pos_first_max;
2911 current_excess += byte_aggregate.excess_total;
2915 while (range_begin <= range_end) {
2916 current_excess +=
bit(range_begin) ? +1 : -1;
2917 if (current_excess > max_value) {
2918 max_value = current_excess;
2919 first_position = range_begin;
2924 max_value_out = (max_value == INT_MIN ? 0 : max_value);
2933 void build(
const size_t& leaf_block_bits,
const float& max_overhead) {
2936 const size_t clamp_by_overhead =
2937 (max_overhead >= 0.0
2938 ? choose_block_bits_for_overhead(num_bits, max_overhead)
2943 if (leaf_block_bits == 0) {
2945 std::max(clamp_by_overhead,
2946 std::bit_ceil<size_t>(
2947 (num_bits <= 1) ? 1 : std::bit_width(num_bits - 1)));
2950 std::max(clamp_by_overhead,
2951 std::bit_ceil(std::max<size_t>(1, leaf_block_bits)));
2956 built_overhead = overhead_for(num_bits, block_bits);
2959 leaf_count = ceil_div(num_bits, block_bits);
2960 first_leaf_index = std::bit_ceil(std::max<size_t>(1, leaf_count));
2961 const size_t tree_size = first_leaf_index + leaf_count - 1;
2962 segment_size_bits.assign(tree_size + 1, 0);
2963 node_total_excess.assign(tree_size + 1, 0);
2964 node_min_prefix_excess.assign(tree_size + 1, 0);
2965 node_max_prefix_excess.assign(tree_size + 1, 0);
2966 node_min_count.assign(tree_size + 1, 0);
2967 node_pattern10_count.assign(tree_size + 1, 0);
2968 node_first_bit.assign(tree_size + 1, 0);
2969 node_last_bit.assign(tree_size + 1, 0);
2972 for (
size_t leaf_block_index = 0; leaf_block_index < leaf_count;
2973 ++leaf_block_index) {
2974 const size_t leaf_node_index = first_leaf_index + leaf_block_index;
2975 const size_t segment_begin = leaf_block_index * block_bits;
2976 const size_t segment_end = std::min(num_bits, segment_begin + block_bits);
2977 segment_size_bits[leaf_node_index] = segment_end - segment_begin;
2979 if (segment_begin < segment_end) {
2980 node_first_bit[leaf_node_index] =
bit(segment_begin);
2983 const auto& aggregates_table = LUT8();
2985 int current_excess = 0, min_value = INT_MAX, max_value = INT_MIN;
2986 uint32_t min_count = 0;
2987 uint32_t pattern10_count = 0;
2989 uint8_t previous_bit = 0;
2991 size_t position = segment_begin;
2994 while (position + 8 <= segment_end) {
2995 const uint8_t byte_value = get_byte(position);
2996 const auto& byte_aggregate = aggregates_table[byte_value];
2999 pattern10_count += byte_aggregate.pattern10_count;
3002 if (previous_bit == 1 && byte_aggregate.first_bit == 0) {
3007 const int candidate_min = current_excess + byte_aggregate.min_prefix;
3008 if (candidate_min < min_value) {
3009 min_value = candidate_min;
3010 min_count = byte_aggregate.min_count;
3011 }
else if (candidate_min == min_value) {
3012 min_count += byte_aggregate.min_count;
3016 std::max(max_value, current_excess + byte_aggregate.max_prefix);
3017 current_excess += byte_aggregate.excess_total;
3018 previous_bit = byte_aggregate.last_bit;
3023 while (position < segment_end) {
3024 const uint8_t bit_value =
bit(position);
3025 if (previous_bit == 1 && bit_value == 0) {
3028 const int step = bit_value ? +1 : -1;
3029 current_excess += step;
3030 if (current_excess < min_value) {
3031 min_value = current_excess;
3033 }
else if (current_excess == min_value) {
3036 if (current_excess > max_value) {
3037 max_value = current_excess;
3040 previous_bit = bit_value;
3044 if (segment_begin < segment_end) {
3045 node_last_bit[leaf_node_index] = previous_bit;
3048 node_total_excess[leaf_node_index] = current_excess;
3049 node_min_prefix_excess[leaf_node_index] =
3050 (segment_size_bits[leaf_node_index] == 0 ? 0 : min_value);
3051 node_max_prefix_excess[leaf_node_index] =
3052 (segment_size_bits[leaf_node_index] == 0 ? 0 : max_value);
3053 node_min_count[leaf_node_index] = min_count;
3054 node_pattern10_count[leaf_node_index] = (uint32_t)pattern10_count;
3057 for (
size_t node_index = first_leaf_index - 1; node_index >= 1;
3059 const size_t left_child = node_index << 1;
3060 const size_t right_child = left_child | 1;
3061 const bool has_left =
3062 (left_child <= tree_size) && segment_size_bits[left_child];
3063 const bool has_right =
3064 (right_child <= tree_size) && segment_size_bits[right_child];
3065 if (!has_left && !has_right) {
3066 segment_size_bits[node_index] = 0;
3069 if (has_left && !has_right) {
3070 segment_size_bits[node_index] = segment_size_bits[left_child];
3071 node_total_excess[node_index] = node_total_excess[left_child];
3072 node_min_prefix_excess[node_index] = node_min_prefix_excess[left_child];
3073 node_max_prefix_excess[node_index] = node_max_prefix_excess[left_child];
3074 node_min_count[node_index] = node_min_count[left_child];
3075 node_pattern10_count[node_index] = node_pattern10_count[left_child];
3076 node_first_bit[node_index] = node_first_bit[left_child];
3077 node_last_bit[node_index] = node_last_bit[left_child];
3078 }
else if (!has_left && has_right) {
3079 segment_size_bits[node_index] = segment_size_bits[right_child];
3080 node_total_excess[node_index] = node_total_excess[right_child];
3081 node_min_prefix_excess[node_index] =
3082 node_min_prefix_excess[right_child];
3083 node_max_prefix_excess[node_index] =
3084 node_max_prefix_excess[right_child];
3085 node_min_count[node_index] = node_min_count[right_child];
3086 node_pattern10_count[node_index] = node_pattern10_count[right_child];
3087 node_first_bit[node_index] = node_first_bit[right_child];
3088 node_last_bit[node_index] = node_last_bit[right_child];
3090 segment_size_bits[node_index] =
3091 segment_size_bits[left_child] + segment_size_bits[right_child];
3092 node_total_excess[node_index] =
3093 node_total_excess[left_child] + node_total_excess[right_child];
3094 const int right_min_candidate =
3095 node_total_excess[left_child] + node_min_prefix_excess[right_child];
3096 const int right_max_candidate =
3097 node_total_excess[left_child] + node_max_prefix_excess[right_child];
3098 node_min_prefix_excess[node_index] =
3099 std::min(node_min_prefix_excess[left_child], right_min_candidate);
3100 node_max_prefix_excess[node_index] =
3101 std::max(node_max_prefix_excess[left_child], right_max_candidate);
3102 node_min_count[node_index] =
3103 (node_min_prefix_excess[left_child] ==
3104 node_min_prefix_excess[node_index]
3105 ? node_min_count[left_child]
3107 (right_min_candidate == node_min_prefix_excess[node_index]
3108 ? node_min_count[right_child]
3110 node_pattern10_count[node_index] = node_pattern10_count[left_child] +
3111 node_pattern10_count[right_child] +
3112 ((node_last_bit[left_child] == 1 &&
3113 node_first_bit[right_child] == 0)
3116 node_first_bit[node_index] = node_first_bit[left_child];
3117 node_last_bit[node_index] = node_last_bit[right_child];
3119 if (node_index == 1) {