Skip to main content

rudb_encoding/
integer.rs

1//! The single column integer encodings and the cascade over them.
2//!
3//! `spec/06-compression.md` section 6.2 lists the encoding set and section 6.3 says the ratios are
4//! in the cascade rather than in any one encoding. This module is both: the seven candidate shapes
5//! for an integer column, each of which encodes its own output by calling back into the chooser, so
6//! that RLE over a dictionary over a bit packed code array is a thing that happens by construction
7//! rather than a case somebody wrote out.
8//!
9//! Everything here works on `i64`. A narrower column is widened on the way in and nothing is lost
10//! by it, because every encoding's size comes from the range of the values rather than from the
11//! declared width of the type: a `SMALLINT` column of values 100 to 130 packs to 5 bits whether it
12//! arrived as `i16` or as `i64`. The one place the widening would cost something is a raw copy, and
13//! there is no raw copy, because a bit packed unit at width 64 is exactly that and the chooser
14//! reaches it on its own when nothing else fits.
15//!
16//! ## The unit
17//!
18//! Bit packing is per 1024 values, per [`crate::bitpack`]. Everything else is per chunk, where a
19//! chunk is however many values the caller passes in and is meant to be a row group. The two
20//! granularities are the point rather than an accident. A frame of reference base that is chosen
21//! per 1024 values tracks a column that drifts, which is what a timestamp column and an
22//! autoincrementing key both do, and one base per row group would pay the whole range of the row
23//! group on every value. A dictionary, on the other hand, is worth more the larger the unit it
24//! covers, which is the argument section 6.5 takes all the way to a dictionary per table.
25//!
26//! ## The serialized form
27//!
28//! A chunk is a tag byte, a value count, and a body whose shape depends on the tag. Bodies that
29//! contain another array of integers contain a whole chunk, tag and all, which is what makes the
30//! decoder a fold and what makes the cascade free: nothing in `Rle` knows what its run lengths are
31//! encoded as. The header is fixed width little endian rather than a varint, because 5 bytes per
32//! chunk against a chunk that holds a row group is not worth the branch on the decode path.
33//!
34//! ## What the chooser does, and what it will have to do instead
35//!
36//! It encodes every candidate and keeps the smallest. That is the honest baseline for M1, which is
37//! a measurement of what the format can do rather than of how fast a writer can decide, and it is
38//! not what a write path can afford. Section 6.3 describes the real thing: evaluate the candidates
39//! on a systematic sample, not the first N rows, because column data is frequently clustered and
40//! the first 1024 rows of a sorted column look constant. Building that first would mean the numbers
41//! this milestone produces are the sampler's numbers rather than the format's, and there would be
42//! no way to tell how much the sampler is leaving behind.
43
44use std::collections::BTreeMap;
45
46use rudb_common::{Error, Result};
47
48use crate::chooser::{Chooser, EXHAUSTIVE};
49use crate::reader::Reader;
50
51use crate::bitpack::{self, VALUES};
52
53/// How deep a cascade is allowed to go.
54///
55/// Three levels is what section 6.3 says captures most of what a general compressor would find:
56/// dictionary, then bit packed codes, then nothing left worth doing. The limit exists because the
57/// chooser is exhaustive and a cascade that could nest forever would be exponential, and because a
58/// fourth level has never once been the smallest candidate in anything measured so far.
59const MAX_DEPTH: u8 = 3;
60
61/// How many values a run writes at once, whatever the run is.
62///
63/// A run length decode used to write a value at a time for the length of the run, which reads well
64/// and is the wrong shape for the data: a clustered join key runs two or three long, so the loop
65/// spent its time mispredicting its own exit and the branch cost more than the stores did. Writing
66/// a fixed eight and then moving on by the run's real length has no exit to predict, and whatever
67/// of the eight was surplus is overwritten by the run that follows, because every run writes at
68/// least its own length. Eight because it is two vector stores on every machine this runs on and
69/// longer than nearly every run in a column worth run length encoding at all.
70const RUN: usize = 8;
71
72/// The average run length from which a run length chunk is decoded into reserved room rather than
73/// a zeroed one. Past it the zeroing is most of the writes, and below it the fixed width write of
74/// [`RUN`] is the cheaper loop.
75const LONG_RUN: usize = 64;
76
77/// What a chunk is encoded as. The discriminant is the tag byte in the serialized form and is part
78/// of the format, so the numbers are written down rather than left to the compiler.
79#[derive(Debug, Clone, Copy, PartialEq, Eq)]
80pub enum Kind {
81    /// One value repeated. The whole chunk is the tag, the count and the value.
82    Constant = 0,
83    /// Frame of reference then bit packed, per 1024 values. Covers plain bit packing at base zero
84    /// and a raw copy at width 64.
85    Packed = 1,
86    /// Differences between neighbours, zigzagged so a decreasing column is as cheap as an
87    /// increasing one, then encoded as a chunk in its own right.
88    Delta = 2,
89    /// Run values and run lengths, each encoded as a chunk in its own right.
90    Rle = 3,
91    /// A dictionary of the distinct values and an array of codes into it, both encoded as chunks in
92    /// their own right.
93    Dict = 4,
94    /// One dominant value with an exception list of positions and values.
95    Sparse = 5,
96    /// A base and a common step, with the number of steps to each value encoded as a chunk in its
97    /// own right.
98    Strided = 6,
99}
100
101impl Kind {
102    /// Every kind, in tag order.
103    pub const ALL: [Self; 7] = [
104        Self::Constant,
105        Self::Packed,
106        Self::Delta,
107        Self::Rle,
108        Self::Dict,
109        Self::Sparse,
110        Self::Strided,
111    ];
112
113    fn tag(self) -> u8 {
114        self as u8
115    }
116
117    fn from_tag(tag: u8) -> Result<Self> {
118        match tag {
119            0 => Ok(Self::Constant),
120            1 => Ok(Self::Packed),
121            2 => Ok(Self::Delta),
122            3 => Ok(Self::Rle),
123            4 => Ok(Self::Dict),
124            5 => Ok(Self::Sparse),
125            6 => Ok(Self::Strided),
126            other => Err(Error::internal(format!("unknown encoding tag {other}"))),
127        }
128    }
129
130    /// The name that goes in a report.
131    #[must_use]
132    pub fn name(self) -> &'static str {
133        match self {
134            Self::Constant => "CONSTANT",
135            Self::Packed => "FOR+BITPACK",
136            Self::Delta => "DELTA",
137            Self::Rle => "RLE",
138            Self::Dict => "DICT",
139            Self::Sparse => "SPARSE",
140            Self::Strided => "STRIDE",
141        }
142    }
143}
144
145/// Encodes a chunk of integers, choosing the cascade that comes out smallest.
146///
147/// # Errors
148///
149/// If the chunk is longer than `u32::MAX`, or if an encoding produces something its own decoder
150/// would not accept, which is an internal inconsistency rather than a caller error.
151pub fn encode(values: &[i64]) -> Result<Vec<u8>> {
152    encode_with(values, &EXHAUSTIVE)
153}
154
155/// [`encode`] with somebody else deciding which candidates are worth encoding in full.
156///
157/// A chooser narrows the list and nothing else. It cannot offer a candidate that does not apply, so
158/// whatever it picks still has to encode the whole chunk and still has to decode, and the worst a
159/// bad one can do is come out bigger than [`encode`] would have.
160///
161/// # Errors
162///
163/// As [`encode`].
164pub fn encode_with(values: &[i64], chooser: &dyn Chooser) -> Result<Vec<u8>> {
165    encode_at(values, 0, chooser)
166}
167
168/// Decodes a chunk written by [`encode`].
169///
170/// # Errors
171///
172/// If the bytes are truncated, carry an unknown tag, or describe a chunk whose parts do not agree
173/// with each other.
174pub fn decode(bytes: &[u8]) -> Result<Vec<i64>> {
175    let mut reader = Reader::new(bytes);
176    let values = with_decoding(|scratch| decode_chunk(&mut reader, scratch))?;
177    if reader.remaining() != 0 {
178        return Err(Error::internal(format!(
179            "{} bytes left over after decoding a chunk",
180            reader.remaining()
181        )));
182    }
183    Ok(values)
184}
185
186/// Counts values in one encoded chunk without expanding sparse or run-length chunks into rows.
187///
188/// The result is computed from the encoded row values when called. It is not a stored histogram.
189/// Other encodings use the ordinary decoder until they have a useful count form of their own.
190///
191/// # Errors
192///
193/// As [`decode`], or if a sparse position or run length is outside the chunk.
194pub fn tally(bytes: &[u8]) -> Result<(usize, Vec<(i64, u64)>)> {
195    let mut counts = BTreeMap::<i64, u64>::new();
196    let rows = fold(bytes, |value, count| {
197        *counts.entry(value).or_default() += count;
198        Ok(())
199    })?;
200    Ok((rows, counts.into_iter().collect()))
201}
202
203/// Visits the values of one encoded chunk with their runtime row counts. Sparse chunks written
204/// with sorted exception positions need no per-chunk count map. An older or malformed chunk with
205/// repeated positions keeps the decoder's last-write-wins behavior.
206///
207/// # Errors
208///
209/// As [`decode`], or if the callback rejects a count.
210pub fn fold(bytes: &[u8], mut emit: impl FnMut(i64, u64) -> Result<()>) -> Result<usize> {
211    let mut reader = Reader::new(bytes);
212    let kind = Kind::from_tag(reader.u8()?)?;
213    let count = reader.u32()? as usize;
214    match kind {
215        Kind::Constant => {
216            let value = reader.i64()?;
217            if count != 0 {
218                emit(value, count as u64)?;
219            }
220        }
221        Kind::Sparse => {
222            let dominant = reader.i64()?;
223            let exception_count = reader.u32()? as usize;
224            let (positions, values) = with_decoding(|scratch| -> Result<_> {
225                Ok((decode_chunk(&mut reader, scratch)?, decode_chunk(&mut reader, scratch)?))
226            })?;
227            if positions.len() != exception_count || values.len() != exception_count {
228                return Err(Error::internal("a sparse chunk disagrees about its exception count"));
229            }
230            let mut ordered = true;
231            let mut previous = None;
232            for &position in &positions {
233                let position = usize::try_from(position)
234                    .ok()
235                    .filter(|&position| position < count)
236                    .ok_or_else(|| Error::internal("a sparse exception is outside the chunk"))?;
237                if previous.is_some_and(|last| position <= last) {
238                    ordered = false;
239                }
240                previous = Some(position);
241            }
242            if ordered {
243                if count != exception_count {
244                    emit(dominant, (count - exception_count) as u64)?;
245                }
246                for value in values {
247                    emit(value, 1)?;
248                }
249            } else {
250                // The ordinary decoder lets a later exception overwrite an earlier one at the
251                // same position. Keep that rule for chunks the writer would not normally produce.
252                let mut exceptions = BTreeMap::<usize, i64>::new();
253                for (position, value) in positions.into_iter().zip(values) {
254                    exceptions.insert(position as usize, value);
255                }
256                if count != exceptions.len() {
257                    emit(dominant, (count - exceptions.len()) as u64)?;
258                }
259                for value in exceptions.into_values() {
260                    emit(value, 1)?;
261                }
262            }
263        }
264        Kind::Rle => {
265            let (values, lengths) = with_decoding(|scratch| -> Result<_> {
266                Ok((decode_chunk(&mut reader, scratch)?, decode_chunk(&mut reader, scratch)?))
267            })?;
268            if values.len() != lengths.len() {
269                return Err(Error::internal("an RLE chunk has more runs than run lengths"));
270            }
271            let mut rows = 0_usize;
272            for (value, length) in values.into_iter().zip(lengths) {
273                let length = usize::try_from(length)
274                    .map_err(|_| Error::internal("a negative RLE run length"))?;
275                rows = rows
276                    .checked_add(length)
277                    .filter(|&rows| rows <= count)
278                    .ok_or_else(|| Error::internal("an RLE run ends past its chunk"))?;
279                if length != 0 {
280                    emit(value, length as u64)?;
281                }
282            }
283            check_count(rows, count)?;
284        }
285        _ => {
286            // Re-read the header through the existing decoder for the other cascade shapes.
287            reader = Reader::new(bytes);
288            let values = with_decoding(|scratch| decode_chunk(&mut reader, scratch))?;
289            check_count(values.len(), count)?;
290            for value in values {
291                emit(value, 1)?;
292            }
293        }
294    }
295    if reader.remaining() != 0 {
296        return Err(Error::internal(format!(
297            "{} bytes left over after counting a chunk",
298            reader.remaining()
299        )));
300    }
301    Ok(count)
302}
303
304/// Decodes selected row positions from a chunk written by [`encode`].
305///
306/// Positions must be sorted and unique. Packed chunks read only the words holding those positions,
307/// and run length chunks walk their run boundaries without expanding the output. Other cascade
308/// shapes use the full decoder and select afterward until they have a point form of their own.
309///
310/// # Errors
311///
312/// As [`decode`], or if a position is outside the chunk or the positions are not strictly
313/// increasing.
314pub fn decode_selected(bytes: &[u8], positions: &[usize]) -> Result<Vec<i64>> {
315    if positions.windows(2).any(|pair| pair[0] >= pair[1]) {
316        return Err(Error::internal("selected integer positions are not sorted and unique"));
317    }
318    let mut reader = Reader::new(bytes);
319    let values = with_decoding(|scratch| decode_selected_chunk(&mut reader, positions, scratch))?;
320    if reader.remaining() != 0 {
321        return Err(Error::internal(format!(
322            "{} bytes left over after decoding selected values",
323            reader.remaining()
324        )));
325    }
326    Ok(values)
327}
328
329/// Decodes a chunk that sits at the front of a longer buffer, and says how many bytes it took.
330///
331/// A string column holds integer chunks inside its own body, and the reader on that side cannot
332/// know where the nested chunk ends until it has been read. A chunk is self delimiting, so this is
333/// the same work [`decode`] does without the check that nothing follows.
334///
335/// # Errors
336///
337/// As [`decode`], except that trailing bytes are what the caller asked about rather than an error.
338pub fn decode_prefix(bytes: &[u8]) -> Result<(Vec<i64>, usize)> {
339    let mut reader = Reader::new(bytes);
340    let values = with_decoding(|scratch| decode_chunk(&mut reader, scratch))?;
341    Ok((values, reader.used()))
342}
343
344/// [`describe`] over a chunk at the front of a longer buffer, and how many bytes it took.
345///
346/// # Errors
347///
348/// As [`decode_prefix`].
349pub fn describe_prefix(bytes: &[u8]) -> Result<(String, usize)> {
350    let mut reader = Reader::new(bytes);
351    let text = describe_chunk(&mut reader)?;
352    Ok((text, reader.used()))
353}
354
355/// The size in bytes of every candidate, for a report that wants to say what the cascade was
356/// chosen over rather than only what it chose. A candidate that does not apply is absent.
357///
358/// # Errors
359///
360/// As [`encode`].
361pub fn candidate_sizes(values: &[i64]) -> Result<Vec<(Kind, usize)>> {
362    let mut sizes = Vec::new();
363    for kind in candidates(values, 0, &EXHAUSTIVE) {
364        if let Some(bytes) = encode_as(kind, values, 0, &EXHAUSTIVE)? {
365            sizes.push((kind, bytes.len()));
366        }
367    }
368    Ok(sizes)
369}
370
371/// Which candidates [`encode`] would try on this chunk, in the order it tries them.
372///
373/// The chooser is exhaustive, so this is also the list of encodes it pays for to return one of
374/// them. A caller measuring where the encode time goes needs the list separately from the sizes,
375/// because a candidate that is offered and turns out not to apply still costs whatever it spent
376/// finding that out.
377#[must_use]
378pub fn offered(values: &[i64]) -> Vec<Kind> {
379    candidates(values, 0, &EXHAUSTIVE)
380}
381
382/// One candidate on its own, which is what the chooser calls once per entry in [`offered`].
383///
384/// `None` when the encoding does not apply. This is here so that the time the chooser spends can be
385/// attributed to the candidate that spent it, which is the measurement F2 wants before anybody
386/// replaces the exhaustive search with a sampled one. It is not how a writer encodes a chunk:
387/// [`encode`] is, and picking a kind by hand gives up the only thing the chooser is for.
388///
389/// # Errors
390///
391/// As [`encode`].
392pub fn encode_only(kind: Kind, values: &[i64]) -> Result<Option<Vec<u8>>> {
393    encode_as(kind, values, 0, &EXHAUSTIVE)
394}
395
396/// How big one candidate comes out, which is all a sampling chooser needs from it.
397///
398/// The bytes are thrown away, so this says nothing [`encode_only`] does not. It is `pub(crate)` and
399/// separate so that the sampler in [`crate::chooser`] is not handing back buffers it will not read.
400pub(crate) fn size_as(kind: Kind, values: &[i64], depth: u8) -> Result<Option<usize>> {
401    Ok(encode_as(kind, values, depth, &EXHAUSTIVE)?.map(|bytes| bytes.len()))
402}
403
404/// The kind at every level of an encoded chunk, in the order the encoder chose them.
405///
406/// The order is the one [`encode_with`] asks its chooser in: a level, then everything under its
407/// first inner chunk, then everything under its second. So a chooser that hands these back one per
408/// question gets the same cascade on a chunk that offers the same kinds, without searching any of
409/// it. That is what a writer with many small parts of one column wants, because the search is
410/// most of what the encode costs and neighbouring parts nearly always come out the same shape.
411///
412/// # Errors
413///
414/// As [`decode`].
415pub fn shape(bytes: &[u8]) -> Result<Vec<Kind>> {
416    let mut reader = Reader::new(bytes);
417    let mut kinds = Vec::new();
418    shape_chunk(&mut reader, &mut kinds)?;
419    Ok(kinds)
420}
421
422/// The cascade a chunk was encoded as, as a line of text like `DICT(PACKED, PACKED)`.
423///
424/// # Errors
425///
426/// As [`decode`].
427pub fn describe(bytes: &[u8]) -> Result<String> {
428    let mut reader = Reader::new(bytes);
429    describe_chunk(&mut reader)
430}
431
432fn encode_at(values: &[i64], depth: u8, chooser: &dyn Chooser) -> Result<Vec<u8>> {
433    let offered = candidates(values, depth, chooser);
434    let mut best: Option<Vec<u8>> = None;
435    for kind in chooser.narrow_integers(values, &offered, depth) {
436        let Some(bytes) = encode_as(kind, values, depth, chooser)? else {
437            continue;
438        };
439        if best.as_ref().is_none_or(|current| bytes.len() < current.len()) {
440            best = Some(bytes);
441        }
442    }
443    // `Packed` applies to every input including the empty one, so the chooser always has at least
444    // one candidate and this cannot be reached without a bug in `candidates`.
445    best.ok_or_else(|| Error::internal("no encoding applied to the chunk"))
446}
447
448/// Which candidates are worth encoding for this input.
449///
450/// The filters here are not the cost model. They are the cases where the encoding cannot be
451/// expressed at all, or is provably larger than `Packed` on the same data, so that the exhaustive
452/// chooser does not spend a dictionary build on a column of 100,000 distinct values to discover
453/// what its distinct count already said.
454///
455/// A kind the chooser says it will never keep is not tested for at all. The test for a dictionary
456/// sorts a copy of the chunk, and this runs at every level of the cascade, so a chooser that never
457/// keeps a dictionary was paying for a sort per level to find out something it would ignore.
458fn candidates(values: &[i64], depth: u8, chooser: &dyn Chooser) -> Vec<Kind> {
459    let mut kinds = vec![Kind::Packed];
460    if depth >= MAX_DEPTH {
461        return kinds;
462    }
463    let Some(profile) = Profile::of(values) else {
464        return kinds;
465    };
466    if profile.runs == 1 {
467        // Nothing else can beat 13 bytes, so this is the whole answer rather than a candidate.
468        return vec![Kind::Constant];
469    }
470    let considered = |kind| chooser.considers_integer(kind, depth);
471    // Every neighbouring difference is no wider than the whole range, so a range that fits in an
472    // `i64` answers for all of them and only a chunk holding both ends of the type walks the pairs.
473    if considered(Kind::Delta)
474        && (profile.max.checked_sub(profile.min).is_some() || deltas_fit(values))
475    {
476        kinds.push(Kind::Delta);
477    }
478    if considered(Kind::Rle) && profile.runs * 4 <= values.len() * 3 {
479        kinds.push(Kind::Rle);
480    }
481    if considered(Kind::Dict) && spread_of(values).0 * 2 <= values.len() {
482        kinds.push(Kind::Dict);
483    }
484    // A value in four rows out of five leaves a fifth for everything else, and each of those rows
485    // starts at most two runs, so a chunk with more runs than that has no such value and the vote
486    // is not taken.
487    if considered(Kind::Sparse)
488        && (profile.runs - 1) * 5 <= values.len() * 2
489        && majority(values).is_some_and(|(_, count)| count * 10 >= values.len() * 8)
490    {
491        kinds.push(Kind::Sparse);
492    }
493    if considered(Kind::Strided) && stride_from(values, profile.min).is_some() {
494        kinds.push(Kind::Strided);
495    }
496    kinds
497}
498
499/// What one pass over a chunk says about it, which is most of what the candidate tests ask.
500///
501/// The tests used to walk the chunk once each: once to see whether it was one value, once for the
502/// deltas, once to count runs, twice for the vote and once more for the smallest value under the
503/// stride. That is six passes on every chunk at every level of the cascade, and on ClickBench `hits`
504/// they were most of the tenth of the load's CPU that `encode_at` came to, since a replayed part
505/// still asks every question the fallback would. This is one pass, and the vote is only taken where
506/// the run count leaves room for it.
507struct Profile {
508    min: i64,
509    max: i64,
510    /// Runs of equal neighbours, which is one for a chunk of a single value.
511    runs: usize,
512}
513
514impl Profile {
515    fn of(values: &[i64]) -> Option<Self> {
516        let first = *values.first()?;
517        let (mut min, mut max, mut breaks) = (first, first, 0usize);
518        for (before, after) in values.iter().zip(&values[1..]) {
519            min = min.min(*after);
520            max = max.max(*after);
521            breaks += usize::from(before != after);
522        }
523        Some(Self { min, max, runs: breaks + 1 })
524    }
525}
526
527/// `None` when the encoding does not apply to this input, which the caller treats as a candidate
528/// that did not run rather than as a failure.
529fn encode_as(
530    kind: Kind,
531    values: &[i64],
532    depth: u8,
533    chooser: &dyn Chooser,
534) -> Result<Option<Vec<u8>>> {
535    let mut out = Vec::new();
536    put_u8(&mut out, kind.tag());
537    put_u32(&mut out, u32::try_from(values.len()).map_err(|_| too_long(values.len()))?);
538    match kind {
539        Kind::Constant => {
540            let Some(first) = values.first() else {
541                return Ok(None);
542            };
543            if values.iter().any(|value| value != first) {
544                return Ok(None);
545            }
546            put_i64(&mut out, *first);
547        }
548        Kind::Packed => encode_packed(values, &mut out)?,
549        Kind::Delta => {
550            // An empty chunk has no first value to hang the differences off. The search never asks
551            // for one because `candidates` rules it out, but `encode_only` goes straight past that
552            // and used to index into the chunk anyway.
553            let (Some(first), Some(deltas)) = (values.first(), deltas(values)) else {
554                return Ok(None);
555            };
556            put_i64(&mut out, *first);
557            out.extend_from_slice(&encode_at(&deltas, depth + 1, chooser)?);
558        }
559        Kind::Rle => {
560            let (run_values, run_lengths) = runs(values);
561            if run_values.is_empty() {
562                return Ok(None);
563            }
564            out.extend_from_slice(&encode_at(&run_values, depth + 1, chooser)?);
565            out.extend_from_slice(&encode_at(&run_lengths, depth + 1, chooser)?);
566        }
567        Kind::Dict => {
568            let dictionary = distinct_values(values);
569            if dictionary.is_empty() {
570                return Ok(None);
571            }
572            let codes = codes_over(values, &dictionary);
573            out.extend_from_slice(&encode_at(&dictionary, depth + 1, chooser)?);
574            out.extend_from_slice(&encode_at(&codes, depth + 1, chooser)?);
575        }
576        Kind::Sparse => {
577            // The majority is the most frequent value whenever there is one, and a chunk the search
578            // offers this for always has one. `encode_only` can ask about any chunk, so the sort is
579            // still there for a chunk with no majority.
580            let Some((value, _)) = majority(values).or_else(|| spread_of(values).1) else {
581                return Ok(None);
582            };
583            let mut positions = Vec::new();
584            let mut exceptions = Vec::new();
585            for (index, other) in values.iter().enumerate() {
586                if *other != value {
587                    positions.push(index as i64);
588                    exceptions.push(*other);
589                }
590            }
591            put_i64(&mut out, value);
592            put_u32(
593                &mut out,
594                u32::try_from(positions.len()).map_err(|_| too_long(positions.len()))?,
595            );
596            out.extend_from_slice(&encode_at(&positions, depth + 1, chooser)?);
597            out.extend_from_slice(&encode_at(&exceptions, depth + 1, chooser)?);
598        }
599        Kind::Strided => {
600            let (Some(base), Some(stride)) = (values.iter().min().copied(), stride_of(values))
601            else {
602                return Ok(None);
603            };
604            let mut steps = Vec::with_capacity(values.len());
605            for value in values {
606                let step = offset_from(*value, base) / stride;
607                // A step count the recursion cannot hold. An offset is at most 65 bits because both
608                // ends came from an `i64`, and only a stride of one leaves it that wide, which is a
609                // stride this never offers. Refused rather than wrapped, because a candidate that
610                // does not apply is one the chooser skips.
611                let Ok(step) = i64::try_from(step) else {
612                    return Ok(None);
613                };
614                steps.push(step);
615            }
616            put_i64(&mut out, base);
617            put_u64(&mut out, stride);
618            out.extend_from_slice(&encode_at(&steps, depth + 1, chooser)?);
619        }
620    }
621    Ok(Some(out))
622}
623
624/// Frame of reference and bit packing, one base and one width per 1024 values.
625///
626/// A base per unit rather than per chunk is most of what makes this work on real columns. A
627/// timestamp column over a day drifts across a range that needs 47 bits, and the same column inside
628/// any one unit spans a few seconds and needs 12. One base per row group would pay the 47 on every
629/// value.
630///
631/// A unit shorter than 1024 values, which is the last one of any chunk whose length is not a
632/// multiple of the unit and is the only one of every short array in a cascade, goes through
633/// [`bitpack::pack_tail`] instead. The transposed layout has no partial form and would charge a
634/// five entry dictionary for 1024 entries.
635fn encode_packed(values: &[i64], out: &mut Vec<u8>) -> Result<()> {
636    // The same three buffers for every unit, for the reason written on `Decoding` on the other side.
637    // The chooser encodes every candidate it is offered before it picks one, so this loop runs more
638    // often on the way in than the decoding loop does on the way out.
639    let mut offsets: Vec<u64> = Vec::with_capacity(VALUES);
640    // Held at the width 64 length for the reason written on `Decoding`, so a narrower unit writes
641    // the front of it and the resize per unit goes away.
642    let mut packed: Vec<u64> = vec![0; bitpack::packed_len::<u64>(64)];
643    let mut transposed = bitpack::Scratch::<u64>::new();
644    for unit in values.chunks(VALUES) {
645        let base = unit.iter().copied().min().unwrap_or(0);
646        offsets.clear();
647        offsets.extend(unit.iter().map(|value| offset_from(*value, base)));
648        let width = bitpack::required_width(&offsets);
649        put_i64(out, base);
650        put_u8(out, u8::try_from(width).map_err(|_| Error::internal("impossible width"))?);
651        if unit.len() == VALUES {
652            let words = bitpack::packed_len::<u64>(width);
653            bitpack::pack_with(&offsets, width, &mut packed[..words], &mut transposed)?;
654            for word in &packed[..words] {
655                put_u64(out, *word);
656            }
657        } else {
658            bitpack::pack_tail(&offsets, width, out)?;
659        }
660    }
661    Ok(())
662}
663
664/// The buffer a decode reuses from one unit of 1024 values to the next.
665///
666/// This used to be allocated inside the loop, and because it was allocated with a value rather than
667/// grown, the allocator zeroed it and then the decode overwrote every byte. In a ClickBench profile
668/// that zeroing was the single largest item, ahead of the unpacking it was making room for, because
669/// a scan pays it once per 1024 rows of every packed integer column it reads.
670///
671/// It is threaded through the recursion rather than made per call because a chunk is a cascade. A
672/// dictionary of deltas is three nested decodes, and each of them would otherwise make its own.
673///
674/// It starts empty and is grown on the first unit that needs it, to its largest size rather than to
675/// the size that unit wants, so that every unit after the first finds it the right length already
676/// and nothing is zeroed or resized again.
677///
678/// There used to be a second buffer here holding one unit of unpacked offsets, which the decode
679/// then walked to add the frame of reference base back on. The unpackers take the base now and
680/// write into the chunk directly, so that buffer and the pass over it are both gone.
681///
682/// It lives on the thread rather than in the caller, which is worth saying why. A chunk is a row
683/// group, and a row group in the native format is about a thousand rows, which is one unit. So there
684/// is no second unit in a chunk to reuse anything and holding this per call is strictly worse than
685/// allocating per unit was: it was tried, and it cost more in the growing than it saved in the
686/// zeroing. What there are many of is chunks, one per part per column, and the thread that reads
687/// them reads them one after another. That is the loop the reuse belongs to, and reaching it by
688/// passing a buffer down would mean a parameter through every page decoder in the storage layer for
689/// a buffer none of them has an opinion about.
690struct Decoding {
691    /// The packed words of one unit, as read off the wire. Held at the width 64 length, which is the
692    /// largest a unit can be, so a narrower unit uses the front of it.
693    packed: Vec<u64>,
694}
695
696thread_local! {
697    /// The buffers this thread decodes through. See [`Decoding`].
698    static DECODING: std::cell::RefCell<Decoding> =
699        const { std::cell::RefCell::new(Decoding::new()) };
700}
701
702/// Runs a decode over this thread's buffers.
703///
704/// Nothing inside a decode calls back into one, so the borrow is never already taken. It is asked
705/// for rather than assumed anyway, and a decode that somehow arrives while another is running gets
706/// buffers of its own rather than a panic, because the alternative is a crash in a reader on a
707/// path nobody exercised.
708fn with_decoding<T>(run: impl FnOnce(&mut Decoding) -> T) -> T {
709    DECODING.with(|cell| match cell.try_borrow_mut() {
710        Ok(mut scratch) => run(&mut scratch),
711        Err(_) => run(&mut Decoding::new()),
712    })
713}
714
715impl Decoding {
716    /// A buffer that has not made room for anything yet.
717    const fn new() -> Self {
718        Self { packed: Vec::new() }
719    }
720
721    /// Makes room for one unit. A no op every time after the first.
722    fn ready(&mut self) {
723        if self.packed.len() != bitpack::packed_len::<u64>(64) {
724            self.packed.resize(bitpack::packed_len::<u64>(64), 0);
725        }
726    }
727}
728
729fn decode_chunk(reader: &mut Reader<'_>, scratch: &mut Decoding) -> Result<Vec<i64>> {
730    let kind = Kind::from_tag(reader.u8()?)?;
731    let count = reader.u32()? as usize;
732    match kind {
733        Kind::Constant => Ok(vec![reader.i64()?; count]),
734        Kind::Packed => {
735            // One buffer for the chunk, and every value written into it once. Both unpackers take
736            // the frame of reference base and put the value it belongs to where it goes, so there
737            // is no unit of raw offsets in between and no second pass to fold the base back in.
738            let mut values = vec![0i64; count];
739            scratch.ready();
740            let mut done = 0;
741            while done < count {
742                let base = reader.i64()?;
743                let width = reader.u8()? as usize;
744                let wanted = (count - done).min(VALUES);
745                let into = &mut values[done..done + wanted];
746                if wanted == VALUES {
747                    let words = bitpack::packed_len::<u64>(width);
748                    for word in &mut scratch.packed[..words] {
749                        *word = reader.u64()?;
750                    }
751                    bitpack::unpack_mapped(&scratch.packed[..words], width, into, |offset| {
752                        value_from(offset, base)
753                    })?;
754                } else {
755                    let bytes = reader.bytes(bitpack::tail_len(wanted, width))?;
756                    bitpack::unpack_tail_into(bytes, width, into, |offset| {
757                        value_from(offset, base)
758                    })?;
759                }
760                done += wanted;
761            }
762            Ok(values)
763        }
764        Kind::Delta => {
765            let first = reader.i64()?;
766            let deltas = decode_chunk(reader, scratch)?;
767            let mut values = Vec::with_capacity(count);
768            values.push(first);
769            let mut current = first;
770            for delta in deltas {
771                current = current.wrapping_add(unzigzag(delta as u64));
772                values.push(current);
773            }
774            check_count(values.len(), count)?;
775            Ok(values)
776        }
777        Kind::Rle => {
778            let run_values = decode_chunk(reader, scratch)?;
779            let run_lengths = decode_chunk(reader, scratch)?;
780            if run_values.len() != run_lengths.len() {
781                return Err(Error::internal("an RLE chunk has more runs than run lengths"));
782            }
783            // A chunk whose runs are long on average, the way a sorted column's are thousands of
784            // rows each, has every run appended into reserved room, so that each value is written
785            // once by the run it belongs to. Zeroing the chunk first was a second write of all of
786            // it. Short runs are cheaper the other way, with room for one run past the end so that
787            // the write below never has to ask how much of its fixed width landed inside the chunk,
788            // and appending those cost a few percent more on ClickBench 15, 17 and 31.
789            let long = run_values.len().saturating_mul(LONG_RUN) <= count;
790            let mut values = if long { Vec::with_capacity(count) } else { vec![0; count + RUN] };
791            let mut at = 0usize;
792            for (value, length) in run_values.into_iter().zip(run_lengths) {
793                let length = usize::try_from(length)
794                    .map_err(|_| Error::internal("a negative RLE run length"))?;
795                let end = at
796                    .checked_add(length)
797                    .filter(|end| *end <= count)
798                    .ok_or_else(|| Error::internal("an RLE run ends past its chunk"))?;
799                if long {
800                    values.resize(end, value);
801                } else {
802                    let short =
803                        if length <= RUN { values[at..].first_chunk_mut::<RUN>() } else { None };
804                    match short {
805                        Some(window) => window.fill(value),
806                        None => values[at..end].fill(value),
807                    }
808                }
809                at = end;
810            }
811            check_count(at, count)?;
812            values.truncate(count);
813            Ok(values)
814        }
815        Kind::Dict => {
816            let dictionary = decode_chunk(reader, scratch)?;
817            let codes = decode_chunk(reader, scratch)?;
818            let mut values = Vec::with_capacity(count);
819            for code in codes {
820                let index =
821                    usize::try_from(code).ok().and_then(|index| dictionary.get(index)).ok_or_else(
822                        || Error::internal(format!("code {code} is not in the dictionary")),
823                    )?;
824                values.push(*index);
825            }
826            check_count(values.len(), count)?;
827            Ok(values)
828        }
829        Kind::Sparse => {
830            let value = reader.i64()?;
831            let exception_count = reader.u32()? as usize;
832            let positions = decode_chunk(reader, scratch)?;
833            let exceptions = decode_chunk(reader, scratch)?;
834            if positions.len() != exception_count || exceptions.len() != exception_count {
835                return Err(Error::internal("a sparse chunk disagrees about its exception count"));
836            }
837            let mut values = vec![value; count];
838            for (position, exception) in positions.into_iter().zip(exceptions) {
839                let position = usize::try_from(position)
840                    .ok()
841                    .filter(|position| *position < count)
842                    .ok_or_else(|| {
843                        Error::internal(format!("exception at {position} is outside the chunk"))
844                    })?;
845                values[position] = exception;
846            }
847            Ok(values)
848        }
849        Kind::Strided => {
850            let base = reader.i64()?;
851            let stride = reader.u64()?;
852            let steps = decode_chunk(reader, scratch)?;
853            check_count(steps.len(), count)?;
854            let mut values = Vec::with_capacity(count);
855            for step in steps {
856                let step = u64::try_from(step)
857                    .map_err(|_| Error::internal("a negative number of strides"))?;
858                values.push(value_from(step.wrapping_mul(stride), base));
859            }
860            Ok(values)
861        }
862    }
863}
864
865fn decode_selected_chunk(
866    reader: &mut Reader<'_>,
867    positions: &[usize],
868    scratch: &mut Decoding,
869) -> Result<Vec<i64>> {
870    let Some(&tag) = reader.rest().first() else {
871        return Err(Error::internal("a chunk ended before its encoding tag"));
872    };
873    let kind = Kind::from_tag(tag)?;
874    if !matches!(kind, Kind::Constant | Kind::Packed | Kind::Rle) {
875        let values = decode_chunk(reader, scratch)?;
876        return positions
877            .iter()
878            .map(|&position| {
879                values.get(position).copied().ok_or_else(|| {
880                    Error::internal(format!(
881                        "selected integer position {position} is outside {} values",
882                        values.len()
883                    ))
884                })
885            })
886            .collect();
887    }
888
889    let decoded = Kind::from_tag(reader.u8()?)?;
890    debug_assert_eq!(decoded, kind);
891    let count = reader.u32()? as usize;
892    if positions.last().is_some_and(|&position| position >= count) {
893        return Err(Error::internal(format!(
894            "selected integer position {} is outside {count} values",
895            positions.last().expect("a last position exists")
896        )));
897    }
898    match kind {
899        Kind::Constant => {
900            let value = reader.i64()?;
901            Ok(vec![value; positions.len()])
902        }
903        Kind::Packed => {
904            let mut out = Vec::with_capacity(positions.len());
905            let mut from = 0;
906            let mut done = 0;
907            while done < count {
908                let base = reader.i64()?;
909                let width = reader.u8()? as usize;
910                let wanted = (count - done).min(VALUES);
911                let upto = positions.partition_point(|&position| position < done + wanted);
912                if wanted == VALUES {
913                    let bytes = reader.bytes(bitpack::packed_len::<u64>(width) * 8)?;
914                    for &position in &positions[from..upto] {
915                        let offset = bitpack::unpack_u64_at(bytes, width, position - done)?;
916                        out.push(value_from(offset, base));
917                    }
918                } else {
919                    let bytes = reader.bytes(bitpack::tail_len(wanted, width))?;
920                    for &position in &positions[from..upto] {
921                        let offset = bitpack::tail_at(bytes, width, position - done)?;
922                        out.push(value_from(offset, base));
923                    }
924                }
925                from = upto;
926                done += wanted;
927            }
928            Ok(out)
929        }
930        Kind::Rle => {
931            let run_value_bytes = reader.rest();
932            let mut run_value_reader = Reader::new(run_value_bytes);
933            let run_value_count = skip_chunk(&mut run_value_reader)?;
934            let run_value_len = run_value_reader.used();
935            reader.skip(run_value_len)?;
936            let run_lengths = decode_chunk(reader, scratch)?;
937            if run_value_count != run_lengths.len() {
938                return Err(Error::internal("an RLE chunk has more runs than run lengths"));
939            }
940            let mut wanted_runs = Vec::new();
941            let mut selected_per_run = Vec::new();
942            let mut selected = 0;
943            let mut at = 0usize;
944            for (run, length) in run_lengths.into_iter().enumerate() {
945                let length = usize::try_from(length)
946                    .map_err(|_| Error::internal("a negative RLE run length"))?;
947                let end = at
948                    .checked_add(length)
949                    .filter(|end| *end <= count)
950                    .ok_or_else(|| Error::internal("an RLE run ends past its chunk"))?;
951                let before = selected;
952                while selected < positions.len() && positions[selected] < end {
953                    if positions[selected] < at {
954                        return Err(Error::internal("selected integer positions went backwards"));
955                    }
956                    selected += 1;
957                }
958                if selected != before {
959                    wanted_runs.push(run);
960                    selected_per_run.push(selected - before);
961                }
962                at = end;
963            }
964            check_count(at, count)?;
965            if selected != positions.len() {
966                return Err(Error::internal("an RLE chunk ended before a selected position"));
967            }
968            let run_values = decode_selected(&run_value_bytes[..run_value_len], &wanted_runs)?;
969            let mut out = Vec::with_capacity(positions.len());
970            for (value, repeat) in run_values.into_iter().zip(selected_per_run) {
971                out.extend(std::iter::repeat_n(value, repeat));
972            }
973            Ok(out)
974        }
975        _ => unreachable!("unsupported kinds used the full decoder"),
976    }
977}
978
979/// Advances over one encoded chunk without materializing its values and returns its row count.
980fn skip_chunk(reader: &mut Reader<'_>) -> Result<usize> {
981    let kind = Kind::from_tag(reader.u8()?)?;
982    let count = reader.u32()? as usize;
983    match kind {
984        Kind::Constant => reader.skip(8)?,
985        Kind::Packed => skip_packed(reader, count)?,
986        Kind::Delta => {
987            reader.skip(8)?;
988            skip_chunk(reader)?;
989        }
990        Kind::Rle | Kind::Dict => {
991            skip_chunk(reader)?;
992            skip_chunk(reader)?;
993        }
994        Kind::Sparse => {
995            reader.skip(12)?;
996            skip_chunk(reader)?;
997            skip_chunk(reader)?;
998        }
999        Kind::Strided => {
1000            reader.skip(16)?;
1001            skip_chunk(reader)?;
1002        }
1003    }
1004    Ok(count)
1005}
1006
1007/// Advances over the units of a `Packed` body of `count` values.
1008fn skip_packed(reader: &mut Reader<'_>, count: usize) -> Result<()> {
1009    let mut done = 0;
1010    while done < count {
1011        reader.skip(8)?;
1012        let width = reader.u8()? as usize;
1013        if width > 64 {
1014            return Err(Error::internal(format!("a packed integer width of {width} is past 64")));
1015        }
1016        let wanted = (count - done).min(VALUES);
1017        let bytes = if wanted == VALUES {
1018            bitpack::packed_len::<u64>(width)
1019                .checked_mul(8)
1020                .ok_or_else(|| Error::internal("packed integer size overflow"))?
1021        } else {
1022            bitpack::tail_len(wanted, width)
1023        };
1024        reader.skip(bytes)?;
1025        done += wanted;
1026    }
1027    Ok(())
1028}
1029
1030/// [`shape`] for one chunk and everything inside it.
1031fn shape_chunk(reader: &mut Reader<'_>, kinds: &mut Vec<Kind>) -> Result<()> {
1032    let kind = Kind::from_tag(reader.u8()?)?;
1033    let count = reader.u32()? as usize;
1034    kinds.push(kind);
1035    match kind {
1036        Kind::Constant => reader.skip(8)?,
1037        Kind::Packed => skip_packed(reader, count)?,
1038        Kind::Delta => {
1039            reader.skip(8)?;
1040            shape_chunk(reader, kinds)?;
1041        }
1042        Kind::Rle | Kind::Dict => {
1043            shape_chunk(reader, kinds)?;
1044            shape_chunk(reader, kinds)?;
1045        }
1046        Kind::Sparse => {
1047            reader.skip(12)?;
1048            shape_chunk(reader, kinds)?;
1049            shape_chunk(reader, kinds)?;
1050        }
1051        Kind::Strided => {
1052            reader.skip(16)?;
1053            shape_chunk(reader, kinds)?;
1054        }
1055    }
1056    Ok(())
1057}
1058
1059fn describe_chunk(reader: &mut Reader<'_>) -> Result<String> {
1060    let kind = Kind::from_tag(reader.u8()?)?;
1061    let count = reader.u32()? as usize;
1062    Ok(match kind {
1063        Kind::Constant => {
1064            reader.i64()?;
1065            "CONSTANT".to_string()
1066        }
1067        Kind::Packed => {
1068            let mut widths = Vec::new();
1069            let mut seen = 0;
1070            while seen < count {
1071                reader.i64()?;
1072                let width = reader.u8()? as usize;
1073                let wanted = (count - seen).min(VALUES);
1074                if wanted == VALUES {
1075                    for _ in 0..bitpack::packed_len::<u64>(width) {
1076                        reader.u64()?;
1077                    }
1078                } else {
1079                    reader.bytes(bitpack::tail_len(wanted, width))?;
1080                }
1081                widths.push(width);
1082                seen += wanted;
1083            }
1084            let low = widths.iter().copied().min().unwrap_or(0);
1085            let high = widths.iter().copied().max().unwrap_or(0);
1086            // Square brackets rather than round ones, so that a reader and a test can both take a
1087            // parenthesis to mean one more level of cascade and nothing else.
1088            if low == high {
1089                format!("FOR+BITPACK[{low}]")
1090            } else {
1091                format!("FOR+BITPACK[{low}..{high}]")
1092            }
1093        }
1094        Kind::Delta => {
1095            reader.i64()?;
1096            format!("DELTA({})", describe_chunk(reader)?)
1097        }
1098        Kind::Rle => {
1099            let values = describe_chunk(reader)?;
1100            let lengths = describe_chunk(reader)?;
1101            format!("RLE({values}, {lengths})")
1102        }
1103        Kind::Dict => {
1104            let dictionary = describe_chunk(reader)?;
1105            let codes = describe_chunk(reader)?;
1106            format!("DICT({dictionary}, {codes})")
1107        }
1108        Kind::Sparse => {
1109            reader.i64()?;
1110            reader.u32()?;
1111            let positions = describe_chunk(reader)?;
1112            let exceptions = describe_chunk(reader)?;
1113            format!("SPARSE({positions}, {exceptions})")
1114        }
1115        Kind::Strided => {
1116            reader.i64()?;
1117            let stride = reader.u64()?;
1118            format!("STRIDE[{stride}]({})", describe_chunk(reader)?)
1119        }
1120    })
1121}
1122
1123/// The step every value of the chunk is a whole number of, or `None` when there is not one worth
1124/// having.
1125///
1126/// This is the greatest common divisor of every value's distance from the smallest one. A timestamp
1127/// column loaded from a source that recorded whole seconds holds microseconds that are all multiples
1128/// of a million, and without this the frame of reference pays twenty bits a value to write down the
1129/// twenty zero bits at the bottom of every one of them.
1130///
1131/// The walk stops the moment the divisor reaches one, which is what makes this affordable to ask on
1132/// every chunk. Two values that share no factor are enough to answer, and on a column of arbitrary
1133/// numbers that is almost always the first pair.
1134fn stride_of(values: &[i64]) -> Option<u64> {
1135    stride_from(values, values.iter().min().copied()?)
1136}
1137
1138/// [`stride_of`] for a chunk whose smallest value is already known.
1139fn stride_from(values: &[i64], base: i64) -> Option<u64> {
1140    let mut divisor = 0u64;
1141    for value in values {
1142        divisor = gcd(divisor, offset_from(*value, base));
1143        if divisor == 1 {
1144            return None;
1145        }
1146    }
1147    // Zero is every value being the base, which `Constant` already holds for nothing, and one is
1148    // the frame of reference on its own with two extra words of header.
1149    (divisor > 1).then_some(divisor)
1150}
1151
1152/// Binary GCD, which is the one without a division in it.
1153fn gcd(mut left: u64, mut right: u64) -> u64 {
1154    if left == 0 {
1155        return right;
1156    }
1157    if right == 0 {
1158        return left;
1159    }
1160    let shift = (left | right).trailing_zeros();
1161    left >>= left.trailing_zeros();
1162    loop {
1163        right >>= right.trailing_zeros();
1164        if left > right {
1165            std::mem::swap(&mut left, &mut right);
1166        }
1167        right -= left;
1168        if right == 0 {
1169            return left << shift;
1170        }
1171    }
1172}
1173
1174/// The distance from the frame of reference base, which is always representable in a `u64` because
1175/// both ends came from an `i64` and the width of the difference is at most 65 bits minus the sign.
1176fn offset_from(value: i64, base: i64) -> u64 {
1177    (i128::from(value) - i128::from(base)) as u64
1178}
1179
1180fn value_from(offset: u64, base: i64) -> i64 {
1181    (i128::from(base) + i128::from(offset)) as i64
1182}
1183
1184/// Zigzag, so that a column that counts down packs as narrowly as one that counts up. Without it a
1185/// delta of -1 is 64 bits of ones.
1186fn zigzag(value: i64) -> u64 {
1187    ((value << 1) ^ (value >> 63)) as u64
1188}
1189
1190fn unzigzag(value: u64) -> i64 {
1191    ((value >> 1) as i64) ^ -((value & 1) as i64)
1192}
1193
1194/// The zigzagged differences, or `None` if any difference is too wide to be one.
1195///
1196/// A column holding both `i64::MIN` and `i64::MAX` has a difference that does not fit in an `i64`,
1197/// and rather than widening every delta array to 128 bits for a case that does not occur in data,
1198/// the encoding declines to apply. `Packed` covers it.
1199/// Whether every neighbouring difference fits in an `i64`, which is the only thing the candidate
1200/// list needs to know about deltas.
1201///
1202/// The candidate list used to answer this by building the whole delta array and checking that it
1203/// came back, which is an allocation and a pass over the chunk thrown away on every chunk, and then
1204/// `Kind::Delta` built it again. This is the same pass with nothing kept.
1205fn deltas_fit(values: &[i64]) -> bool {
1206    values.windows(2).all(|pair| pair[1].checked_sub(pair[0]).is_some())
1207}
1208
1209fn deltas(values: &[i64]) -> Option<Vec<i64>> {
1210    let mut deltas = Vec::with_capacity(values.len().saturating_sub(1));
1211    for pair in values.windows(2) {
1212        let difference = pair[1].checked_sub(pair[0])?;
1213        deltas.push(zigzag(difference) as i64);
1214    }
1215    Some(deltas)
1216}
1217
1218/// The value and the length of every run of equal neighbours.
1219///
1220/// Each run is found by walking to its end and pushed once. This used to push the first value of a
1221/// run and then add one to the last length for every value after it, which kept both vectors'
1222/// lengths in memory across the whole loop and was the hottest loop left in `encode_at` once the
1223/// candidate tests became one pass.
1224fn runs(values: &[i64]) -> (Vec<i64>, Vec<i64>) {
1225    let mut run_values: Vec<i64> = Vec::new();
1226    let mut run_lengths: Vec<i64> = Vec::new();
1227    let mut start = 0;
1228    while let Some(&value) = values.get(start) {
1229        let length = values[start..].iter().take_while(|other| **other == value).count();
1230        run_values.push(value);
1231        run_lengths.push(length as i64);
1232        start += length;
1233    }
1234    (run_values, run_lengths)
1235}
1236
1237/// The distinct values in sorted order.
1238///
1239/// Sorted rather than in order of first appearance, because an ordered dictionary is what lets a
1240/// range predicate become a code range instead of a code set, per section 6.7, and because the
1241/// codes of a clustered column then run in order and delta encode.
1242/// How many distinct values there are and which one occurs most often, from one sort.
1243///
1244/// Both questions are about the histogram of the chunk and neither needs the histogram itself, so
1245/// one sorted copy and one walk over it answers both. They used to be two functions that each sorted
1246/// their own copy and threw it away, which is a chunk sorted twice on every chunk at every level of
1247/// the cascade before a single candidate has been encoded.
1248///
1249/// No hash map, because the sort is what makes the walk a scan of equal runs, and a hash map would
1250/// pay a lookup per value to learn the same thing.
1251fn spread_of(values: &[i64]) -> (usize, Option<(i64, usize)>) {
1252    let mut sorted = values.to_vec();
1253    sorted.sort_unstable();
1254    let mut distinct = 0;
1255    let mut best: Option<(i64, usize)> = None;
1256    let mut index = 0;
1257    while index < sorted.len() {
1258        let value = sorted[index];
1259        let mut end = index;
1260        while end < sorted.len() && sorted[end] == value {
1261            end += 1;
1262        }
1263        distinct += 1;
1264        let count = end - index;
1265        if best.is_none_or(|(_, seen)| count > seen) {
1266            best = Some((value, count));
1267        }
1268        index = end;
1269    }
1270    (distinct, best)
1271}
1272
1273/// The value more than half of the chunk holds, and how many times, found in two passes without
1274/// sorting anything.
1275///
1276/// This is the vote that keeps one candidate and a lead: a value that holds more than half the
1277/// chunk outlasts every other value put together, so it is the candidate left at the end, and the
1278/// second pass checks that the candidate really does hold more than half. When it does it is the
1279/// value [`spread_of`] would name as the most frequent, since a value over half the chunk has no tie.
1280fn majority(values: &[i64]) -> Option<(i64, usize)> {
1281    let mut candidate = *values.first()?;
1282    let mut lead = 0usize;
1283    for value in values {
1284        if lead == 0 {
1285            candidate = *value;
1286            lead = 1;
1287        } else if *value == candidate {
1288            lead += 1;
1289        } else {
1290            lead -= 1;
1291        }
1292    }
1293    let count = values.iter().filter(|value| **value == candidate).count();
1294    (count * 2 > values.len()).then_some((candidate, count))
1295}
1296
1297/// The distinct values in sorted order, for the same reason the string dictionary is sorted: an
1298/// ordered dictionary turns a range predicate into a code range rather than a code set.
1299fn distinct_values(values: &[i64]) -> Vec<i64> {
1300    let mut distinct = values.to_vec();
1301    distinct.sort_unstable();
1302    distinct.dedup();
1303    distinct
1304}
1305
1306/// Where each value sits in the dictionary.
1307///
1308/// The string side builds its dictionary and its codes together from one sort of a permutation,
1309/// because the alternative there is a copy of every value onto the heap and a `memcmp` per level of
1310/// a binary search per row. This side was changed to match and it measured slower, so it was changed
1311/// back. An integer dictionary only exists when the distinct count is at most half the row count, so
1312/// the search is over something small and cache resident, the comparison is one integer rather than
1313/// a string, and carrying the source index through the sort means sorting a padded sixteen byte pair
1314/// instead of an eight byte value. The search is cheaper than the wider sort.
1315fn codes_over(values: &[i64], dictionary: &[i64]) -> Vec<i64> {
1316    values
1317        .iter()
1318        .map(|value| {
1319            dictionary
1320                .binary_search(value)
1321                .expect("the dictionary is the distinct values of this chunk") as i64
1322        })
1323        .collect()
1324}
1325
1326fn check_count(actual: usize, expected: usize) -> Result<()> {
1327    if actual == expected {
1328        Ok(())
1329    } else {
1330        Err(Error::internal(format!(
1331            "a chunk says it holds {expected} values and decoded to {actual}"
1332        )))
1333    }
1334}
1335
1336fn too_long(len: usize) -> Error {
1337    Error::internal(format!("a chunk of {len} values is longer than the format allows"))
1338}
1339
1340fn put_u8(out: &mut Vec<u8>, value: u8) {
1341    out.push(value);
1342}
1343
1344fn put_u32(out: &mut Vec<u8>, value: u32) {
1345    out.extend_from_slice(&value.to_le_bytes());
1346}
1347
1348fn put_u64(out: &mut Vec<u8>, value: u64) {
1349    out.extend_from_slice(&value.to_le_bytes());
1350}
1351
1352fn put_i64(out: &mut Vec<u8>, value: i64) {
1353    out.extend_from_slice(&value.to_le_bytes());
1354}
1355
1356#[cfg(test)]
1357mod tests {
1358    use super::*;
1359
1360    fn round_trip(values: &[i64]) -> Vec<u8> {
1361        let bytes = encode(values).unwrap();
1362        assert_eq!(decode(&bytes).unwrap(), values, "{}", describe(&bytes).unwrap());
1363        bytes
1364    }
1365
1366    fn kind_of(bytes: &[u8]) -> Kind {
1367        Kind::from_tag(bytes[0]).unwrap()
1368    }
1369
1370    /// The same xorshift the bit packing tests use, for the same reason.
1371    struct Random(u64);
1372
1373    impl Random {
1374        fn new() -> Self {
1375            Self(0x9e37_79b9_7f4a_7c15)
1376        }
1377
1378        fn next(&mut self) -> u64 {
1379            self.0 ^= self.0 << 13;
1380            self.0 ^= self.0 >> 7;
1381            self.0 ^= self.0 << 17;
1382            self.0
1383        }
1384    }
1385
1386    #[test]
1387    fn the_dictionary_is_sorted_and_the_codes_point_back_at_the_values() {
1388        let values = vec![30i64, 10, 30, 20, 10, -5];
1389        let dictionary = distinct_values(&values);
1390        let codes = codes_over(&values, &dictionary);
1391        assert_eq!(dictionary, vec![-5, 10, 20, 30]);
1392        assert_eq!(codes, vec![3, 1, 3, 2, 1, 0]);
1393        for (code, value) in codes.iter().zip(&values) {
1394            assert_eq!(dictionary[*code as usize], *value);
1395        }
1396    }
1397
1398    #[test]
1399    fn one_sort_gives_the_distinct_count_and_the_most_frequent_value() {
1400        let values = vec![7i64, 7, 7, 1, 2, 2];
1401        assert_eq!(spread_of(&values), (3, Some((7, 3))));
1402        assert_eq!(spread_of(&[]), (0, None));
1403        assert_eq!(spread_of(&[9]), (1, Some((9, 1))));
1404
1405        // A tie goes to the value that sorts first, which is arbitrary but has to be stable,
1406        // because Sparse writes the dominant value into the chunk and the size depends on it.
1407        assert_eq!(spread_of(&[4i64, 4, 8, 8]), (2, Some((4, 2))));
1408    }
1409
1410    #[test]
1411    fn the_majority_is_the_most_frequent_value_whenever_there_is_one() {
1412        let chunks: Vec<Vec<i64>> = vec![
1413            vec![],
1414            vec![3],
1415            vec![1, 2],
1416            vec![1, 1, 2],
1417            vec![2, 1, 1],
1418            vec![4, 4, 8, 8],
1419            vec![7, 1, 7, 2, 7, 3, 7],
1420            vec![1, 2, 3, 9, 9, 9, 9],
1421            (0..1000).map(|index| if index % 5 == 0 { index } else { -4 }).collect(),
1422            (0..1000).map(|index| index % 3).collect(),
1423        ];
1424        for chunk in chunks {
1425            let (_, dominant) = spread_of(&chunk);
1426            let expected = dominant.filter(|(_, count)| count * 2 > chunk.len());
1427            assert_eq!(majority(&chunk), expected, "{chunk:?}");
1428        }
1429    }
1430
1431    /// The one pass offers exactly what the separate tests offered, including on the chunks where
1432    /// the shortcuts in it are the whole answer: a range too wide for an `i64`, and a chunk with too
1433    /// many runs to have a value in four rows out of five.
1434    #[test]
1435    fn the_one_pass_offers_what_the_separate_tests_offered() {
1436        let mut random = Random::new();
1437        let mut chunks: Vec<Vec<i64>> = vec![
1438            vec![],
1439            vec![5],
1440            vec![5, 5, 5],
1441            vec![i64::MIN, i64::MAX],
1442            vec![i64::MAX, i64::MIN, i64::MAX],
1443            vec![i64::MIN, 0, i64::MAX],
1444            vec![-1, i64::MAX],
1445            (0..1000).map(|index| if index % 5 == 0 { index } else { -4 }).collect(),
1446            (0..1000).map(|index| if index % 4 == 0 { index } else { -4 }).collect(),
1447            (0..1000).map(|index| index / 7).collect(),
1448            (0..1000).map(|index| index * 1_000_000).collect(),
1449        ];
1450        for _ in 0..200 {
1451            let len = (random.next() % 300) as usize;
1452            let spread = 1 + random.next() % 8;
1453            let common = (random.next() % 5) as i64;
1454            chunks.push(
1455                (0..len)
1456                    .map(|_| {
1457                        let draw = random.next();
1458                        if draw % 10 < spread { (draw >> 8) as i64 % 50 } else { common }
1459                    })
1460                    .collect(),
1461            );
1462        }
1463        for chunk in chunks {
1464            let mut expected = vec![Kind::Packed];
1465            if !chunk.is_empty() {
1466                if chunk.iter().all(|value| *value == chunk[0]) {
1467                    expected = vec![Kind::Constant];
1468                } else {
1469                    if chunk.len() >= 2 && deltas_fit(&chunk) {
1470                        expected.push(Kind::Delta);
1471                    }
1472                    let runs = 1 + chunk.windows(2).filter(|pair| pair[0] != pair[1]).count();
1473                    if runs * 4 <= chunk.len() * 3 {
1474                        expected.push(Kind::Rle);
1475                    }
1476                    if spread_of(&chunk).0 * 2 <= chunk.len() {
1477                        expected.push(Kind::Dict);
1478                    }
1479                    if majority(&chunk).is_some_and(|(_, count)| count * 10 >= chunk.len() * 8) {
1480                        expected.push(Kind::Sparse);
1481                    }
1482                    if stride_of(&chunk).is_some() {
1483                        expected.push(Kind::Strided);
1484                    }
1485                }
1486            }
1487            assert_eq!(candidates(&chunk, 0, &EXHAUSTIVE), expected, "{chunk:?}");
1488        }
1489    }
1490
1491    #[test]
1492    fn runs_are_every_stretch_of_equal_neighbours_in_order() {
1493        assert_eq!(runs(&[]), (vec![], vec![]));
1494        assert_eq!(runs(&[4]), (vec![4], vec![1]));
1495        assert_eq!(runs(&[1, 1, 2, 1, 1, 1]), (vec![1, 2, 1], vec![2, 1, 3]));
1496    }
1497
1498    #[test]
1499    fn deltas_that_do_not_fit_are_refused_before_they_are_built() {
1500        assert!(deltas_fit(&[1i64, 2, 3]));
1501        assert!(deltas_fit(&[i64::MAX, i64::MAX]));
1502        assert!(!deltas_fit(&[i64::MIN, i64::MAX]));
1503        assert_eq!(deltas_fit(&[i64::MIN, i64::MAX]), deltas(&[i64::MIN, i64::MAX]).is_some());
1504        assert_eq!(deltas_fit(&[1i64, 2, 3]), deltas(&[1i64, 2, 3]).is_some());
1505    }
1506
1507    #[test]
1508    fn what_the_chooser_returns_is_the_smallest_of_what_it_was_offered() {
1509        // `offered` and `encode_only` are what `cargo xtask encode` splits the chooser's seconds
1510        // with, so they have to describe the chooser that actually runs rather than a second copy
1511        // of its rules that drifts. This is the assertion that keeps the two the same thing.
1512        let mut random = Random::new();
1513        let noise: Vec<i64> = (0..2000).map(|_| (random.next() % 5000) as i64).collect();
1514        let runs: Vec<i64> = (0..2000).map(|index: i64| index / 100).collect();
1515        let climbing: Vec<i64> = (0..2000).map(|index| 1_700_000_000 + index).collect();
1516        for values in [noise, runs, climbing, vec![7; 300], Vec::new()] {
1517            let chosen = encode(&values).unwrap();
1518            let mut smallest: Option<Vec<u8>> = None;
1519            for kind in offered(&values) {
1520                let Some(bytes) = encode_only(kind, &values).unwrap() else {
1521                    continue;
1522                };
1523                if smallest.as_ref().is_none_or(|best| bytes.len() < best.len()) {
1524                    smallest = Some(bytes);
1525                }
1526            }
1527            assert_eq!(smallest.as_deref(), Some(chosen.as_slice()), "{}", values.len());
1528        }
1529    }
1530
1531    #[test]
1532    fn a_column_of_whole_seconds_in_microseconds_pays_nothing_for_the_zeroes() {
1533        // What three ClickBench columns are. `epoch_ms(EventTime * 1000)` on a source that recorded
1534        // whole seconds gives microseconds with twenty zero bits under every value, and a frame of
1535        // reference over a part that spans a working day needs 36 bits to write them down.
1536        let mut random = Random::new();
1537        let day = 1_374_000_000_000_000i64;
1538        let values: Vec<i64> =
1539            (0..100_000).map(|_| day + (random.next() % 68_400) as i64 * 1_000_000).collect();
1540        let bytes = round_trip(&values);
1541        assert_eq!(kind_of(&bytes), Kind::Strided);
1542        assert!(describe(&bytes).unwrap().starts_with("STRIDE[1000000]"), "{:?}", describe(&bytes));
1543        // 17 bits a value for the range of seconds, against the 36 the microseconds need.
1544        let strided = 100_000 * 17 / 8;
1545        assert!(bytes.len() < strided + 2000, "{} bytes for {strided} of payload", bytes.len());
1546
1547        let plain = encode_only(Kind::Packed, &values).unwrap().expect("packing always applies");
1548        assert!(
1549            bytes.len() * 2 < plain.len(),
1550            "{} strided against {} packed",
1551            bytes.len(),
1552            plain.len()
1553        );
1554    }
1555
1556    #[test]
1557    fn a_stride_is_the_common_factor_of_the_distances_from_the_smallest_value() {
1558        assert_eq!(stride_of(&[10i64, 20, 40]), Some(10));
1559        // The base is the smallest value and not zero, so a column that does not start on a
1560        // multiple of its own step still has one.
1561        assert_eq!(stride_of(&[7i64, 17, 37]), Some(10));
1562        assert_eq!(stride_of(&[10i64, 20, 23]), None);
1563        // Every value the same is `Constant`'s case and this declines it rather than dividing by a
1564        // stride of zero.
1565        assert_eq!(stride_of(&[5i64; 100]), None);
1566        assert_eq!(stride_of(&[]), None);
1567        // The two ends of the type, where the distance needs 65 bits and only a `u64` holds it.
1568        assert_eq!(stride_of(&[i64::MIN, i64::MAX]), Some(u64::MAX));
1569    }
1570
1571    #[test]
1572    fn a_stride_across_the_whole_of_the_type_round_trips() {
1573        // The distance is 65 bits, so the step count is one and the offset it comes back as is a
1574        // number no `i64` holds. This is the arithmetic the encoder has to do in `u64`.
1575        for values in [vec![i64::MIN, i64::MAX], vec![i64::MIN, 0, i64::MAX]] {
1576            let bytes = round_trip(&values);
1577            assert_eq!(decode(&bytes).unwrap(), values);
1578        }
1579    }
1580
1581    #[test]
1582    fn a_column_with_no_common_factor_is_not_offered_a_stride() {
1583        let mut random = Random::new();
1584        let values: Vec<i64> = (0..2000).map(|_| (random.next() % 1_000_000) as i64).collect();
1585        assert!(!offered(&values).contains(&Kind::Strided));
1586        assert!(encode_only(Kind::Strided, &values).unwrap().is_none());
1587    }
1588
1589    #[test]
1590    fn an_empty_chunk_round_trips() {
1591        let bytes = round_trip(&[]);
1592        assert_eq!(bytes.len(), 5);
1593    }
1594
1595    #[test]
1596    fn a_constant_column_costs_thirteen_bytes_however_long_it_is() {
1597        let bytes = round_trip(&vec![42; 1_000_000]);
1598        assert_eq!(kind_of(&bytes), Kind::Constant);
1599        assert_eq!(bytes.len(), 13);
1600    }
1601
1602    #[test]
1603    fn a_narrow_range_is_packed_at_the_width_of_the_range_and_not_of_the_type() {
1604        // 100_000 values between 1000 and 1063 is 6 bits each, plus 9 bytes of header per 1024.
1605        let mut random = Random::new();
1606        let values: Vec<i64> = (0..100_000).map(|_| 1000 + (random.next() % 64) as i64).collect();
1607        let bytes = round_trip(&values);
1608        assert_eq!(kind_of(&bytes), Kind::Packed);
1609        let packed = 100_000 * 6 / 8;
1610        assert!(bytes.len() < packed + 2000, "{} bytes for {packed} of payload", bytes.len());
1611        assert!(bytes.len() > packed, "{} bytes cannot hold {packed}", bytes.len());
1612    }
1613
1614    #[test]
1615    fn a_counter_becomes_deltas_and_then_a_constant() {
1616        // The classic case and the reason DELTA exists. A million consecutive integers is a
1617        // difference of 1 a million times, which is a constant chunk under the delta.
1618        let values: Vec<i64> = (0..1_000_000).collect();
1619        let bytes = round_trip(&values);
1620        assert_eq!(kind_of(&bytes), Kind::Delta);
1621        assert_eq!(describe(&bytes).unwrap(), "DELTA(CONSTANT)");
1622        assert!(bytes.len() < 40, "{} bytes for a counter", bytes.len());
1623    }
1624
1625    #[test]
1626    fn a_column_that_counts_down_is_as_cheap_as_one_that_counts_up() {
1627        // What zigzag is for. Without it every delta is -1, which is 64 bits of ones.
1628        let up: Vec<i64> = (0..100_000).collect();
1629        let down: Vec<i64> = (0..100_000).rev().collect();
1630        assert_eq!(round_trip(&up).len(), round_trip(&down).len());
1631    }
1632
1633    #[test]
1634    fn long_runs_become_rle() {
1635        let mut values = Vec::new();
1636        for run in 0..1000 {
1637            values.extend(std::iter::repeat_n(run % 7, 200));
1638        }
1639        let bytes = round_trip(&values);
1640        assert_eq!(kind_of(&bytes), Kind::Rle);
1641        assert!(bytes.len() < 2000, "{} bytes for 1000 runs", bytes.len());
1642    }
1643
1644    #[test]
1645    fn a_low_cardinality_column_becomes_a_dictionary() {
1646        // Values that are far apart so that packing them directly is 30 bits each, and only 40 of
1647        // them so that the codes are 6 bits each. The dictionary has to win by a factor of five.
1648        //
1649        // Drawn at random rather than laid out at a fixed interval, because a fixed interval is a
1650        // stride and STRIDE writes the same codes without a dictionary to point them at.
1651        let mut random = Random::new();
1652        let dictionary: Vec<i64> =
1653            (0..40).map(|_| 1_000_000_000 + (random.next() % (1 << 30)) as i64).collect();
1654        let values: Vec<i64> =
1655            (0..100_000).map(|_| dictionary[(random.next() % 40) as usize]).collect();
1656        let bytes = round_trip(&values);
1657        assert_eq!(kind_of(&bytes), Kind::Dict);
1658        assert!(bytes.len() < 100_000, "{} bytes", bytes.len());
1659    }
1660
1661    #[test]
1662    fn a_nearly_constant_column_becomes_sparse() {
1663        let mut values = vec![0i64; 100_000];
1664        for index in 0..300 {
1665            values[index * 331] = 1 << 40;
1666        }
1667        let bytes = round_trip(&values);
1668        assert_eq!(kind_of(&bytes), Kind::Sparse);
1669        assert!(bytes.len() < 3000, "{} bytes for 300 exceptions", bytes.len());
1670    }
1671
1672    #[test]
1673    fn encoded_counts_match_decoded_rows_across_integer_shapes() {
1674        let mut sparse = vec![0_i64; 4096];
1675        for (index, value) in [(7, -3), (91, 12), (1001, -3), (3000, 12)] {
1676            sparse[index] = value;
1677        }
1678        let mut runs = Vec::new();
1679        for value in [0, 7, 0, -5] {
1680            runs.extend(std::iter::repeat_n(value, 500));
1681        }
1682        let mut random = Random::new();
1683        let packed = (0..2000).map(|_| (random.next() % 251) as i64).collect::<Vec<_>>();
1684        for values in [vec![0_i64; 1024], sparse, runs, packed] {
1685            let bytes = encode(&values).unwrap();
1686            let (rows, counts) = tally(&bytes).unwrap();
1687            let mut expected = BTreeMap::<i64, u64>::new();
1688            for value in decode(&bytes).unwrap() {
1689                *expected.entry(value).or_default() += 1;
1690            }
1691            assert_eq!(rows, values.len());
1692            assert_eq!(counts, expected.into_iter().collect::<Vec<_>>());
1693        }
1694    }
1695
1696    #[test]
1697    fn folded_sparse_exceptions_keep_the_last_value_at_a_repeated_position() {
1698        let mut bytes = vec![Kind::Sparse.tag()];
1699        put_u32(&mut bytes, 10);
1700        put_i64(&mut bytes, 0);
1701        put_u32(&mut bytes, 2);
1702        bytes.extend(encode(&[7, 7]).unwrap());
1703        bytes.extend(encode(&[3, 5]).unwrap());
1704
1705        let mut counts = BTreeMap::<i64, u64>::new();
1706        assert_eq!(
1707            fold(&bytes, |value, count| {
1708                *counts.entry(value).or_default() += count;
1709                Ok(())
1710            })
1711            .unwrap(),
1712            10
1713        );
1714        assert_eq!(counts, BTreeMap::from([(0, 9), (5, 1)]));
1715        assert_eq!(decode(&bytes).unwrap()[7], 5);
1716    }
1717
1718    #[test]
1719    fn the_cascade_goes_more_than_one_level_deep() {
1720        // The whole point of section 6.3. A dictionary over a clustered column produces codes that
1721        // run in long stretches, and the run lengths of those are themselves compressible.
1722        let mut values = Vec::new();
1723        for index in 0..2000i64 {
1724            values.extend(std::iter::repeat_n(1_000_000 + (index % 5) * 104_729, 100));
1725        }
1726        let bytes = round_trip(&values);
1727        let shape = describe(&bytes).unwrap();
1728        assert!(shape.contains('('), "{shape} is not a cascade");
1729        assert!(bytes.len() < 4000, "{} bytes: {shape}", bytes.len());
1730    }
1731
1732    #[test]
1733    fn random_data_is_packed_at_full_width_and_costs_what_it_costs() {
1734        // The case where nothing works, which has to come out at eight bytes a value plus change
1735        // rather than at eight bytes a value plus a dictionary of every value in the column.
1736        let mut random = Random::new();
1737        let values: Vec<i64> = (0..10_000).map(|_| random.next() as i64).collect();
1738        let bytes = round_trip(&values);
1739        assert_eq!(kind_of(&bytes), Kind::Packed);
1740        assert!(bytes.len() < 10_000 * 8 + 1000, "{} bytes", bytes.len());
1741    }
1742
1743    #[test]
1744    fn the_extremes_of_the_type_survive() {
1745        // Every offset and every delta in here overflows something if the arithmetic is done in 64
1746        // bits, which is why it is done in 128.
1747        let values = vec![i64::MIN, i64::MAX, 0, -1, i64::MIN, i64::MAX];
1748        round_trip(&values);
1749        round_trip(&[i64::MIN; 3]);
1750        round_trip(&[i64::MIN, i64::MIN + 1]);
1751    }
1752
1753    #[test]
1754    fn a_chunk_that_is_not_a_multiple_of_the_unit_round_trips() {
1755        for len in [1, 2, 1023, 1024, 1025, 2047, 2049] {
1756            let values: Vec<i64> = (0..len).map(|index| (index * 31 % 97) as i64).collect();
1757            round_trip(&values);
1758        }
1759    }
1760
1761    #[test]
1762    fn units_of_different_widths_in_one_chunk_do_not_read_each_others_leftovers() {
1763        // A decode reuses its buffers from one unit to the next instead of getting a zeroed one
1764        // each time, so a unit that wrote fewer bits than the unit before it would come back with
1765        // the older unit's values in the bits it did not write. Each run of 1024 here needs a
1766        // different width and the widths go up and down, and the last run repeats the first, which
1767        // is the pair that would agree by accident if the reuse were wrong in the obvious way.
1768        //
1769        // The values are random rather than written out because this has to stay one packed chunk
1770        // of six units to be testing anything, and the first version of it was arithmetic and got
1771        // cascaded into a delta of runs where every nested array was under a unit long. That was
1772        // caught by gating a panic on the second unit and rerunning, which this version reaches and
1773        // the old one did not, and the assertion on the shape below is there so it stays reached.
1774        let mut random = Random::new();
1775        let mut values = Vec::new();
1776        for width in [40u32, 3, 61, 1, 17, 40] {
1777            for _ in 0..1024 {
1778                values.push((random.next() & ((1u64 << width) - 1)) as i64);
1779            }
1780        }
1781        let bytes = encode(&values).unwrap();
1782        let described = describe(&bytes).unwrap();
1783        assert!(described.starts_with("FOR+BITPACK"), "expected one packed chunk, got {described}");
1784        assert_eq!(decode(&bytes).unwrap(), values, "{described}");
1785    }
1786
1787    #[test]
1788    fn a_cascade_decodes_the_same_through_a_shared_scratch_as_through_its_own() {
1789        // The scratch is threaded through the recursion, so a dictionary of deltas is three nested
1790        // decodes sharing one set of buffers. Nothing in the nesting arms holds a buffer across the
1791        // call it makes, and this is the test that says so: a chunk long enough to cascade and wide
1792        // enough to bit pack at more than one level, decoded whole.
1793        let mut values = Vec::new();
1794        for index in 0..8192i64 {
1795            values.push(1_600_000_000 + index / 4 + (index % 7) * 1_000);
1796        }
1797        let bytes = encode(&values).unwrap();
1798        let described = describe(&bytes).unwrap();
1799        assert!(described.contains('('), "expected a cascade, got {described}");
1800        assert_eq!(decode(&bytes).unwrap(), values, "{described}");
1801    }
1802
1803    #[test]
1804    fn selected_positions_agree_with_a_full_decode_for_packed_and_run_length_chunks() {
1805        let positions = [0, 1, 17, 1023, 1024, 4097, 8191];
1806        let packed: Vec<i64> = (0..8192).map(|index| index * 31 % 1_000_003).collect();
1807        let mut runs = Vec::new();
1808        for run in 0..160i64 {
1809            runs.extend(std::iter::repeat_n(run * 13, (run as usize % 71) + 2));
1810        }
1811        runs.resize(8192, -7);
1812
1813        for (kind, values) in [(Kind::Packed, packed), (Kind::Rle, runs)] {
1814            let bytes = encode_only(kind, &values).unwrap().expect("encoding applies");
1815            let selected = decode_selected(&bytes, &positions).unwrap();
1816            let expected = positions.iter().map(|&position| values[position]).collect::<Vec<_>>();
1817            assert_eq!(selected, expected, "{}", kind.name());
1818        }
1819    }
1820
1821    #[test]
1822    fn selected_positions_must_be_ordered_and_inside_the_chunk() {
1823        let bytes = encode_only(Kind::Packed, &(0..2048).collect::<Vec<_>>())
1824            .unwrap()
1825            .expect("packed applies");
1826        assert!(decode_selected(&bytes, &[7, 7]).is_err());
1827        assert!(decode_selected(&bytes, &[8, 3]).is_err());
1828        assert!(decode_selected(&bytes, &[2048]).is_err());
1829    }
1830
1831    #[test]
1832    fn a_partial_unit_costs_its_own_values_and_not_a_whole_unit() {
1833        // Three values that need 40 bits each. In the transposed layout a unit is 1024 values
1834        // whether it holds them or not, so this would be 5 KB, and every nested array in a cascade
1835        // is this short. It is 15 bytes of payload and 14 of header.
1836        let values = vec![1i64 << 39, (1 << 39) + 7, 1 << 38];
1837        let bytes = encode_only(Kind::Packed, &values).unwrap().unwrap();
1838        assert_eq!(bytes.len(), 5 + 9 + 15);
1839        assert_eq!(decode(&bytes).unwrap(), values);
1840    }
1841
1842    #[test]
1843    fn the_frame_of_reference_is_per_unit_and_not_per_chunk() {
1844        // A column that drifts, which is what a timestamp column and a clustered key both do. Each
1845        // unit here spans 1023 and packs at 10 bits, and a base per chunk would pay the 22 bits the
1846        // whole chunk spans on every value in it.
1847        let values: Vec<i64> =
1848            (0..4096i64).map(|index| (index / 1024) * 1_000_000 + (index % 1024)).collect();
1849        let bytes = encode_only(Kind::Packed, &values).unwrap().unwrap();
1850        assert_eq!(describe(&bytes).unwrap(), "FOR+BITPACK[10]");
1851        assert_eq!(decode(&bytes).unwrap(), values);
1852    }
1853
1854    #[test]
1855    fn every_candidate_that_applies_decodes_to_the_input() {
1856        // The chooser only ever hands back the smallest, so without this the other five are only
1857        // tested when they happen to win. Any of them being wrong is a wrong answer that appears
1858        // when a column's distribution shifts.
1859        let mut values = vec![5i64; 3000];
1860        for (index, value) in values.iter_mut().enumerate() {
1861            if index % 500 == 0 {
1862                *value = index as i64;
1863            }
1864        }
1865        let applicable = candidates(&values, 0, &EXHAUSTIVE);
1866        assert!(applicable.len() >= 4, "{applicable:?}");
1867        for kind in applicable {
1868            let bytes = encode_only(kind, &values).unwrap().unwrap();
1869            assert_eq!(decode(&bytes).unwrap(), values, "{}", kind.name());
1870        }
1871    }
1872
1873    /// The test above only asks the kinds `candidates` offered, so between them the two cover the
1874    /// encoders on input the search would give them and nothing else. `encode_only` does not go
1875    /// through `candidates` at all, so every one of its callers can hand an encoder a shape the
1876    /// filter would have refused, and the empty chunk is the shape that used to panic.
1877    #[test]
1878    fn every_kind_that_applies_decodes_to_what_it_was_given() {
1879        let shapes: Vec<Vec<i64>> = vec![
1880            Vec::new(),
1881            vec![5; 1024],
1882            vec![i64::MIN, i64::MAX, 0, -1],
1883            (0..1024).map(|at| at * 7).collect(),
1884            (0..1024).map(|at| at % 17).collect(),
1885            (0..1024).map(|at| if at % 100 == 0 { at } else { 3 }).collect(),
1886            (0..1024).map(|at| -at * 1_000_003).collect(),
1887            (0..1024_i64)
1888                .map(|at| {
1889                    at.wrapping_mul(6_364_136_223_846_793_005)
1890                        .wrapping_add(1_442_695_040_888_963_407)
1891                })
1892                .collect(),
1893        ];
1894        let kinds =
1895            [Kind::Constant, Kind::Packed, Kind::Delta, Kind::Rle, Kind::Dict, Kind::Sparse];
1896        for values in &shapes {
1897            for kind in kinds {
1898                let Some(bytes) = encode_only(kind, values).unwrap() else {
1899                    continue;
1900                };
1901                assert_eq!(
1902                    &decode(&bytes).unwrap(),
1903                    values,
1904                    "{} over {} values",
1905                    kind.name(),
1906                    values.len()
1907                );
1908            }
1909        }
1910    }
1911
1912    #[test]
1913    fn the_chooser_picks_the_smallest_candidate_rather_than_the_first_that_applies() {
1914        let mut values = vec![5i64; 3000];
1915        values[1500] = 9;
1916        let chosen = encode(&values).unwrap();
1917        for (_, size) in candidate_sizes(&values).unwrap() {
1918            assert!(chosen.len() <= size);
1919        }
1920    }
1921
1922    #[test]
1923    fn a_truncated_chunk_is_an_error_and_not_a_panic() {
1924        let bytes = encode(&[1, 2, 3, 4, 5]).unwrap();
1925        for len in 0..bytes.len() {
1926            let error = decode(&bytes[..len]).unwrap_err();
1927            assert!(error.message().contains("chunk"), "{error}");
1928        }
1929    }
1930
1931    #[test]
1932    fn trailing_bytes_are_an_error() {
1933        let mut bytes = encode(&[1, 2, 3]).unwrap();
1934        bytes.push(0);
1935        let error = decode(&bytes).unwrap_err();
1936        assert!(error.message().contains("left over"), "{error}");
1937    }
1938
1939    #[test]
1940    fn an_unknown_tag_is_an_error() {
1941        let error = decode(&[99, 0, 0, 0, 0]).unwrap_err();
1942        assert!(error.message().contains("unknown encoding tag"), "{error}");
1943    }
1944
1945    #[test]
1946    fn a_dictionary_code_outside_the_dictionary_is_an_error() {
1947        // A corrupted or malicious chunk must not index out of bounds, and this is the one place in
1948        // the decoder where a number that came off the disk is used as an index. Built by hand
1949        // rather than by corrupting a real chunk, because a byte offset into an encoding that the
1950        // chooser is free to change is a test that breaks for the wrong reason.
1951        let mut bytes = vec![Kind::Dict.tag()];
1952        put_u32(&mut bytes, 1);
1953        bytes.extend_from_slice(&encode(&[10]).unwrap());
1954        bytes.extend_from_slice(&encode(&[5]).unwrap());
1955        let error = decode(&bytes).unwrap_err();
1956        assert!(error.message().contains("not in the dictionary"), "{error}");
1957    }
1958
1959    #[test]
1960    fn a_negative_run_length_is_an_error() {
1961        // The other number off the disk that the decoder would otherwise trust, and the one that
1962        // would turn into an allocation of nine quintillion values.
1963        let mut bytes = vec![Kind::Rle.tag()];
1964        put_u32(&mut bytes, 4);
1965        bytes.extend_from_slice(&encode(&[7]).unwrap());
1966        bytes.extend_from_slice(&encode(&[-4]).unwrap());
1967        let error = decode(&bytes).unwrap_err();
1968        assert!(error.message().contains("negative"), "{error}");
1969    }
1970
1971    /// A run that ends past the chunk it is in is an error and not a write past the end.
1972    #[test]
1973    fn a_run_that_runs_past_its_chunk_is_an_error() {
1974        // The decode writes a fixed eight values per run and moves on by the run's own length, so
1975        // the buffer carries eight values of slack and a run that claims more rows than the chunk
1976        // holds would be the one way to reach past it. It is refused before the write rather than
1977        // caught by the count afterwards.
1978        let mut bytes = vec![Kind::Rle.tag()];
1979        put_u32(&mut bytes, 4);
1980        bytes.extend_from_slice(&encode(&[7]).unwrap());
1981        bytes.extend_from_slice(&encode(&[9]).unwrap());
1982        let error = decode(&bytes).unwrap_err();
1983        assert!(error.message().contains("past its chunk"), "{error}");
1984    }
1985
1986    /// Runs of every length around the eight that a run is written in, in one chunk.
1987    #[test]
1988    fn runs_shorter_and_longer_than_the_width_they_are_written_in_all_come_back() {
1989        // A run of one, several shorter than eight, one of exactly eight and two longer, with the
1990        // shortest run last so that the surplus of the write before it has nothing after it to be
1991        // overwritten by. The values differ from each other, because a surplus that was left in
1992        // place would be invisible against a neighbour holding the same value.
1993        let lengths = [1, 3, 7, 8, 9, 40, 2, 1];
1994        let mut values = Vec::new();
1995        for (at, length) in lengths.iter().enumerate() {
1996            let value = i64::try_from(at).expect("eight runs") * 1000 - 3;
1997            values.extend(std::iter::repeat_n(value, *length));
1998        }
1999        let bytes = encode(&values).expect("encodes");
2000        assert_eq!(decode(&bytes).expect("decodes"), values, "runs around the write width");
2001        // And the same rows a run at a time, which is the run length encoder's worst case and the
2002        // shape a column with no runs in it decodes as.
2003        let singles: Vec<i64> = (0..300).map(|index| index * 7 % 11).collect();
2004        let bytes = encode(&singles).expect("encodes");
2005        assert_eq!(decode(&bytes).expect("decodes"), singles, "no run longer than one");
2006    }
2007
2008    #[test]
2009    fn the_cascade_depth_is_bounded() {
2010        // Without the limit a chooser that finds a dictionary of a dictionary of a dictionary would
2011        // recurse until the values ran out, and the encode time of a wide column would be a
2012        // surprise rather than a number.
2013        let values: Vec<i64> = (0..50_000).map(|index| (index / 100) % 250).collect();
2014        let bytes = round_trip(&values);
2015        let shape = describe(&bytes).unwrap();
2016        let depth = shape.matches('(').count();
2017        assert!(depth <= MAX_DEPTH as usize, "{shape} is {depth} deep");
2018    }
2019
2020    #[test]
2021    fn candidate_sizes_reports_what_the_chooser_looked_at() {
2022        let values: Vec<i64> = (0..5000).map(|index| index % 17).collect();
2023        let sizes = candidate_sizes(&values).unwrap();
2024        assert!(sizes.iter().any(|(kind, _)| *kind == Kind::Dict));
2025        assert!(sizes.iter().any(|(kind, _)| *kind == Kind::Packed));
2026        assert!(sizes.iter().all(|(_, size)| *size > 0));
2027    }
2028
2029    #[test]
2030    fn a_chunk_can_be_read_from_the_front_of_a_longer_buffer() {
2031        // What a string column does. It writes an integer chunk of lengths into the middle of its
2032        // own body and has to find the end of it again on the way back.
2033        let first = encode(&[1, 2, 3]).unwrap();
2034        let second: Vec<i64> = (0..3000).map(|index| index % 11).collect();
2035        let second_bytes = encode(&second).unwrap();
2036        let mut joined = first.clone();
2037        joined.extend_from_slice(&second_bytes);
2038        joined.extend_from_slice(b"and then something else");
2039
2040        let (values, used) = decode_prefix(&joined).unwrap();
2041        assert_eq!(values, vec![1, 2, 3]);
2042        assert_eq!(used, first.len());
2043        let (more, used_again) = decode_prefix(&joined[used..]).unwrap();
2044        assert_eq!(more, second);
2045        assert_eq!(used_again, second_bytes.len());
2046
2047        let (text, described) = describe_prefix(&joined).unwrap();
2048        assert_eq!(described, first.len());
2049        assert_eq!(text, describe(&first).unwrap());
2050    }
2051
2052    #[test]
2053    fn a_truncated_chunk_is_still_an_error_when_read_as_a_prefix() {
2054        let bytes = encode(&(0..2000).collect::<Vec<i64>>()).unwrap();
2055        for len in 0..bytes.len() {
2056            assert!(decode_prefix(&bytes[..len]).is_err(), "{len} bytes decoded");
2057        }
2058    }
2059}