60class BlockedMonotoneSamples {
62 using metadata_storage_type = MetadataStorage;
64 BlockedMonotoneSamples() =
default;
66 explicit BlockedMonotoneSamples(std::span<const std::uint64_t> values)
69 if (!std::is_sorted(values.begin(), values.end())) {
70 throw std::invalid_argument(
"Monotone samples must be non-decreasing");
72 const std::size_t groups =
73 values.empty() ? 0 : 1 + (values.size() - 1) / 32;
75 std::size_t words = 0;
76 for (std::size_t group = 0; group < groups; ++group) {
77 const std::size_t begin = group * 32;
78 const std::size_t count =
79 std::min<std::size_t>(32, values.size() - begin);
80 const unsigned width =
81 std::bit_width((values[begin + count - 1] - values[begin]) >> 5);
82 offsets_[group] = words | (std::uint64_t{width} << 58);
83 const std::size_t record_words = 2 + (count * width + 63) / 64;
84 if (words > std::numeric_limits<std::size_t>::max() / 64 - record_words) {
85 throw std::length_error(
"Monotone samples are too large");
87 words += record_words;
90 auto* packed = storage_.data();
91 for (std::size_t group = 0; group < groups; ++group) {
92 const std::size_t begin = group * 32;
93 const std::size_t count =
94 std::min<std::size_t>(32, values.size() - begin);
95 const auto descriptor = offsets_[group];
96 auto* record = packed + (descriptor & kOffsetMask);
97 record[0] = values[begin];
98 const unsigned width = descriptor >> 58;
99 for (std::size_t i = 0; i < count; ++i) {
100 const std::uint64_t delta = values[begin + i] - record[0];
101 record[1] |= std::uint64_t{1} << ((delta >> width) + i);
102 write_monotone_low(record + 2, i, width, delta);
107 std::uint64_t operator[](std::size_t index)
const {
108 const std::uint64_t descriptor = offsets_[index / 32];
109 const auto* record = storage_.data() + (descriptor & kOffsetMask);
110 const std::size_t local = index % 32;
111 const unsigned width = descriptor >> 58;
112 const std::uint64_t high = ::select_64(record[1], local) - local;
113 return record[0] + (high << width) +
114 read_monotone_low(record + 2, local, width);
117 std::size_t allocated_bytes()
const {
118 return storage_.allocated_bytes() + offsets_.allocated_bytes();
122 static constexpr std::uint64_t kOffsetMask = (std::uint64_t{1} << 58) - 1;
167class BitmapMonotoneSamples :
public Base {
169 BitmapMonotoneSamples() =
default;
170 BitmapMonotoneSamples(std::span<const std::uint64_t> values,
171 std::span<const std::uint64_t> wide = {})
173 wide_(std::span<const SampleWideGroup>(
174 make_sample_wide_groups(values.size(), wide))) {}
176 std::optional<std::size_t> wide_entry(std::size_t index)
const {
180 const auto& group = wide_[index / 32];
181 return sample_wide_entry(group.begin, group.mask, index % 32);
183 std::size_t allocated_bytes()
const {
184 return Base::allocated_bytes() + wide_.allocated_bytes();