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