Everett
Loading...
Searching...
No Matches
elias_fano.h
Go to the documentation of this file.
1
13#pragma once
14
15#include <algorithm>
16#include <array>
17#include <everett/word_view.h>
19#include <everett/backend.h>
20#include <simd/integer.h>
21#include <simd/packing.h>
22
23#include <bit>
24#include <cstddef>
25#include <cstdint>
26#include <limits>
27#include <numeric>
28#include <span>
29#include <stdexcept>
30#include <utility>
31#include <vector>
32
33namespace everett {
34 namespace elias_fano_detail {
35 constexpr std::uint64_t add(std::uint64_t a, std::uint64_t b) noexcept { return a + b; }
36 constexpr std::uint64_t multiply(std::uint64_t a, std::uint64_t b) noexcept { return a * b; }
37 inline std::uint64_t words(std::uint64_t bits) noexcept {
38 return (bits + 63) >> 6;
39 }
40
41 template <simd::architecture Arch = simd::scalar>
42 inline bool monotone(std::span<std::uint64_t const> source) noexcept {
43 if (source.size() < 2) return true;
44 std::size_t i = 1;
45 if constexpr (!std::is_same_v<Arch, simd::scalar>) {
46 using V = simd::vec<std::uint64_t, backend_detail::register_bytes<Arch> / 8, Arch>;
47 for (; source.size() - i >= V::lanes; i += V::lanes)
48 if (any(V::load(source.data() + i) < V::load(source.data() + i - 1))) return false;
49 }
50 for (; i < source.size(); ++i) if (source[i] < source[i - 1]) return false;
51 return true;
52 }
53
54 // Zero-based selection in a nonzero word, with ordinal < popcount(value).
55 // Byte-prefix populations fit in seven bits, so the marked subtraction
56 // finds the first byte whose cumulative population exceeds ordinal.
57 template <simd::architecture Arch = simd::scalar>
58 inline unsigned select_word(std::uint64_t value, unsigned ordinal) noexcept {
59 if constexpr (std::is_same_v<Arch, simd::avx2> || std::is_same_v<Arch, simd::avx512>)
60 return unsigned(std::countr_zero(deposit_bits(Arch{}, std::uint64_t{1} << ordinal, value)));
61 else {
62 auto pairs = value - ((value >> 1) & 0x5555555555555555ull);
63 auto nibbles = (pairs & 0x3333333333333333ull) + ((pairs >> 2) & 0x3333333333333333ull);
64 auto bytes = (nibbles + (nibbles >> 4)) & 0x0f0f0f0f0f0f0f0full;
65 auto prefixes = bytes * 0x0101010101010101ull;
66 auto marked = ((prefixes | 0x8080808080808080ull) -
67 (ordinal + 1) * 0x0101010101010101ull) & 0x8080808080808080ull;
68 auto shift = unsigned(std::countr_zero(marked)) & ~7u;
69 if (shift) ordinal -= unsigned((prefixes >> (shift - 8)) & 255);
70 auto lower = unsigned((nibbles >> shift) & 15);
71 auto step = unsigned(ordinal >= lower);
72 shift += step * 4;
73 ordinal -= step * lower;
74 auto bits = unsigned(value >> shift) & 15;
75 lower = (bits & 1) + ((bits >> 1) & 1);
76 step = unsigned(ordinal >= lower);
77 shift += step * 2;
78 ordinal -= step * lower;
79 return shift + ordinal + unsigned(((value >> shift) & 1) == 0);
80 }
81 }
82
83 template <unsigned W, std::size_t O, std::size_t I>
84 inline std::uint64_t low_component(std::uint64_t const * source) noexcept {
85 constexpr auto mask = (std::uint64_t{1} << W) - 1;
86 constexpr auto bit = I * W;
87 constexpr auto first = O * 64;
88 if constexpr (bit < first) return (source[I] & mask) >> (first - bit);
89 else return (source[I] & mask) << (bit - first);
90 }
91
92 template <unsigned W, std::size_t O, std::size_t... I>
93 inline std::uint64_t low_word(std::uint64_t const * source, std::index_sequence<I...>) noexcept {
94 constexpr auto first = O * 64 / W;
95 return (low_component<W, O, first + I>(source) | ...);
96 }
97
98 template <unsigned W, std::size_t... O>
99 inline void low_tile(std::uint64_t const * source, std::uint64_t * out,
100 std::index_sequence<O...>) noexcept {
101 ((out[O] = low_word<W, O>(source,
102 std::make_index_sequence<(O * 64 + 63) / W - O * 64 / W + 1>{})), ...);
103 }
104
105 // W-bit fields return to a word boundary after 64/gcd(W,64) values.
106 // Each tile assigns its output words once, rather than repeatedly loading
107 // and updating them for each input field. All shifts are compile-time
108 // constants below 64; the final incomplete tile uses bounded scalar work.
109 template <unsigned W, simd::architecture Arch = simd::scalar>
110 inline void pack_low_fixed(std::span<std::uint64_t const> source,
111 std::span<std::uint64_t> out) noexcept {
112 static_assert(W <= 63);
113 if constexpr (W) {
114 constexpr auto divisor = std::gcd(W, 64u);
115 constexpr auto inputs = 64 / divisor;
116 constexpr auto outputs = W / divisor;
117 std::size_t at = 0;
118 for (; source.size() - at >= inputs; at += inputs) {
119 auto destination = out.data() + (at / inputs) * outputs;
120 // Narrowing truncates low fields and concatenates in source order.
121 // Only the first eight packed bytes are written, with no tail read.
122 if constexpr (!std::is_same_v<Arch, simd::scalar> &&
123 std::endian::native == std::endian::little && (W == 8 || W == 16)) {
124 using V = simd::vec<std::uint64_t, 2, Arch>;
125 auto a = narrow_concat<std::uint32_t>(V::load(source.data() + at),
126 V::load(source.data() + at + 2));
127 if constexpr (W == 16) {
128 auto packed = narrow_concat<std::uint16_t>(a, decltype(a){});
129 reinterpret_bits<std::uint64_t>(packed).store_partial(destination, 1);
130 } else {
131 auto b = narrow_concat<std::uint32_t>(V::load(source.data() + at + 4),
132 V::load(source.data() + at + 6));
133 auto half = narrow_concat<std::uint16_t>(a, b);
134 auto packed = narrow_concat<std::uint8_t>(half, decltype(half){});
135 reinterpret_bits<std::uint64_t>(packed).store_partial(destination, 1);
136 }
137 } else
138 low_tile<W>(source.data() + at, destination, std::make_index_sequence<outputs>{});
139 }
140 auto tail = out.subspan((at / inputs) * outputs);
141 std::fill(tail.begin(), tail.end(), 0);
142 constexpr auto mask = (std::uint64_t{1} << W) - 1;
143 for (std::size_t i = 0; i != source.size() - at; ++i) {
144 auto bit = i * W;
145 unsigned shift = unsigned(bit & 63);
146 auto value = source[at + i] & mask;
147 tail[bit >> 6] |= value << shift;
148 if (shift + W > 64) tail[(bit >> 6) + 1] |= value >> (64 - shift);
149 }
150 }
151 }
152
153 template <simd::architecture Arch, std::size_t... W>
154 constexpr auto low_packers(std::index_sequence<W...>) noexcept {
155 using packer = void (*)(std::span<std::uint64_t const>, std::span<std::uint64_t>) noexcept;
156 return std::array<packer, sizeof...(W)>{&pack_low_fixed<W, Arch>...};
157 }
158
159 // This dispatch occurs once per complete low section, not per value. The
160 // destination may contain old data: both complete and tail words are set,
161 // including zero tail padding. Source and destination must not overlap.
162 template <simd::architecture Arch = simd::scalar>
163 inline void pack_low(std::span<std::uint64_t const> source,
164 std::span<std::uint64_t> out, unsigned width) {
165 if (width > 63) error_detail::raise<std::invalid_argument>("elias_fano low width");
166 if (width && source.size() > (std::numeric_limits<std::uint64_t>::max() - 63) / width)
167 error_detail::raise<std::overflow_error>("elias_fano low section extent");
168 if (out.size() != words(source.size() * width))
169 error_detail::raise<std::invalid_argument>("elias_fano low output size");
170 static constexpr auto packers = low_packers<Arch>(std::make_index_sequence<64>{});
171 packers[width](source, out);
172 }
173
174 // The owner has checked monotonicity, width and extent and zeroed out.
175 // (source[i] >> width) + i is strictly increasing, even for equal values.
176 // Accumulating a word locally removes repeated dependent memory updates;
177 // gaps remain zero. This preserves the exact existing high-bit ordering.
178 inline void write_high(std::span<std::uint64_t const> source,
179 std::span<std::uint64_t> out, unsigned width) noexcept {
180 std::uint64_t word = 0, value = 0;
181 for (std::uint64_t i = 0; i != source.size(); ++i) {
182 auto position = (source[i] >> width) + i;
183 auto next = position >> 6;
184 if (next != word) {
185 out[word] = value;
186 word = next;
187 value = 0;
188 }
189 value |= std::uint64_t{1} << (position & 63);
190 }
191 if (!source.empty()) out[word] = value;
192 }
193 }
194
196 std::uint64_t first;
197 // UINT64_MAX denotes a dense group. Other values index the exception
198 // array, containing every one-bit position of this group of <=256 ones.
199 std::uint64_t sparse;
200 };
201
202 struct elias_fano_cursor;
203
204 // Elias--Fano over an arbitrary nondecreasing sequence of uint64_t values.
205 // Repeated values and the empty sequence are supported. Sampling intervals,
206 // record counts, sentinels and fixed strides belong to the caller.
207 // Select samples every 256 ones: a dense group spans at most 4096 bits
208 // (65 aligned words); a sparse group stores each one-bit position explicitly.
209 // Constructors validate section shapes without reading their contents.
210 // Borrowed metadata must come from a builder or an independently validated
211 // reader. Native words and unaligned little-endian sections share navigation.
213 elias_fano_view() = default;
214
215 elias_fano_view(std::span<std::uint64_t const> low,
216 std::span<std::uint64_t const> high,
217 std::span<elias_fano_sample const> samples,
218 std::span<std::uint64_t const> sparse,
219 std::uint64_t entry_count, std::uint64_t universe,
220 unsigned low_width)
222 entry_count, universe, low_width) {}
223
224 template <class Words, class Samples>
225 requires (std::is_same_v<Words, word_view> && std::is_same_v<Samples, sample_view>)
226 elias_fano_view(Words low, Words high, Samples samples, Words sparse,
227 std::uint64_t entry_count, std::uint64_t universe, unsigned low_width)
228 : low_(low), high_(high), samples_(samples), sparse_(sparse),
230 if (low_width > 63) error_detail::raise<std::invalid_argument>("elias_fano low width");
231 if (!entry_count) {
232 if (universe || low_width || !low.empty() || !high.empty() || !samples.empty() || !sparse.empty())
233 error_detail::raise<std::invalid_argument>("invalid empty Elias-Fano sections");
234 return;
235 }
236 constexpr auto maximum = std::numeric_limits<std::uint64_t>::max() - 255;
237 auto entries = entry_count;
238 // Validate section extents once, before borrowing any navigation words.
239 if (entries > maximum || (low_width && entries > maximum / low_width) ||
240 (universe >> low_width) > maximum - entries)
241 error_detail::raise<std::overflow_error>("elias_fano section extent");
242 auto low_bits = elias_fano_detail::multiply(entries, low_width);
244 if (low.size() != elias_fano_detail::words(low_bits) ||
245 high.size() != elias_fano_detail::words(high_bits_) ||
246 samples.size() != ((entries + 255) >> 8))
247 error_detail::raise<std::invalid_argument>("invalid elias_fano spans");
248 }
249
250 word_view low_words() const noexcept { return low_; }
251 word_view high_words() const noexcept { return high_; }
252 sample_view samples() const noexcept { return samples_; }
253 word_view sparse_words() const noexcept { return sparse_; }
254 std::uint64_t universe() const noexcept { return universe_; }
255 unsigned low_width() const noexcept { return low_width_; }
256 std::uint64_t size() const noexcept { return entry_count_; }
257
258 template <simd::architecture Arch = simd::scalar>
259 std::uint64_t select(std::uint64_t ordinal) const {
260 if (ordinal >= entry_count_) [[unlikely]]
261 error_detail::raise<std::out_of_range>("Elias-Fano ordinal");
262 return decode(ordinal, select_high<Arch>(ordinal));
263 }
264
265 template <simd::architecture Arch = simd::scalar>
266 elias_fano_cursor cursor(std::uint64_t ordinal = 0) const;
267
268 private:
269 friend struct elias_fano_cursor;
270 std::uint64_t decode(std::uint64_t ordinal, std::uint64_t position) const {
271 if (position < ordinal) error_detail::raise<std::invalid_argument>("invalid elias_fano high value");
272 auto hi = position - ordinal;
273 if (hi > (universe_ >> low_width_)) error_detail::raise<std::invalid_argument>("elias_fano high overflow");
274 std::uint64_t lo = 0;
275 if (low_width_) {
276 auto bit = ordinal * low_width_;
277 auto word = bit >> 6;
278 unsigned shift = unsigned(bit & 63);
279 lo = low_[word] >> shift;
280 if (shift + low_width_ > 64) lo |= low_[word + 1] << (64 - shift);
281 lo &= (std::uint64_t{1} << low_width_) - 1;
282 }
283 auto value = (hi << low_width_) | lo;
284 if (value > universe_) error_detail::raise<std::invalid_argument>("elias_fano value exceeds universe");
285 return value;
286 }
287
288 template <simd::architecture Arch>
289 std::uint64_t select_high(std::uint64_t ordinal) const {
290 auto sample = samples_[ordinal >> 8];
291 unsigned remaining = unsigned(ordinal & 255);
292 if (sample.sparse != std::numeric_limits<std::uint64_t>::max()) {
293 if (sample.sparse > sparse_.size() || remaining >= sparse_.size() - sample.sparse)
294 error_detail::raise<std::invalid_argument>("invalid elias_fano exception");
295 auto position = sparse_[sample.sparse + remaining];
296 if (position >= high_bits_ || !(high_[position >> 6] & (std::uint64_t{1} << (position & 63))))
297 error_detail::raise<std::invalid_argument>("invalid elias_fano sparse position");
298 return position;
299 }
300 if (sample.first >= high_bits_) error_detail::raise<std::invalid_argument>("invalid elias_fano sample");
301 auto word = sample.first >> 6;
302 auto value = high_[word] & (~std::uint64_t{0} << (sample.first & 63));
303 for (unsigned scanned = 0; scanned < 65 && word < high_.size(); ++scanned, ++word) {
304 if (scanned) value = high_[word];
305 auto population = unsigned(std::popcount(value));
306 if (remaining < population) {
307 auto position = word * 64 + elias_fano_detail::select_word<Arch>(value, remaining);
308 if (position >= high_bits_ || position - sample.first >= 4096)
309 error_detail::raise<std::invalid_argument>("elias_fano dense span");
310 return position;
311 }
312 remaining -= population;
313 }
314 error_detail::raise<std::invalid_argument>("elias_fano missing high bit");
315 }
316
321 std::uint64_t entry_count_ = 0;
322 std::uint64_t universe_ = 0;
323 std::uint64_t high_bits_ = 0;
324 unsigned low_width_ = 0;
325 };
326
327 // Forward selection retains the unused high bits of its current word.
328 // Every 256 entries it enters the next directory sample, preserving dense
329 // span and sparse-exception checks. An ordinal start performs one selection;
330 // starting at zero or a directory boundary reads no payload pages.
331 // The source sections must outlive this cursor and any copies of it.
333 template <simd::architecture Arch = simd::scalar>
334 explicit elias_fano_cursor(elias_fano_view source, std::uint64_t ordinal = 0,
335 std::type_identity<Arch> = {})
336 : source_(source), ordinal_(ordinal) {
337 if (ordinal > source.size()) error_detail::raise<std::out_of_range>("Elias-Fano cursor ordinal");
338 if (done() || !(ordinal & 255)) return;
339 auto sample = source_.samples_[ordinal >> 8];
340 sample_ = {sample.first, sample.sparse};
341 if (sample_.sparse == std::numeric_limits<std::uint64_t>::max()) {
342 auto position = source_.select_high<Arch>(ordinal);
343 word_ = position >> 6;
344 remaining_ = source_.high_[word_] & (~std::uint64_t{0} << (position & 63));
345 }
346 }
347 bool done() const noexcept { return ordinal_ == source_.size(); }
348 std::uint64_t ordinal() const noexcept { return ordinal_; }
349 std::uint64_t next() {
350 if (done()) [[unlikely]] error_detail::raise<std::out_of_range>("Elias-Fano cursor end");
351 if (!(ordinal_ & 255)) {
352 auto sample = source_.samples_[ordinal_ >> 8];
353 sample_ = {sample.first, sample.sparse};
354 if (sample_.sparse == std::numeric_limits<std::uint64_t>::max()) {
356 error_detail::raise<std::invalid_argument>("invalid elias_fano sample");
357 word_ = sample_.first >> 6;
358 remaining_ = source_.high_[word_] & (~std::uint64_t{0} << (sample_.first & 63));
359 }
360 }
361 std::uint64_t position;
362 if (sample_.sparse != std::numeric_limits<std::uint64_t>::max()) {
363 auto lane = ordinal_ & 255;
365 error_detail::raise<std::invalid_argument>("invalid elias_fano exception");
366 position = source_.sparse_[sample_.sparse + lane];
367 if (position >= source_.high_bits_ || !(source_.high_[position >> 6] & (std::uint64_t{1} << (position & 63))))
368 error_detail::raise<std::invalid_argument>("invalid elias_fano sparse position");
369 } else {
370 while (!remaining_) {
371 ++word_;
372 if (word_ >= source_.high_.size() || word_ - (sample_.first >> 6) >= 65)
373 error_detail::raise<std::invalid_argument>("elias_fano missing high bit");
375 }
376 position = (word_ << 6) + unsigned(std::countr_zero(remaining_));
377 if (position >= source_.high_bits_ || position - sample_.first >= 4096)
378 error_detail::raise<std::invalid_argument>("elias_fano dense span");
379 }
380 auto value = source_.decode(ordinal_, position);
381 remaining_ &= remaining_ - 1;
382 ++ordinal_;
383 return value;
384 }
385
386 private:
389 std::uint64_t ordinal_ = 0, word_ = 0, remaining_ = 0;
390 };
391
392 template <simd::architecture Arch>
393 inline elias_fano_cursor elias_fano_view::cursor(std::uint64_t ordinal) const {
394 return elias_fano_cursor(*this, ordinal, std::type_identity<Arch>{});
395 }
396
397 struct elias_fano {
398 template <simd::architecture Arch = simd::scalar>
399 static elias_fano build(std::span<std::uint64_t const> residuals) {
400 if (residuals.empty()) return {};
401 if (!elias_fano_detail::monotone<Arch>(residuals))
402 error_detail::raise<std::invalid_argument>("elias_fano nonmonotone offsets");
403 elias_fano result;
404 result.entry_count = residuals.size();
405 result.universe = residuals.back();
406 auto quotient = result.universe / residuals.size();
407 result.low_width = quotient ? unsigned(std::bit_width(quotient) - 1) : 0;
408 constexpr auto maximum = std::numeric_limits<std::uint64_t>::max() - 255;
409 if (residuals.size() > maximum || (result.low_width && residuals.size() > maximum / result.low_width) ||
410 (result.universe >> result.low_width) > maximum - residuals.size())
411 error_detail::raise<std::overflow_error>("elias_fano section extent");
412 auto low_bits = elias_fano_detail::multiply(residuals.size(), result.low_width);
413 auto high_bits = elias_fano_detail::add(result.universe >> result.low_width, residuals.size());
414 result.low.assign(elias_fano_detail::words(low_bits), 0);
415 result.high.assign(elias_fano_detail::words(high_bits), 0);
416 result.samples.clear();
417 elias_fano_detail::pack_low<Arch>(residuals, result.low, result.low_width);
418 elias_fano_detail::write_high(residuals, result.high, result.low_width);
419 for (std::uint64_t begin = 0; begin < residuals.size(); begin += 256) {
420 auto end = residuals.size() - begin < 256 ? residuals.size() : begin + 256;
421 auto first = (residuals[begin] >> result.low_width) + begin;
422 auto last = (residuals[end - 1] >> result.low_width) + end - 1;
423 auto sparse = std::numeric_limits<std::uint64_t>::max();
424 if (last - first >= 4096) {
425 sparse = result.sparse.size();
426 for (auto i = begin; i < end; ++i)
427 result.sparse.push_back((residuals[i] >> result.low_width) + i);
428 }
429 result.samples.push_back({first, sparse});
430 }
431 return result;
432 }
433
436 }
437
438 elias_fano_view view() const && = delete;
439
440 // The default is an empty sequence. A sampling owner encodes any terminal
441 // sentinel explicitly as another value; the codec imposes no stride.
442 std::vector<std::uint64_t> low;
443 std::vector<std::uint64_t> high;
445 std::vector<std::uint64_t> sparse;
446 std::uint64_t entry_count = 0;
447 std::uint64_t universe = 0;
448 unsigned low_width = 0;
449 };
450}
Shares explicit SIMD architecture traits with Everett's kernels.
Outlines exceptional check failures while preserving their types and messages.
unsigned select_word(std::uint64_t value, unsigned ordinal) noexcept
Definition elias_fano.h:58
bool monotone(std::span< std::uint64_t const > source) noexcept
Definition elias_fano.h:42
void low_tile(std::uint64_t const *source, std::uint64_t *out, std::index_sequence< O... >) noexcept
Definition elias_fano.h:99
std::uint64_t low_component(std::uint64_t const *source) noexcept
Definition elias_fano.h:84
void pack_low_fixed(std::span< std::uint64_t const > source, std::span< std::uint64_t > out) noexcept
Definition elias_fano.h:110
void pack_low(std::span< std::uint64_t const > source, std::span< std::uint64_t > out, unsigned width)
Definition elias_fano.h:163
constexpr auto low_packers(std::index_sequence< W... >) noexcept
Definition elias_fano.h:154
std::uint64_t words(std::uint64_t bits) noexcept
Definition elias_fano.h:37
std::uint64_t low_word(std::uint64_t const *source, std::index_sequence< I... >) noexcept
Definition elias_fano.h:93
constexpr std::uint64_t multiply(std::uint64_t a, std::uint64_t b) noexcept
Definition elias_fano.h:36
void write_high(std::span< std::uint64_t const > source, std::span< std::uint64_t > out, unsigned width) noexcept
Definition elias_fano.h:178
constexpr std::uint64_t add(std::uint64_t a, std::uint64_t b) noexcept
Definition elias_fano.h:35
Definition active_engine.h:18
Definition elias_fano.h:332
elias_fano_sample sample_
Definition elias_fano.h:388
elias_fano_cursor(elias_fano_view source, std::uint64_t ordinal=0, std::type_identity< Arch >={})
Definition elias_fano.h:334
elias_fano_view source_
Definition elias_fano.h:387
std::uint64_t remaining_
Definition elias_fano.h:389
std::uint64_t ordinal_
Definition elias_fano.h:389
std::uint64_t next()
Definition elias_fano.h:349
std::uint64_t word_
Definition elias_fano.h:389
bool done() const noexcept
Definition elias_fano.h:347
std::uint64_t ordinal() const noexcept
Definition elias_fano.h:348
Definition elias_fano.h:195
std::uint64_t first
Definition elias_fano.h:196
std::uint64_t sparse
Definition elias_fano.h:199
Definition elias_fano.h:212
word_view sparse_
Definition elias_fano.h:320
word_view high_
Definition elias_fano.h:318
std::uint64_t select(std::uint64_t ordinal) const
Definition elias_fano.h:259
elias_fano_view(Words low, Words high, Samples samples, Words sparse, std::uint64_t entry_count, std::uint64_t universe, unsigned low_width)
Definition elias_fano.h:226
unsigned low_width_
Definition elias_fano.h:324
unsigned low_width() const noexcept
Definition elias_fano.h:255
elias_fano_cursor cursor(std::uint64_t ordinal=0) const
Definition elias_fano.h:393
word_view sparse_words() const noexcept
Definition elias_fano.h:253
std::uint64_t entry_count_
Definition elias_fano.h:321
word_view low_words() const noexcept
Definition elias_fano.h:250
std::uint64_t universe_
Definition elias_fano.h:322
sample_view samples_
Definition elias_fano.h:319
std::uint64_t select_high(std::uint64_t ordinal) const
Definition elias_fano.h:289
friend struct elias_fano_cursor
Definition elias_fano.h:269
std::uint64_t size() const noexcept
Definition elias_fano.h:256
sample_view samples() const noexcept
Definition elias_fano.h:252
word_view high_words() const noexcept
Definition elias_fano.h:251
std::uint64_t universe() const noexcept
Definition elias_fano.h:254
std::uint64_t decode(std::uint64_t ordinal, std::uint64_t position) const
Definition elias_fano.h:270
elias_fano_view(std::span< std::uint64_t const > low, std::span< std::uint64_t const > high, std::span< elias_fano_sample const > samples, std::span< std::uint64_t const > sparse, std::uint64_t entry_count, std::uint64_t universe, unsigned low_width)
Definition elias_fano.h:215
word_view low_
Definition elias_fano.h:317
std::uint64_t high_bits_
Definition elias_fano.h:323
Definition elias_fano.h:397
std::vector< std::uint64_t > sparse
Definition elias_fano.h:445
std::vector< std::uint64_t > high
Definition elias_fano.h:443
std::vector< std::uint64_t > low
Definition elias_fano.h:442
std::vector< elias_fano_sample > samples
Definition elias_fano.h:444
unsigned low_width
Definition elias_fano.h:448
std::uint64_t universe
Definition elias_fano.h:447
static elias_fano build(std::span< std::uint64_t const > residuals)
Definition elias_fano.h:399
elias_fano_view view() const &
Definition elias_fano.h:434
elias_fano_view view() const &&=delete
std::uint64_t entry_count
Definition elias_fano.h:446
Definition word_view.h:82
std::size_t size() const noexcept
Definition word_view.h:97
bool empty() const noexcept
Definition word_view.h:98
Definition word_view.h:31
std::size_t size() const noexcept
Definition word_view.h:41
Borrows native or little-endian directory words and select samples.