37 namespace cola_detail {
struct query_access; }
38 namespace profile_detail {
39 inline std::uint64_t
add(std::uint64_t a, std::uint64_t b) {
40 if (b > std::numeric_limits<std::uint64_t>::max() - a)
41 error_detail::raise<std::overflow_error>(
"profile addition");
44 inline std::uint64_t
multiply(std::uint64_t a, std::uint64_t b) {
45 if (b && a > std::numeric_limits<std::uint64_t>::max() / b)
46 error_detail::raise<std::overflow_error>(
"profile multiplication");
50 inline std::uint64_t
byte_count(std::uint64_t bits)
noexcept {
51 return (bits + 7) >> 3;
58 bit_view(std::span<std::byte const> bytes, std::uint64_t bits, std::uint64_t
offset = 0)
62 error_detail::raise<std::invalid_argument>(
"bit view exceeds storage");
64 std::uint64_t
size() const noexcept {
return size_; }
68 bool at(std::uint64_t i)
const {
69 if (i >=
size_) error_detail::raise<std::out_of_range>(
"bit position");
71 return (std::to_integer<unsigned>(
bytes_[
bit >> 3]) >> (7 - (
bit & 7))) & 1;
74 if (first >
size_ || count >
size_ - first) error_detail::raise<std::out_of_range>(
"bit subview");
76 result.offset_ += first;
88 namespace profile_detail {
89 inline std::uint64_t
low_mask(
unsigned width)
noexcept {
90 return width == 64 ? ~std::uint64_t{0} : (std::uint64_t{1} << width) - 1;
93 inline std::uint64_t
load_bits(
bit_view data, std::uint64_t first,
unsigned width)
noexcept {
95 auto offset = data.offset() + first;
96 auto source = data.storage().data() + (offset >> 3);
97 unsigned shift = unsigned(offset & 7), bytes = (shift + width + 7) >> 3;
102 if (bytes == 9) value |= std::uint64_t(std::to_integer<unsigned>(source[8])) >> (8 - shift);
104 return width == 64 ? value : value >> (64 - width);
106 std::uint64_t value = 0;
107 for (
unsigned i = 0; i != bytes; ++i) value = (value << 8) | std::to_integer<unsigned>(source[i]);
108 return (value >> ((bytes << 3) - shift - width)) &
low_mask(width);
111 inline void store_bits(std::byte * target, std::uint64_t at, std::uint64_t value,
unsigned width)
noexcept {
115 auto take = std::min(width, 8u -
unsigned(at & 7));
116 auto shift = 8u - unsigned(at & 7) - take;
117 auto mask = unsigned(
low_mask(take)) << shift;
118 auto bits = unsigned((value >> (width - take)) &
low_mask(take)) << shift;
119 target[at >> 3] = std::byte((std::to_integer<unsigned>(target[at >> 3]) & ~mask) | bits);
120 at += take; width -= take;
124 auto count = source.size();
126 if (((first | source.offset() | count) & 7) == 0) {
127 std::memmove(target + (first >> 3), source.storage().data() + (source.offset() >> 3),
128 static_cast<std::size_t
>(count >> 3));
132 auto destination =
reinterpret_cast<std::uintptr_t
>(target + (first >> 3));
133 auto origin =
reinterpret_cast<std::uintptr_t
>(source.storage().data() + (source.offset() >> 3));
134 auto source_bytes =
byte_count((source.offset() & 7) + count);
135 bool backwards = (destination > origin || (destination == origin && (first & 7) > (source.offset() & 7))) &&
136 destination - origin < source_bytes;
139 auto width = unsigned(std::min<std::uint64_t>(count, 64));
145 std::uint64_t at = 0;
147 auto width = unsigned(std::min<std::uint64_t>(count, 8 - (first & 7)));
150 if (((source.offset() + at) & 7) == 0) {
151 auto bytes = (count - at) >> 3;
152 if (bytes) std::memmove(target + ((first + at) >> 3),
153 source.storage().data() + ((source.offset() + at) >> 3),
static_cast<std::size_t
>(bytes));
156 for (; count - at >= 64; at += 64)
159 while (at != count) {
160 auto width = unsigned(std::min<std::uint64_t>(count - at, 8));
171 if (
bit_size > std::numeric_limits<std::uint64_t>::max() - 7 ||
173 error_detail::raise<std::invalid_argument>(
"packed bit-string length");
175 (std::to_integer<unsigned>(
bytes.back()) & ((1u << (8 - (
bit_size & 7))) - 1)))
176 error_detail::raise<std::invalid_argument>(
"nonzero bit-string padding");
192 return from_bytes(std::as_bytes(std::span(source.data(), source.size())));
195 if (source.size() > std::numeric_limits<std::uint64_t>::max() - 7)
196 error_detail::raise<std::length_error>(
"profile bit string too large");
200 for (std::size_t i = 0; i != source.size(); ++i) {
201 if (source[i] !=
'0' && source[i] !=
'1') error_detail::raise<std::invalid_argument>(
"expected binary digits");
202 if (source[i] ==
'1') result.
bytes[i >> 3] |=
static_cast<std::byte
>(1u << (7 - (i & 7)));
213 template <simd::architecture Arch = simd::scalar>
216 auto count = std::min(a.size(), b.size());
220 auto x = (std::to_integer<unsigned>(a.storage()[a.offset() >> 3]) >> (7 - (a.offset() & 7))) & 1;
221 auto y = (std::to_integer<unsigned>(b.storage()[b.offset() >> 3]) >> (7 - (b.offset() & 7))) & 1;
222 if (x != y)
return {0, x ? 1 : -1};
224 std::uint64_t at = 0;
225 if (count >= 8 && (a.offset() & 7) == 0 && (b.offset() & 7) == 0) {
226 at = key_detail::common_bytes<Arch>(a.storage().data() + (a.offset() >> 3),
227 b.storage().data() + (b.offset() >> 3),
static_cast<std::size_t
>(count >> 3)) << 3;
228 if (count - at >= 8) {
230 return {at + std::countl_zero(x ^ y) - 56, x < y ? -1 : 1};
233 while (at != count) {
234 auto width = unsigned(std::min<std::uint64_t>(count - at, 64));
236 if (
auto different = x ^ y)
237 return {at + std::countl_zero(different) - (64 - width), x < y ? -1 : 1};
240 return {count, a.size() < b.size() ? -1 : a.size() > b.size() ? 1 : 0};
242 template <simd::architecture Arch = simd::scalar>
245 if ((a.
size() & (P::bits_per_unit - 1)) || (b.
size() & (P::bits_per_unit - 1)))
246 error_detail::raise<std::invalid_argument>(
"key length does not match profile unit");
247 return compare_common_bits<typename P::architecture>(a, b).common_bits >> P::unit_shift;
254 if (key.size() & (P::bits_per_unit - 1)) error_detail::raise<std::invalid_argument>(
"anchor unit mismatch");
255 return {key, (key.size() >> P::unit_shift)};
260 if ((query.
size() & (P::bits_per_unit - 1)) || (key.prefix.size() & (P::bits_per_unit - 1)))
261 error_detail::raise<std::invalid_argument>(
"query unit mismatch");
262 auto query_units = (query.
size() >> P::unit_shift);
264 if (key.prefix.size() < needed) error_detail::raise<std::invalid_argument>(
"query prefix is incomplete");
265 auto order = compare_bits<typename P::architecture>(key.prefix.prefix(needed), query.
prefix(needed));
266 if (order)
return order;
267 return key.full_units < query_units ? -1 : key.full_units > query_units ? 1 : 0;
330 if (query.
size() & (P::bits_per_unit - 1)) error_detail::raise<std::invalid_argument>(
"query unit mismatch");
332 order_ = query.
size() ? -1 : 0;
338 if (query.
bit_size & (P::bits_per_unit - 1)) error_detail::raise<std::invalid_argument>(
"query unit mismatch");
339 auto order = query.
bit_size ? -1 : 0;
343 if (!query_) error_detail::raise<std::logic_error>(
"comparison context has no query");
344 return query_->view();
346 std::uint64_t
common_bits() const noexcept {
return common_bits_; }
350 return length_known_ ? std::optional(full_units_) : std::nullopt;
352 int order() const noexcept {
return order_; }
357 std::uint64_t
advance_parts(std::uint64_t retained_bits, std::uint64_t full_bits,
358 std::span<bit_view const> literal) {
359 if ((full_bits & (P::bits_per_unit - 1)) || retained_bits > full_bits ||
360 (length_known_ && retained_bits > (full_units_ << P::unit_shift)))
361 error_detail::raise<std::invalid_argument>(
"invalid inherited comparison frame");
362 std::uint64_t total = retained_bits;
364 if (total != full_bits) error_detail::raise<std::invalid_argument>(
"incomplete comparison literal");
365 std::uint64_t compared = 0;
366 if (common_bits_ >= retained_bits) {
367 auto at = retained_bits;
369 for (
auto part : literal) {
370 auto available = query().size() - at;
371 auto other = query().subview(at, available);
372 auto result = compare_common_bits<typename P::architecture>(part, other.prefix(std::min(part.size(), available)));
373 compared += result.common_bits + (result.common_bits < std::min(part.size(), available));
374 at += result.common_bits;
375 if (result.order) { order_ = result.order;
break; }
378 if (!order_) order_ = full_bits < query().size() ? -1 : full_bits > query().size() ? 1 : 0;
380 full_units_ = full_bits >> P::unit_shift;
381 length_known_ =
true;
386 if (key.size() & (P::bits_per_unit - 1)) error_detail::raise<std::invalid_argument>(
"boundary key unit mismatch");
388 auto comparison = compare_common_bits<typename P::architecture>(key, query());
389 result.common_bits_ = comparison.common_bits;
390 result.full_units_ = (key.size() >> P::unit_shift);
391 result.length_known_ =
true;
392 result.order_ = comparison.order;
402 if (query.
bit_size & (P::bits_per_unit - 1)) error_detail::raise<std::invalid_argument>(
"query unit mismatch");
403 auto alias = std::shared_ptr<bit_string const>(std::shared_ptr<bit_string const>{}, &query);
408 : query_(std::move(query)), order_(order) {}
413 std::shared_ptr<bit_string const>
query_;
414 std::uint64_t common_bits_ = 0;
415 std::uint64_t full_units_ = 0;
417 bool length_known_ =
true;
420 if (length_known_ && record.
retained > full_units_)
421 error_detail::raise<std::invalid_argument>(
"comparison anchor is too short");
423 std::uint64_t compared = 0;
424 if (common_bits_ >= retained_bits) {
425 auto suffix_query = query().subview(retained_bits, query().size() - retained_bits);
426 auto comparison = compare_common_bits<typename P::architecture>(record.
suffix, suffix_query);
428 order_ = comparison.order;
429 compared = comparison.common_bits +
430 (comparison.common_bits < std::min(record.
suffix.
size(), suffix_query.size()));
433 length_known_ =
true;
438 if (order_ > 0 || (length_known_ &&
440 error_detail::raise<std::invalid_argument>(
"invalid cut predecessor comparison");
442 result.common_bits_ = std::min(lcp_bits, common_bits_);
445 result.length_known_ = result.common_bits_ == query().size();
446 result.full_units_ = result.length_known_ ? query().size() >> P::unit_shift : 0;
447 result.order_ = result.length_known_ ? 0 : -1;
453 std::uint64_t skipped_headers = 0;
454 std::uint64_t visited_headers = 0;
455 std::uint64_t compared_bits = 0;
459 std::uint64_t ordinal = 0;
464 namespace profile_detail {
466 if (bits > std::numeric_limits<std::uint64_t>::max() - 7)
467 error_detail::raise<std::length_error>(
"profile bit string too large");
469 if (bytes > value.
bytes.max_size()) error_detail::raise<std::length_error>(
"profile bit string too large");
470 value.
bytes.resize(
static_cast<std::size_t
>(bytes));
472 if (bits & 7) value.
bytes.back() &=
static_cast<std::byte
>(0xffu << (8 - (bits & 7)));
476 error_detail::raise<std::out_of_range>(
"profile copy exceeds destination");
482 auto begin =
reinterpret_cast<std::uintptr_t
>(target.
bytes.data());
483 auto input =
reinterpret_cast<std::uintptr_t
>(source.
storage().data());
484 if (source.
size() && input >= begin && input - begin < target.
bytes.size()) {
485 auto saved = bit_string::copy(source);
486 resize(target, add(at, saved.bit_size));
495 resize(target, add(at, 1));
496 if (
bit) target.
bytes[at >> 3] |=
static_cast<std::byte
>(1u << (7 - (at & 7)));
499 if ((target.
bit_size & 7)) error_detail::raise<std::logic_error>(
"unaligned byte profile writer");
500 target.
bytes.push_back(
static_cast<std::byte
>(value));
506 error_detail::raise<std::out_of_range>(
"profile fixed field exceeds destination");
511 if (width > 64 || at > data.
size() || width > data.
size() - at)
512 error_detail::raise<std::invalid_argument>(
"truncated backspace remainder");
518 char const * truncated,
char const * overflow) {
519 std::uint64_t zeros = 0;
521 if (at >= data.
size()) error_detail::raise<std::invalid_argument>(truncated);
522 auto width = unsigned(std::min<std::uint64_t>(data.
size() - at, 64));
524 auto leading = unsigned(std::countl_zero(word)) - (64 - width);
525 if (leading > limit - zeros) {
526 at += limit - zeros + 1;
527 error_detail::raise<std::invalid_argument>(overflow);
529 zeros += leading; at += leading;
530 if (leading != width) { ++at;
return zeros; }
534 if constexpr (P::unit == profile_unit::byte) {
535 while (value >= 128) {
append_byte(target,
unsigned(value & 127) | 128); value >>= 7; }
538 auto maximum = value == std::numeric_limits<std::uint64_t>::max();
539 auto width = maximum ? 65u : unsigned(std::bit_width(value + 1));
541 resize(target, add(at, 2 * width - 1));
543 else { at += width - 1;
put_fixed(target, at, value + 1, width); }
548 if constexpr (P::unit == profile_unit::byte) {
549 std::uint64_t value = 0;
550 for (
unsigned shift = 0; shift <= 63; shift += 7) {
551 if (offset >= (data.
size() >> 3)) error_detail::raise<std::invalid_argument>(
"truncated profile count");
552 auto part = std::to_integer<unsigned>(data.
storage()[offset++]);
553 if (shift == 63 && part > 1) error_detail::raise<std::invalid_argument>(
"overflowing profile count");
554 value |= std::uint64_t(part & 127) << shift;
556 if (shift && !(part & 127)) error_detail::raise<std::invalid_argument>(
"noncanonical profile count");
560 error_detail::raise<std::invalid_argument>(
"overflowing profile count");
565 if (offset <= data.
size() && data.
size() - offset >= 16) {
567 auto zeros = unsigned(std::countl_zero(word) - 48);
569 offset += 2 * zeros + 1;
570 return (word >> (15 - 2 * zeros)) - 1;
574 "truncated exponential-Golomb count",
"overflowing exponential-Golomb count"));
575 if (zeros > data.
size() - offset) {
576 offset = data.
size();
577 error_detail::raise<std::invalid_argument>(
"truncated exponential-Golomb count");
579 auto suffix =
read_fixed(data, offset, zeros);
581 if (suffix) error_detail::raise<std::invalid_argument>(
"overflowing exponential-Golomb count");
582 return std::numeric_limits<std::uint64_t>::max();
584 return ((std::uint64_t{1} << zeros) - 1) + suffix;
588 constexpr auto width = std::bit_width(P::backspace_parameter - 1);
589 if constexpr (width == 64)
return std::uint64_t{0} - P::backspace_parameter;
590 else return (std::uint64_t{1} << width) - P::backspace_parameter;
596 static_assert(P::unit == profile_unit::bit);
597 if constexpr (P::backspace_code == bit_backspace_code::exponential_golomb) {
598 auto quotient = value >> P::backspace_parameter;
599 auto prefix = quotient == std::numeric_limits<std::uint64_t>::max()
600 ? 129 : 2 * std::bit_width(quotient + 1) - 1;
601 return prefix + P::backspace_parameter;
603 constexpr auto modulus = P::backspace_parameter;
604 constexpr auto width = std::bit_width(modulus - 1);
605 auto remainder_width = width - (value % modulus < golomb_cutoff<P>());
606 return add(add(value / modulus, 1), remainder_width);
610 if constexpr (P::unit == profile_unit::byte) write_count<P>(target, value);
615 resize(target, add(at, backspace_bits<P>(value)));
616 if constexpr (P::backspace_code == bit_backspace_code::exponential_golomb) {
617 auto quotient = value >> P::backspace_parameter;
618 if (quotient == std::numeric_limits<std::uint64_t>::max()) {
623 auto code = quotient + 1;
624 auto width = unsigned(std::bit_width(code));
628 put_fixed(target, at, value,
unsigned(P::backspace_parameter));
630 constexpr auto modulus = P::backspace_parameter;
631 constexpr auto width = unsigned(std::bit_width(modulus - 1));
632 constexpr auto cutoff = golomb_cutoff<P>();
633 at += value / modulus;
635 auto remainder = value % modulus;
636 if (remainder < cutoff)
put_fixed(target, at, remainder, width - 1);
637 else put_fixed(target, at, remainder + cutoff, width);
642 if constexpr (P::unit == profile_unit::byte)
return read_count<P>(data, offset);
643 else if constexpr (P::backspace_code == bit_backspace_code::exponential_golomb) {
644 auto quotient = read_count<P>(data, offset);
645 if (quotient > (std::numeric_limits<std::uint64_t>::max() >> P::backspace_parameter))
646 error_detail::raise<std::invalid_argument>(
"overflowing exponential-Golomb backspace");
647 auto remainder =
read_fixed(data, offset,
unsigned(P::backspace_parameter));
648 return (quotient << P::backspace_parameter) | remainder;
650 constexpr auto modulus = P::backspace_parameter;
651 constexpr auto width = unsigned(std::bit_width(modulus - 1));
652 constexpr auto cutoff = golomb_cutoff<P>();
653 constexpr auto limit = std::numeric_limits<std::uint64_t>::max() / modulus;
655 "truncated backspace remainder",
"overflowing Golomb quotient");
656 std::uint64_t remainder = 0;
657 if constexpr (width != 0) {
658 remainder =
read_fixed(data, offset, width - 1);
659 if (remainder >= cutoff) remainder = ((remainder << 1) |
read_fixed(data, offset, 1)) - cutoff;
661 auto base = quotient * modulus;
662 if (remainder > std::numeric_limits<std::uint64_t>::max() - base)
663 error_detail::raise<std::invalid_argument>(
"overflowing Golomb backspace");
664 return base + remainder;
670 result.
count_code = P::unit == profile_unit::byte ? profile_count_code::varint : profile_count_code::exp_golomb_zero;
678 result.
common_value_width = Role == stream_role::borrowed ? 0 : P::value_width.value_or(0);
683 template <
class P, stream_role Role = stream_role::native>
struct profile_cursor;
684 template <
class P, stream_role Role = stream_role::native>
struct profile_encoded_cursor;
685 template <
class P>
struct profile_borrowed_writer;
686 template <
class P,
class Native,
class Output>
struct index_builder;
687 namespace profile_detail {
template <
class P>
struct index_output;
template <
class P>
struct borrowed_sections; }
688 namespace cola_detail {
template <
class P,
class Native,
class Main>
struct index_output; }
689 template <
class P>
struct profile_native_writer;
690 namespace profile_detail {
template <
class P>
struct native_output; }
695 template <
class P, stream_role Role = stream_role::native>
struct profile_view {
710 return {bytes, offsets, metadata,
shape_only{}};
717 validate_offset_metadata();
718 auto bits = data_.size();
719 if ((bits & 7) && (std::to_integer<unsigned>(bytes_.back()) & ((1u << (8 - (bits & 7))) - 1)))
720 error_detail::raise<std::invalid_argument>(
"nonzero profile padding");
721 if (block_offset(0) != 0 || block_offset(block_count()) != metadata_.extent)
722 error_detail::raise<std::invalid_argument>(
"profile offset units or extent mismatch");
729 auto stride = profile_detail::multiply(metadata_.record_count, metadata_.common_value_width.value_or(0));
730 if (stride > metadata_.extent || offsets_.universe() != metadata_.extent - stride)
731 error_detail::raise<std::invalid_argument>(
"profile offset universe or fixed stride mismatch");
735 return metadata_.record_count / P::codec_block_size +
736 (metadata_.record_count % P::codec_block_size != 0);
742 auto blocks = block_count();
743 if (block > blocks) error_detail::raise<std::out_of_range>(
"profile block ordinal");
744 auto ordinal = block == blocks ? metadata_.record_count : block * P::codec_block_size;
745 return offsets_.template select<typename P::architecture>(block) + ordinal * metadata_.common_value_width.value_or(0);
748 std::uint64_t
size() const noexcept {
return metadata_.record_count; }
749 std::span<std::byte const>
bytes() const noexcept {
return bytes_; }
759 if (ordinal >= size()) error_detail::raise<std::out_of_range>(
"profile record ordinal");
760 auto [at, retained] = locate(ordinal,
nullptr);
761 return parse_payload(at, retained);
769 if (ordinal > size()) error_detail::raise<std::out_of_range>(
"profile predecessor ordinal");
770 if (!ordinal)
return 0;
771 if (ordinal == size())
return metadata_.terminal_key_units;
772 auto [at, retained] = locate(ordinal - 1, work);
773 auto record = parse_payload(at, retained);
774 if (work) ++work->skipped_headers;
775 return record.key_units;
783 std::uint64_t * predecessor =
nullptr)
const {
784 if (first > last || last > size() || last - first > P::group_size)
785 error_detail::raise<std::out_of_range>(
"profile comparison window exceeds cascade group");
787 if (predecessor) *predecessor = predecessor_units(first, work);
790 auto [at, retained] = locate(first, work, predecessor);
791 auto record = parse_payload(at, retained);
792 for (
auto i = first; i != last; ++i) {
793 auto compared = context.
advance(record);
794 if (work) { ++work->visited_headers; work->compared_bits += compared; }
796 if (i + 1 != last) record = next_record(record, i + 1);
804 template <
class F>
void visit_window(std::uint64_t first, std::uint64_t last,
806 if (first > last || last > size() || last - first > P::group_size)
807 error_detail::raise<std::out_of_range>(
"profile window exceeds the policy group size");
808 if (first == last)
return;
809 if ((anchor.
prefix.
size() & (P::bits_per_unit - 1)) ||
811 error_detail::raise<std::invalid_argument>(
"profile anchor units");
812 auto prefix_bits = profile_detail::multiply(
813 std::min(prefix_limit, (anchor.
prefix.
size() >> P::unit_shift)), P::bits_per_unit);
814 auto scratch = bit_string::copy(anchor.
prefix.
prefix(prefix_bits));
816 auto record = encoded_at(first);
817 for (
auto i = first; i != last; ++i) {
818 decode_into(record, prefix_limit, scratch, context);
820 if (i + 1 != last) record = next_record(record, i + 1);
824 template <
class F>
void visit_all(F && callback)
const {
827 std::uint64_t context = 0;
828 auto record = encoded_at(0);
829 for (std::uint64_t i = 0; i != size(); ++i) {
830 decode_into(record, std::numeric_limits<std::uint64_t>::max(), scratch, context);
832 if (i + 1 != size()) record = next_record(record, i + 1);
834 if (record.next_offset != metadata_.extent) error_detail::raise<std::invalid_argument>(
"trailing profile data");
835 if (record.key_units != metadata_.terminal_key_units)
836 error_detail::raise<std::invalid_argument>(
"profile terminal length mismatch");
843 std::uint64_t prefix_limit = std::numeric_limits<std::uint64_t>::max())
const {
844 auto record = encoded_at(ordinal);
847 result.
value = bit_string::copy(record.value);
848 auto need = std::min(record.key_units, prefix_limit);
849 profile_detail::resize(result.
prefix, profile_detail::multiply(need, P::bits_per_unit));
851 if (record.key_units < need) error_detail::raise<std::invalid_argument>(
"profile predecessor prefix is too short");
852 if (record.retained < need) {
853 auto copy = profile_detail::multiply(need - record.retained, P::bits_per_unit);
854 profile_detail::copy_into(result.
prefix, profile_detail::multiply(record.retained, P::bits_per_unit),
855 record.suffix.prefix(copy));
856 need = record.retained;
859 if (!ordinal) error_detail::raise<std::invalid_argument>(
"nonliteral first profile key");
860 auto retained = record.retained;
861 record = encoded_at(--ordinal);
862 if (record.key_units < retained) error_detail::raise<std::invalid_argument>(
"profile predecessor prefix is too short");
871 : bytes_(bytes), offsets_(offsets), metadata_(metadata) {
872 auto expected = profile_detail::initial_metadata<P, Role>();
876 metadata.
count_code != expected.count_code || metadata.
bit_order != profile_bit_order::msb_first ||
879 error_detail::raise<std::invalid_argument>(
"profile metadata does not match reader policy");
881 error_detail::raise<std::invalid_argument>(
"variable profile policy width must be zero");
882 if constexpr (Role == stream_role::borrowed) {
884 error_detail::raise<std::invalid_argument>(
"borrowed profile must have empty values");
887 error_detail::raise<std::invalid_argument>(
"fixed value width metadata mismatch");
890 error_detail::raise<std::invalid_argument>(
"nonempty data for empty profile");
891 auto bits = profile_detail::multiply(metadata.
extent, P::bits_per_unit);
892 auto blocks = block_count();
893 if (bits > std::numeric_limits<std::uint64_t>::max() - 7 ||
894 bytes.size() != profile_detail::byte_count(bits) ||
895 blocks == std::numeric_limits<std::uint64_t>::max() || offsets.
size() != blocks + 1)
896 error_detail::raise<std::invalid_argument>(
"profile section length mismatch");
897 data_ = {bytes, bits};
908 std::uint64_t * predecessor =
nullptr)
const {
909 auto group = ordinal / P::codec_block_size;
910 auto at = block_offset(group);
911 auto retained = read_absolute(at);
912 if (!group && retained) error_detail::raise<std::invalid_argument>(
"first profile key is not literal");
913 std::uint64_t previous = 0;
914 for (
auto i = group * P::codec_block_size; i < ordinal; ++i) {
915 auto [key_units, next_offset] = parse_payload<false>(at, retained);
916 previous = key_units;
918 auto backspace = profile_detail::read_backspace<P>(data_, at);
919 if (backspace > previous) error_detail::raise<std::invalid_argument>(
"profile backspace exceeds predecessor");
920 retained = previous - backspace;
924 if (ordinal && ordinal % P::codec_block_size == 0)
925 previous = predecessor_units(ordinal, work);
926 if (retained > previous)
927 error_detail::raise<std::invalid_argument>(
"profile retained prefix exceeds predecessor");
928 *predecessor = previous;
930 return {at, retained};
935 auto retained = profile_detail::read_count<P>(data_, at);
938 if (retained > start)
939 error_detail::raise<std::invalid_argument>(
"profile retained prefix exceeds physical offset");
944 auto retained = read_absolute(at);
945 return parse_payload(at, retained);
949 auto backspace = profile_detail::read_backspace<P>(data_, at);
950 if (backspace > previous) error_detail::raise<std::invalid_argument>(
"profile backspace exceeds predecessor");
951 return parse_payload(at, previous - backspace);
954 template <
bool Views = true>
956 auto suffix = profile_detail::read_count<P>(data_, at);
958 if (at > metadata_.
extent || suffix > metadata_.
extent - at || value > metadata_.
extent - at - suffix)
959 error_detail::raise<std::invalid_argument>(
"truncated profile payload");
963 auto key_units = retained + suffix;
964 if constexpr (Views) {
965 auto suffix_bits = profile_detail::multiply(suffix, P::bits_per_unit);
966 auto value_bits = profile_detail::multiply(value, P::bits_per_unit);
967 auto key_data = data_.
subview(profile_detail::multiply(at, P::bits_per_unit), suffix_bits);
969 auto value_data = data_.
subview(profile_detail::multiply(at, P::bits_per_unit), value_bits);
974 return std::pair<std::uint64_t, std::uint64_t>{key_units, at + suffix + value};
978 template <
class Offset>
981 if (ordinal % P::codec_block_size == 0) {
982 if (offset(ordinal / P::codec_block_size) != at)
983 error_detail::raise<std::invalid_argument>(
"profile group offset mismatch");
984 auto next = parse_absolute(at);
986 error_detail::raise<std::invalid_argument>(
"profile retained prefix exceeds predecessor");
989 return parse_relative(at, previous.
key_units);
993 return next_record(previous, ordinal, [&](std::uint64_t block) {
return block_offset(block); });
997 bit_string & scratch, std::uint64_t & context) {
998 if (record.
retained > context) error_detail::raise<std::invalid_argument>(
"profile anchor is too short");
999 auto keep = std::min(record.
retained, limit);
1000 auto keep_bits = profile_detail::multiply(keep, P::bits_per_unit);
1001 if (keep_bits > scratch.
bit_size) error_detail::raise<std::invalid_argument>(
"profile anchor prefix is incomplete");
1002 profile_detail::resize(scratch, keep_bits);
1003 auto full = std::min(record.
key_units, limit);
1004 profile_detail::append(scratch, record.
suffix.
prefix(profile_detail::multiply(full - keep, P::bits_per_unit)));
1020 if (!done()) { record_ = view_.encoded_at(0); (void)offsets_.next(); }
1023 bool done() const noexcept {
return ordinal_ == view_.size(); }
1024 std::uint64_t
ordinal() const noexcept {
return ordinal_; }
1026 if (done()) error_detail::raise<std::out_of_range>(
"encoded profile cursor at end");
1032 if (done()) error_detail::raise<std::out_of_range>(
"encoded profile cursor at end");
1033 if (ordinal_ + 1 == view_.size()) {
1034 if (record_.next_offset != view_.metadata_.extent)
1035 error_detail::raise<std::invalid_argument>(
"trailing profile data");
1036 if (record_.key_units != view_.metadata_.terminal_key_units)
1037 error_detail::raise<std::invalid_argument>(
"profile terminal length mismatch");
1039 std::optional<elias_fano_cursor> offsets;
1040 auto next = view_.next_record(record_, ordinal_ + 1, [&](std::uint64_t block) {
1041 offsets.emplace(offsets_);
1042 return offsets->next() + block * P::codec_block_size * view_.metadata_.common_value_width.value_or(0);
1045 if (offsets) offsets_ = *offsets;
1054 std::uint64_t ordinal_ = 0;
1057 template <
class P, stream_role Role>
1076 : view_(view), offsets_(view.group_offsets(),
1077 ordinal < view.size() ? ordinal / P::codec_block_size : view.group_offsets().size(),
1078 std::type_identity<typename P::architecture>{}), ordinal_(ordinal) {
1079 if (ordinal > view.size()) error_detail::raise<std::out_of_range>(
"profile cursor ordinal");
1081 record_ = view_.encoded_at(ordinal);
1082 (void)offsets_.next();
1083 auto retained = record_.retained << P::unit_shift;
1084 if (retained > query.size()) error_detail::raise<std::invalid_argument>(
"profile cursor missing query prefix");
1085 scratch_ = bit_string::copy(query.subview(0, retained));
1086 context_ = record_.retained;
1091 bool done() const noexcept {
return ordinal_ == view_.size(); }
1092 std::uint64_t
ordinal() const noexcept {
return ordinal_; }
1094 if (done()) error_detail::raise<std::out_of_range>(
"profile cursor at end");
1095 return {ordinal_, {scratch_.view(), context_}, record_.value};
1098 std::uint64_t retained_bits()
const {
1099 if (done()) error_detail::raise<std::out_of_range>(
"profile cursor at end");
1100 return record_.retained << P::unit_shift;
1110 advance_impl<true>(&result);
1111 return done() ? std::nullopt : std::optional<bit_comparison>{result};
1116 if (done()) error_detail::raise<std::out_of_range>(
"profile cursor at end");
1117 if (ordinal_ + 1 == view_.size()) {
1118 if (record_.next_offset != view_.metadata_.extent)
1119 error_detail::raise<std::invalid_argument>(
"trailing profile data");
1120 if (record_.key_units != view_.metadata_.terminal_key_units)
1121 error_detail::raise<std::invalid_argument>(
"profile terminal length mismatch");
1127 std::optional<elias_fano_cursor> offsets;
1128 auto next = view_.next_record(record_, ordinal_ + 1, [&](std::uint64_t block) {
1129 offsets.emplace(offsets_);
1130 return offsets->next() + block * P::codec_block_size * view_.metadata_.common_value_width.value_or(0);
1132 if constexpr (Compare) {
1133 auto retained_bits = profile_detail::multiply(next.retained, P::bits_per_unit);
1134 auto previous = scratch_.view();
1135 if (retained_bits == previous.size() || next.suffix.empty()) {
1136 *comparison = {retained_bits, retained_bits != previous.size() ? 1 : next.suffix.empty() ? 0 : -1};
1138 auto before = profile_detail::load_bits(previous, retained_bits, P::bits_per_unit);
1139 auto after = profile_detail::load_bits(next.suffix, 0, P::bits_per_unit);
1140 if (before != after) {
1141 auto common = unsigned(std::countl_zero(before ^ after)) - (64 - P::bits_per_unit);
1142 *comparison = {retained_bits + common, before < after ? -1 : 1};
1144 auto suffix = compare_common_bits<typename P::architecture>(
1145 previous.subview(retained_bits, previous.size() - retained_bits), next.suffix);
1146 *comparison = {retained_bits + suffix.
common_bits, suffix.order};
1152 if (offsets) offsets_ = *offsets;
1160 std::uint64_t context_ = 0;
1162 std::uint64_t ordinal_ = 0;
1165 template <
class P, stream_role Role>
1168 template <
class P, stream_role Role = stream_role::native>
struct profile_array {
1174 std::span<std::uint64_t const> prefix_ceilings = {}, std::uint64_t restart_factor = 0) {
1175 if (!prefix_ceilings.empty() && prefix_ceilings.size() != records.size())
1176 error_detail::raise<std::invalid_argument>(
"one profile prefix ceiling is required per record");
1177 if (restart_factor && restart_factor < 3) error_detail::raise<std::invalid_argument>(
"LPFC factor must be at least three");
1179 std::optional<std::uint64_t> common;
1180 if constexpr (Role == stream_role::borrowed) common = 0;
1181 else if constexpr (P::fixed_width) common = P::value_width;
1182 else if (records.empty()) common = 0;
1183 else common = (records.front().value.view().size() >> P::unit_shift);
1184 for (
auto const & record : records) {
1185 auto key_bits = record.key.
view().
size();
1186 auto value_bits = record.value.view().size();
1187 if ((key_bits & (P::bits_per_unit - 1)) || (value_bits & (P::bits_per_unit - 1)))
1188 error_detail::raise<std::invalid_argument>(
"record length does not match profile unit");
1189 auto width = (value_bits >> P::unit_shift);
1190 if constexpr (Role == stream_role::borrowed) {
1191 if (width) error_detail::raise<std::invalid_argument>(
"borrowed profile cannot carry values");
1192 }
else if constexpr (P::fixed_width) {
1193 if (width != *P::value_width) error_detail::raise<std::invalid_argument>(
"value does not match fixed policy width");
1195 if (common && *common != width) common.reset();
1202 std::uint64_t previous_units = 0;
1203 std::uint64_t anchor_offset = 0;
1204 std::vector<std::uint64_t> offsets;
1205 for (std::size_t i = 0; i != records.size(); ++i) {
1206 auto key = records[i].key.
view();
1208 auto comparison = compare_common_bits<typename P::architecture>(previous, key);
1209 if (i && comparison.order > 0) error_detail::raise<std::invalid_argument>(
"profile keys must be sorted");
1210 auto position = (data.bit_size >> P::unit_shift);
1211 if (i % P::codec_block_size == 0)
1212 offsets.push_back(position - profile_detail::multiply(i, common.value_or(0)));
1213 auto key_units = (
key.size() >> P::unit_shift);
1214 auto retained = (comparison.common_bits >> P::unit_shift);
1215 if (records[i].retained_limit_bits)
1216 retained = std::min(retained, *records[i].retained_limit_bits >> P::unit_shift);
1217 if (!prefix_ceilings.empty()) retained = std::min(retained, prefix_ceilings[i]);
1218 auto start = (data.bit_size >> P::unit_shift);
1219 if (retained && restart_factor && key_units <= std::numeric_limits<std::uint64_t>::max() / restart_factor &&
1220 start - anchor_offset > restart_factor * key_units) retained = 0;
1221 if (!retained) anchor_offset = start;
1222 if (i % P::codec_block_size == 0) profile_detail::write_count<P>(data, retained);
1223 else profile_detail::write_backspace<P>(data, previous_units - retained);
1224 profile_detail::write_count<P>(data, key_units - retained);
1225 if (!common) profile_detail::write_count<P>(data, (
value.size() >> P::unit_shift));
1226 profile_detail::append(data,
key.subview(profile_detail::multiply(retained, P::bits_per_unit),
1227 key.size() - profile_detail::multiply(retained, P::bits_per_unit)));
1228 profile_detail::append(data, value);
1230 previous_units = key_units;
1234 offsets.push_back(result.
metadata_.
extent - profile_detail::multiply(records.size(), common.value_or(0)));
1235 result.
offsets_ = elias_fano::build<typename P::architecture>(offsets);
1236 result.
bytes_ = std::move(data.bytes);
1240 std::uint64_t
size() const noexcept {
return metadata_.record_count; }
1241 std::span<std::byte const>
bytes() const noexcept {
return bytes_; }
1254 friend struct profile_detail::native_output<P>;
1255 friend struct profile_detail::borrowed_sections<P>;
1256 std::vector<std::
byte> bytes_;
1261 : bytes_(std::move(bytes)), offsets_(std::move(offsets)), metadata_(metadata) {}
1264 namespace profile_detail {
1270 return {std::move(bytes), std::move(offsets), metadata};
1284 std::uint64_t
size() const noexcept {
return count_; }
1287 void append(
bit_view key, std::uint64_t prefix_ceiling = std::numeric_limits<std::uint64_t>::max()) {
1288 if (finished_) error_detail::raise<std::logic_error>(
"borrowed profile writer is finished");
1289 if (key.size() & (P::bits_per_unit - 1)) error_detail::raise<std::invalid_argument>(
"key length does not match profile unit");
1290 auto previous = previous_.view();
1291 auto comparison = compare_common_bits<typename P::architecture>(previous, key);
1292 if (count_ && comparison.order > 0) error_detail::raise<std::invalid_argument>(
"profile keys must be sorted");
1293 append_known(key, comparison.common_bits, prefix_ceiling);
1299 if (finished_) error_detail::raise<std::logic_error>(
"borrowed profile writer is finished");
1301 auto extent = (data_.bit_size >> P::unit_shift);
1302 offsets_.push_back(extent);
1304 result.
offsets_ = elias_fano::build<typename P::architecture>(offsets_);
1306 offsets_.pop_back();
1312 result.
bytes_ = std::move(data_.bytes);
1315 offsets_ = std::vector<std::uint64_t>{};
1328 std::uint64_t prefix_ceiling = std::numeric_limits<std::uint64_t>::max()) {
1329 auto next_count = profile_detail::add(count_, 1);
1330 auto retained = std::min((exact_common_bits >> P::unit_shift), prefix_ceiling);
1331 auto previous_units = (previous_.bit_size >> P::unit_shift);
1332 auto key_units = (key.size() >> P::unit_shift);
1333 auto saved_bits = data_.bit_size;
1334 auto saved_offsets = offsets_.size();
1337 auto next_bytes = profile_detail::byte_count(key.size());
1338 if (next_bytes > previous_.bytes.max_size()) error_detail::raise<std::length_error>(
"profile bit string too large");
1339 previous_.bytes.reserve(
static_cast<std::size_t
>(next_bytes));
1341 if (count_ % P::codec_block_size == 0) {
1342 offsets_.push_back((data_.bit_size >> P::unit_shift));
1343 profile_detail::write_count<P>(data_, retained);
1344 }
else profile_detail::write_backspace<P>(data_, previous_units - retained);
1345 profile_detail::write_count<P>(data_, key_units - retained);
1346 auto retained_bits = profile_detail::multiply(retained, P::bits_per_unit);
1347 profile_detail::append(data_, key.subview(retained_bits, key.size() - retained_bits));
1349 profile_detail::resize(data_, saved_bits);
1350 offsets_.resize(saved_offsets);
1355 auto common_bits = exact_common_bits & ~std::uint64_t(P::bits_per_unit - 1);
1356 profile_detail::resize(previous_, key.size());
1357 profile_detail::copy_into(previous_, common_bits,
1358 key.subview(common_bits, key.size() - common_bits));
1359 count_ = next_count;
1365 std::uint64_t count_ = 0;
1366 bool finished_ =
false;
Encodes and selects arbitrary nondecreasing integer sequences.
Outlines exceptional check failures while preserving their types and messages.
Provides bounded byte comparison shared by the key codecs.
std::uint64_t load_big(void const *source) noexcept
Definition key_detail.h:57
void store_big(void *target, std::uint64_t value) noexcept
Definition key_detail.h:69
void write_count(bit_string &target, std::uint64_t value)
Definition profile.h:533
void put_fixed(bit_string &target, std::uint64_t &at, std::uint64_t value, unsigned width)
Definition profile.h:504
profile_metadata initial_metadata()
Definition profile.h:667
void append_bit(bit_string &target, bool bit)
Definition profile.h:493
std::uint64_t add(std::uint64_t a, std::uint64_t b)
Definition profile.h:39
std::uint64_t multiply(std::uint64_t a, std::uint64_t b)
Definition profile.h:44
std::uint64_t byte_count(std::uint64_t bits) noexcept
Definition profile.h:50
std::uint64_t read_count(bit_view data, std::uint64_t &offset)
Definition profile.h:547
std::uint64_t read_backspace(bit_view data, std::uint64_t &offset)
Definition profile.h:641
std::uint64_t read_zero_run(bit_view data, std::uint64_t &at, std::uint64_t limit, char const *truncated, char const *overflow)
Definition profile.h:517
constexpr std::uint64_t golomb_cutoff()
Definition profile.h:587
std::uint64_t backspace_bits(std::uint64_t value)
Definition profile.h:595
void write_backspace(bit_string &target, std::uint64_t value)
Definition profile.h:609
void resize(bit_string &value, std::uint64_t bits)
Definition profile.h:465
void copy_into(bit_string &target, std::uint64_t first, bit_view source)
Definition profile.h:474
void append_byte(bit_string &target, unsigned value)
Definition profile.h:498
std::uint64_t low_mask(unsigned width) noexcept
Definition profile.h:89
void copy_bits(std::byte *target, std::uint64_t first, bit_view source) noexcept
Definition profile.h:123
void store_bits(std::byte *target, std::uint64_t at, std::uint64_t value, unsigned width) noexcept
Definition profile.h:111
std::uint64_t load_bits(bit_view data, std::uint64_t first, unsigned width) noexcept
Definition profile.h:93
void append(bit_string &target, bit_view source)
Definition profile.h:480
std::uint64_t read_fixed(bit_view data, std::uint64_t &at, unsigned width)
Definition profile.h:510
bit_string value(arrow_t< S > const &value)
Definition typed_world.h:99
bit_string key(key_t< S > const &value)
Definition typed_world.h:89
Definition active_engine.h:18
stream_role
Definition policy.h:25
profile_count_code
Definition profile.h:270
int compare_profile_prefix(profile_anchor< P > key, bit_view query)
Definition profile.h:259
bit_backspace_code
Definition policy.h:27
bit_comparison compare_common_bits(bit_view a, bit_view b)
Definition profile.h:215
std::uint64_t common_prefix_units(bit_view a, bit_view b)
Definition profile.h:244
int compare_bits(bit_view a, bit_view b)
Definition profile.h:243
profile_bit_order
Definition profile.h:271
profile_unit
Definition registry.h:29
Declares Everett's policy support.
std::uint64_t common_bits
Definition profile.h:210
int order
Definition profile.h:211
static bit_string from_bytes(std::span< std::byte const > source)
Definition profile.h:188
bit_view view() const &&=delete
static bit_string from_bits(std::string_view source)
Definition profile.h:194
static bit_string from_bytes(std::string_view source)
Definition profile.h:191
void validate() const
Definition profile.h:170
std::vector< std::byte > bytes
Definition profile.h:167
bool operator==(bit_string const &) const =default
bit_view view() const &
Definition profile.h:178
static bit_string copy(bit_view source)
Definition profile.h:181
std::uint64_t bit_size
Definition profile.h:168
std::span< std::byte const > storage() const noexcept
Definition profile.h:67
bool at(std::uint64_t i) const
Definition profile.h:68
std::uint64_t size() const noexcept
Definition profile.h:64
std::uint64_t size_
Definition profile.h:85
std::uint64_t offset_
Definition profile.h:84
std::uint64_t offset() const noexcept
Definition profile.h:66
bool empty() const noexcept
Definition profile.h:65
bit_view subview(std::uint64_t first, std::uint64_t count) const
Definition profile.h:73
bit_view prefix(std::uint64_t count) const
Definition profile.h:80
bit_view(std::span< std::byte const > bytes, std::uint64_t bits, std::uint64_t offset=0)
Definition profile.h:58
std::span< std::byte const > bytes_
Definition profile.h:83
Definition cola_index.h:398
Definition cola_query.h:85
Definition cola_index.h:114
Definition elias_fano.h:332
Definition elias_fano.h:212
std::uint64_t size() const noexcept
Definition elias_fano.h:256
Definition elias_fano.h:397
Definition index_builder.h:47
std::uint64_t full_units
Definition profile.h:252
static profile_anchor complete(bit_view key)
Definition profile.h:253
bit_view prefix
Definition profile.h:251
Definition profile.h:1168
profile_metadata metadata_
Definition profile.h:1259
elias_fano offsets_
Definition profile.h:1258
elias_fano const & group_offsets() const noexcept
Definition profile.h:1243
std::uint64_t size() const noexcept
Definition profile.h:1240
profile_metadata const & metadata() const noexcept
Definition profile.h:1242
static profile_array build(std::span< profile_record const > records, std::span< std::uint64_t const > prefix_ceilings={}, std::uint64_t restart_factor=0)
Definition profile.h:1173
profile_view< P, Role > view() const &
Definition profile.h:1246
profile_array(std::vector< std::byte > bytes, elias_fano offsets, profile_metadata metadata)
Definition profile.h:1260
P policy_type
Definition profile.h:1170
std::span< std::byte const > bytes() const noexcept
Definition profile.h:1241
std::vector< std::byte > bytes_
Definition profile.h:1256
Definition profile_blob.h:73
Definition profile_blob.h:187
Definition profile.h:1280
bit_string previous_
Definition profile.h:1363
P policy_type
Definition profile.h:1281
void append(bit_view key, std::uint64_t prefix_ceiling=std::numeric_limits< std::uint64_t >::max())
Definition profile.h:1287
profile_array< P, stream_role::borrowed > finish()
Definition profile.h:1298
bit_string data_
Definition profile.h:1362
std::uint64_t size() const noexcept
Definition profile.h:1284
std::vector< std::uint64_t > offsets_
Definition profile.h:1364
void append_known(bit_view key, std::uint64_t exact_common_bits, std::uint64_t prefix_ceiling=std::numeric_limits< std::uint64_t >::max())
Definition profile.h:1327
bool finished() const noexcept
Definition profile.h:1285
bit_view value
Definition profile.h:461
profile_query_context< P > const & comparison
Definition profile.h:460
std::uint64_t skipped_headers
Definition profile.h:453
Definition profile.h:1066
bool done() const noexcept
Definition profile.h:1091
profile_item< P > peek() const &
Definition profile.h:1093
profile_view< P, Role > view_
Definition profile.h:1157
std::uint64_t ordinal() const noexcept
Definition profile.h:1092
std::optional< bit_comparison > advance_comparison()
Definition profile.h:1108
profile_cursor(profile_view< P, Role > view, std::uint64_t ordinal, bit_view query)
Definition profile.h:1075
profile_encoded_record record_
Definition profile.h:1161
profile_cursor(profile_view< P, Role > view)
Definition profile.h:1070
P policy_type
Definition profile.h:1067
void advance()
Definition profile.h:1103
elias_fano_cursor offsets_
Definition profile.h:1158
bit_string scratch_
Definition profile.h:1159
void advance_impl(bit_comparison *comparison)
Definition profile.h:1115
profile_item< P > peek() const &&=delete
bit_string prefix
Definition profile.h:318
profile_anchor< P > anchor() const &
Definition profile.h:321
std::uint64_t full_units
Definition profile.h:319
profile_anchor< P > anchor() const &&=delete
bit_string value
Definition profile.h:320
Definition profile.h:1267
static profile_array< P, stream_role::borrowed > adopt(std::vector< std::byte > bytes, elias_fano offsets, profile_metadata metadata)
Definition profile.h:1268
Definition profile_index.h:86
Definition profile.h:1015
profile_encoded_record record_
Definition profile.h:1053
profile_view< P, Role > view_
Definition profile.h:1051
bool done() const noexcept
Definition profile.h:1023
elias_fano_cursor offsets_
Definition profile.h:1052
profile_encoded_cursor(profile_view< P, Role > view)
Definition profile.h:1019
P policy_type
Definition profile.h:1016
profile_encoded_record const & peek() const &
Definition profile.h:1025
profile_encoded_record const & peek() const &&=delete
std::uint64_t ordinal() const noexcept
Definition profile.h:1024
bit_view value
Definition profile.h:313
std::uint64_t value_units
Definition profile.h:311
std::uint64_t next_offset
Definition profile.h:314
bit_view suffix
Definition profile.h:312
std::uint64_t retained
Definition profile.h:309
std::uint64_t key_units
Definition profile.h:310
std::uint64_t ordinal
Definition profile.h:303
profile_anchor< P > key
Definition profile.h:304
bit_view value
Definition profile.h:305
Definition native_writer.h:158
int order() const noexcept
Definition profile.h:352
std::uint64_t advance(profile_encoded_record const &record)
Definition profile.h:419
profile_query_context(std::shared_ptr< bit_string const > query, int order)
Definition profile.h:407
std::uint64_t advance_parts(std::uint64_t retained_bits, std::uint64_t full_bits, std::span< bit_view const > literal)
Definition profile.h:357
static profile_query_context from_borrowed(bit_string const &query)
Definition profile.h:400
std::optional< std::uint64_t > full_units() const noexcept
Definition profile.h:349
profile_query_context(bit_view query)
Definition profile.h:329
bit_view query() const
Definition profile.h:342
profile_query_context predecessor(std::uint64_t lcp_bits) const
Definition profile.h:437
std::uint64_t common_bits() const noexcept
Definition profile.h:346
static profile_query_context from_owned(bit_string query)
Definition profile.h:336
std::shared_ptr< bit_string const > query_
Definition profile.h:413
profile_query_context with_key(bit_view key) const
Definition profile.h:385
std::optional< std::uint64_t > retained_limit_bits
Definition profile.h:299
bit_string key
Definition profile.h:295
bit_string value
Definition profile.h:296
std::span< std::byte const > bytes() const noexcept
Definition profile.h:749
profile_encoded_record next_record(profile_encoded_record const &previous, std::uint64_t ordinal, Offset &&offset) const
Definition profile.h:979
elias_fano_view group_offsets() const noexcept
Definition profile.h:751
profile_decoded_record< P > reconstruct_at(std::uint64_t ordinal, std::uint64_t prefix_limit=std::numeric_limits< std::uint64_t >::max()) const
Definition profile.h:842
std::uint64_t block_offset(std::uint64_t block) const
Definition profile.h:741
void validate_contents() const
Definition profile.h:716
elias_fano_view offsets_
Definition profile.h:903
profile_encoded_cursor< P, Role > encoded_cursor() const
Definition profile.h:1058
profile_encoded_record next_record(profile_encoded_record const &previous, std::uint64_t ordinal) const
Definition profile.h:992
std::uint64_t block_count() const noexcept
Definition profile.h:734
std::pair< std::uint64_t, std::uint64_t > locate(std::uint64_t ordinal, profile_comparison_work *work, std::uint64_t *predecessor=nullptr) const
Definition profile.h:907
void compare_window(std::uint64_t first, std::uint64_t last, profile_query_context< P > context, F &&callback, profile_comparison_work *work=nullptr, std::uint64_t *predecessor=nullptr) const
Definition profile.h:781
static profile_view from_sections(std::span< std::byte const > bytes, elias_fano_view offsets, profile_metadata metadata)
Definition profile.h:708
profile_metadata metadata_
Definition profile.h:904
void validate_offset_metadata() const
Definition profile.h:728
profile_encoded_record parse_relative(std::uint64_t at, std::uint64_t previous) const
Definition profile.h:948
std::uint64_t size() const noexcept
Definition profile.h:748
static void decode_into(profile_encoded_record const &record, std::uint64_t limit, bit_string &scratch, std::uint64_t &context)
Definition profile.h:996
std::span< std::byte const > bytes_
Definition profile.h:902
profile_encoded_record parse_absolute(std::uint64_t at) const
Definition profile.h:943
void visit_all(F &&callback) const
Definition profile.h:824
profile_cursor< P, Role > cursor() const
Definition profile.h:1166
std::uint64_t read_absolute(std::uint64_t &at) const
Definition profile.h:933
void visit_window(std::uint64_t first, std::uint64_t last, profile_anchor< P > anchor, std::uint64_t prefix_limit, F &&callback) const
Definition profile.h:804
bit_view data_
Definition profile.h:905
std::uint64_t predecessor_units(std::uint64_t ordinal, profile_comparison_work *work=nullptr) const
Definition profile.h:767
profile_encoded_record encoded_at(std::uint64_t ordinal) const
Definition profile.h:758
P policy_type
Definition profile.h:696
auto parse_payload(std::uint64_t at, std::uint64_t retained) const
Definition profile.h:955
profile_metadata const & metadata() const noexcept
Definition profile.h:750
profile_view(std::span< std::byte const > bytes, elias_fano_view offsets, profile_metadata metadata)
Definition profile.h:699