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