1use 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
55const MAX_DEPTH: u8 = 3;
62
63const RUN: usize = 8;
73
74const LONG_RUN: usize = 64;
78
79#[derive(Debug, Clone, Copy, PartialEq, Eq)]
82pub enum Kind {
83 Constant = 0,
85 Packed = 1,
88 Delta = 2,
91 Rle = 3,
93 Dict = 4,
96 Sparse = 5,
98 Strided = 6,
101}
102
103impl Kind {
104 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 #[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
147pub fn encode(values: &[i64]) -> Result<Vec<u8>> {
154 encode_with(values, &EXHAUSTIVE)
155}
156
157pub fn encode_with(values: &[i64], chooser: &dyn Chooser) -> Result<Vec<u8>> {
167 encode_at(values, 0, chooser)
168}
169
170pub 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
188pub 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
205pub 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 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 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
306pub 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
331pub 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
346pub 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
357pub 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#[must_use]
380pub fn offered(values: &[i64]) -> Vec<Kind> {
381 candidates(values, 0, &EXHAUSTIVE)
382}
383
384pub fn encode_only(kind: Kind, values: &[i64]) -> Result<Option<Vec<u8>>> {
395 encode_as(kind, values, 0, &EXHAUSTIVE)
396}
397
398pub(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
406pub 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
424pub 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 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 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
466fn 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 return vec![Kind::Constant];
487 }
488 let considered = |kind| chooser.considers_integer(kind, depth);
489 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 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 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
524struct Profile {
538 min: i64,
539 max: i64,
540 runs: usize,
542 delta_low: u64,
545 delta_high: u64,
546 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 fn width(&self) -> u32 {
572 width_of(self.max.wrapping_sub(self.min) as u64)
573 }
574
575 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 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
593fn 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
614const FEW_DELTAS: usize = 4;
616
617const FEW_DELTAS_SEEN: usize = 64;
619
620fn width_of(range: u64) -> u32 {
622 u64::BITS - range.leading_zeros()
623}
624
625fn 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 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 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 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
722fn encode_packed(values: &[i64], out: &mut Vec<u8>) -> Result<()> {
734 let mut offsets: Vec<u64> = Vec::with_capacity(VALUES);
738 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
762struct Decoding {
789 packed: Vec<u64>,
792}
793
794thread_local! {
795 static DECODING: std::cell::RefCell<Decoding> =
797 const { std::cell::RefCell::new(Decoding::new()) };
798}
799
800fn 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 const fn new() -> Self {
816 Self { packed: Vec::new() }
817 }
818
819 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 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 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
1077fn 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
1105fn 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
1128fn 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 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
1221fn stride_of(values: &[i64]) -> Option<u64> {
1233 stride_from(values, values.iter().min().copied()?)
1234}
1235
1236fn 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 (divisor > 1).then_some(divisor)
1248}
1249
1250fn 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
1272fn 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
1282fn 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
1292fn 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
1316fn 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
1335fn 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
1371fn 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
1395fn distinct_values(values: &[i64]) -> Vec<i64> {
1398 let mut distinct = values.to_vec();
1399 distinct.sort_unstable();
1400 distinct.dedup();
1401 distinct
1402}
1403
1404fn 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 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 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 #[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 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 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 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 assert_eq!(stride_of(&[7i64, 17, 37]), Some(10));
1677 assert_eq!(stride_of(&[10i64, 20, 23]), None);
1678 assert_eq!(stride_of(&[5i64; 100]), None);
1681 assert_eq!(stride_of(&[]), None);
1682 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 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 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 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 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 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 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 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 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 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 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 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 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 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 #[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 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 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 #[test]
2088 fn a_run_that_runs_past_its_chunk_is_an_error() {
2089 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 #[test]
2103 fn runs_shorter_and_longer_than_the_width_they_are_written_in_all_come_back() {
2104 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 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 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 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}