1use rudb_common::{Error, Result};
45
46use crate::chooser::{Chooser, EXHAUSTIVE};
47use crate::reader::Reader;
48
49use crate::bitpack::{self, VALUES};
50
51const MAX_DEPTH: u8 = 3;
58
59#[derive(Debug, Clone, Copy, PartialEq, Eq)]
62pub enum Kind {
63 Constant = 0,
65 Packed = 1,
68 Delta = 2,
71 Rle = 3,
73 Dict = 4,
76 Sparse = 5,
78 Strided = 6,
81}
82
83impl Kind {
84 fn tag(self) -> u8 {
85 self as u8
86 }
87
88 fn from_tag(tag: u8) -> Result<Self> {
89 match tag {
90 0 => Ok(Self::Constant),
91 1 => Ok(Self::Packed),
92 2 => Ok(Self::Delta),
93 3 => Ok(Self::Rle),
94 4 => Ok(Self::Dict),
95 5 => Ok(Self::Sparse),
96 6 => Ok(Self::Strided),
97 other => Err(Error::internal(format!("unknown encoding tag {other}"))),
98 }
99 }
100
101 #[must_use]
103 pub fn name(self) -> &'static str {
104 match self {
105 Self::Constant => "CONSTANT",
106 Self::Packed => "FOR+BITPACK",
107 Self::Delta => "DELTA",
108 Self::Rle => "RLE",
109 Self::Dict => "DICT",
110 Self::Sparse => "SPARSE",
111 Self::Strided => "STRIDE",
112 }
113 }
114}
115
116pub fn encode(values: &[i64]) -> Result<Vec<u8>> {
123 encode_with(values, &EXHAUSTIVE)
124}
125
126pub fn encode_with(values: &[i64], chooser: &dyn Chooser) -> Result<Vec<u8>> {
136 encode_at(values, 0, chooser)
137}
138
139pub fn decode(bytes: &[u8]) -> Result<Vec<i64>> {
146 let mut reader = Reader::new(bytes);
147 let values = with_decoding(|scratch| decode_chunk(&mut reader, scratch))?;
148 if reader.remaining() != 0 {
149 return Err(Error::internal(format!(
150 "{} bytes left over after decoding a chunk",
151 reader.remaining()
152 )));
153 }
154 Ok(values)
155}
156
157pub fn decode_prefix(bytes: &[u8]) -> Result<(Vec<i64>, usize)> {
167 let mut reader = Reader::new(bytes);
168 let values = with_decoding(|scratch| decode_chunk(&mut reader, scratch))?;
169 Ok((values, reader.used()))
170}
171
172pub fn describe_prefix(bytes: &[u8]) -> Result<(String, usize)> {
178 let mut reader = Reader::new(bytes);
179 let text = describe_chunk(&mut reader)?;
180 Ok((text, reader.used()))
181}
182
183pub fn candidate_sizes(values: &[i64]) -> Result<Vec<(Kind, usize)>> {
190 let mut sizes = Vec::new();
191 for kind in candidates(values, 0) {
192 if let Some(bytes) = encode_as(kind, values, 0, &EXHAUSTIVE)? {
193 sizes.push((kind, bytes.len()));
194 }
195 }
196 Ok(sizes)
197}
198
199#[must_use]
206pub fn offered(values: &[i64]) -> Vec<Kind> {
207 candidates(values, 0)
208}
209
210pub fn encode_only(kind: Kind, values: &[i64]) -> Result<Option<Vec<u8>>> {
221 encode_as(kind, values, 0, &EXHAUSTIVE)
222}
223
224pub(crate) fn size_as(kind: Kind, values: &[i64], depth: u8) -> Result<Option<usize>> {
229 Ok(encode_as(kind, values, depth, &EXHAUSTIVE)?.map(|bytes| bytes.len()))
230}
231
232pub fn describe(bytes: &[u8]) -> Result<String> {
238 let mut reader = Reader::new(bytes);
239 describe_chunk(&mut reader)
240}
241
242fn encode_at(values: &[i64], depth: u8, chooser: &dyn Chooser) -> Result<Vec<u8>> {
243 let offered = candidates(values, depth);
244 let mut best: Option<Vec<u8>> = None;
245 for kind in chooser.narrow_integers(values, &offered, depth) {
246 let Some(bytes) = encode_as(kind, values, depth, chooser)? else {
247 continue;
248 };
249 if best.as_ref().is_none_or(|current| bytes.len() < current.len()) {
250 best = Some(bytes);
251 }
252 }
253 best.ok_or_else(|| Error::internal("no encoding applied to the chunk"))
256}
257
258fn candidates(values: &[i64], depth: u8) -> Vec<Kind> {
265 let mut kinds = vec![Kind::Packed];
266 if depth >= MAX_DEPTH || values.is_empty() {
267 return kinds;
268 }
269 if values.iter().all(|value| *value == values[0]) {
270 return vec![Kind::Constant];
272 }
273 if values.len() >= 2 && deltas_fit(values) {
274 kinds.push(Kind::Delta);
275 }
276 if run_count(values) * 4 <= values.len() * 3 {
277 kinds.push(Kind::Rle);
278 }
279 let (distinct, dominant) = spread_of(values);
283 if distinct * 2 <= values.len() {
284 kinds.push(Kind::Dict);
285 }
286 match dominant {
289 Some((_, count)) if count * 10 >= values.len() * 8 => kinds.push(Kind::Sparse),
290 _ => {}
291 }
292 if stride_of(values).is_some() {
293 kinds.push(Kind::Strided);
294 }
295 kinds
296}
297
298fn encode_as(
301 kind: Kind,
302 values: &[i64],
303 depth: u8,
304 chooser: &dyn Chooser,
305) -> Result<Option<Vec<u8>>> {
306 let mut out = Vec::new();
307 put_u8(&mut out, kind.tag());
308 put_u32(&mut out, u32::try_from(values.len()).map_err(|_| too_long(values.len()))?);
309 match kind {
310 Kind::Constant => {
311 let Some(first) = values.first() else {
312 return Ok(None);
313 };
314 if values.iter().any(|value| value != first) {
315 return Ok(None);
316 }
317 put_i64(&mut out, *first);
318 }
319 Kind::Packed => encode_packed(values, &mut out)?,
320 Kind::Delta => {
321 let (Some(first), Some(deltas)) = (values.first(), deltas(values)) else {
325 return Ok(None);
326 };
327 put_i64(&mut out, *first);
328 out.extend_from_slice(&encode_at(&deltas, depth + 1, chooser)?);
329 }
330 Kind::Rle => {
331 let (run_values, run_lengths) = runs(values);
332 if run_values.is_empty() {
333 return Ok(None);
334 }
335 out.extend_from_slice(&encode_at(&run_values, depth + 1, chooser)?);
336 out.extend_from_slice(&encode_at(&run_lengths, depth + 1, chooser)?);
337 }
338 Kind::Dict => {
339 let dictionary = distinct_values(values);
340 if dictionary.is_empty() {
341 return Ok(None);
342 }
343 let codes = codes_over(values, &dictionary);
344 out.extend_from_slice(&encode_at(&dictionary, depth + 1, chooser)?);
345 out.extend_from_slice(&encode_at(&codes, depth + 1, chooser)?);
346 }
347 Kind::Sparse => {
348 let Some((value, _)) = spread_of(values).1 else {
349 return Ok(None);
350 };
351 let mut positions = Vec::new();
352 let mut exceptions = Vec::new();
353 for (index, other) in values.iter().enumerate() {
354 if *other != value {
355 positions.push(index as i64);
356 exceptions.push(*other);
357 }
358 }
359 put_i64(&mut out, value);
360 put_u32(
361 &mut out,
362 u32::try_from(positions.len()).map_err(|_| too_long(positions.len()))?,
363 );
364 out.extend_from_slice(&encode_at(&positions, depth + 1, chooser)?);
365 out.extend_from_slice(&encode_at(&exceptions, depth + 1, chooser)?);
366 }
367 Kind::Strided => {
368 let (Some(base), Some(stride)) = (values.iter().min().copied(), stride_of(values))
369 else {
370 return Ok(None);
371 };
372 let mut steps = Vec::with_capacity(values.len());
373 for value in values {
374 let step = offset_from(*value, base) / stride;
375 let Ok(step) = i64::try_from(step) else {
380 return Ok(None);
381 };
382 steps.push(step);
383 }
384 put_i64(&mut out, base);
385 put_u64(&mut out, stride);
386 out.extend_from_slice(&encode_at(&steps, depth + 1, chooser)?);
387 }
388 }
389 Ok(Some(out))
390}
391
392fn encode_packed(values: &[i64], out: &mut Vec<u8>) -> Result<()> {
404 let mut offsets: Vec<u64> = Vec::with_capacity(VALUES);
408 let mut packed: Vec<u64> = vec![0; bitpack::packed_len::<u64>(64)];
411 let mut transposed = bitpack::Scratch::<u64>::new();
412 for unit in values.chunks(VALUES) {
413 let base = unit.iter().copied().min().unwrap_or(0);
414 offsets.clear();
415 offsets.extend(unit.iter().map(|value| offset_from(*value, base)));
416 let width = bitpack::required_width(&offsets);
417 put_i64(out, base);
418 put_u8(out, u8::try_from(width).map_err(|_| Error::internal("impossible width"))?);
419 if unit.len() == VALUES {
420 let words = bitpack::packed_len::<u64>(width);
421 bitpack::pack_with(&offsets, width, &mut packed[..words], &mut transposed)?;
422 for word in &packed[..words] {
423 put_u64(out, *word);
424 }
425 } else {
426 bitpack::pack_tail(&offsets, width, out)?;
427 }
428 }
429 Ok(())
430}
431
432struct Decoding {
455 packed: Vec<u64>,
458 unit: Vec<u64>,
460 transposed: bitpack::Scratch<u64>,
462}
463
464thread_local! {
465 static DECODING: std::cell::RefCell<Decoding> =
467 const { std::cell::RefCell::new(Decoding::new()) };
468}
469
470fn with_decoding<T>(run: impl FnOnce(&mut Decoding) -> T) -> T {
477 DECODING.with(|cell| match cell.try_borrow_mut() {
478 Ok(mut scratch) => run(&mut scratch),
479 Err(_) => run(&mut Decoding::new()),
480 })
481}
482
483impl Decoding {
484 const fn new() -> Self {
486 Self { packed: Vec::new(), unit: Vec::new(), transposed: bitpack::Scratch::new() }
487 }
488
489 fn ready(&mut self) {
491 if self.unit.len() != VALUES {
492 self.unit.resize(VALUES, 0);
493 self.packed.resize(bitpack::packed_len::<u64>(64), 0);
494 }
495 }
496}
497
498fn decode_chunk(reader: &mut Reader<'_>, scratch: &mut Decoding) -> Result<Vec<i64>> {
499 let kind = Kind::from_tag(reader.u8()?)?;
500 let count = reader.u32()? as usize;
501 match kind {
502 Kind::Constant => Ok(vec![reader.i64()?; count]),
503 Kind::Packed => {
504 let mut values = Vec::with_capacity(count);
505 scratch.ready();
506 while values.len() < count {
507 let base = reader.i64()?;
508 let width = reader.u8()? as usize;
509 let wanted = (count - values.len()).min(VALUES);
510 if wanted == VALUES {
511 let words = bitpack::packed_len::<u64>(width);
512 for word in &mut scratch.packed[..words] {
513 *word = reader.u64()?;
514 }
515 bitpack::unpack_with(
516 &scratch.packed[..words],
517 width,
518 &mut scratch.unit,
519 &mut scratch.transposed,
520 )?;
521 values.extend(scratch.unit.iter().map(|offset| value_from(*offset, base)));
522 } else {
523 let bytes = reader.bytes(bitpack::tail_len(wanted, width))?;
524 let unit = bitpack::unpack_tail(bytes, width, wanted)?;
525 values.extend(unit.iter().map(|offset| value_from(*offset, base)));
526 }
527 }
528 Ok(values)
529 }
530 Kind::Delta => {
531 let first = reader.i64()?;
532 let deltas = decode_chunk(reader, scratch)?;
533 let mut values = Vec::with_capacity(count);
534 values.push(first);
535 let mut current = first;
536 for delta in deltas {
537 current = current.wrapping_add(unzigzag(delta as u64));
538 values.push(current);
539 }
540 check_count(values.len(), count)?;
541 Ok(values)
542 }
543 Kind::Rle => {
544 let run_values = decode_chunk(reader, scratch)?;
545 let run_lengths = decode_chunk(reader, scratch)?;
546 if run_values.len() != run_lengths.len() {
547 return Err(Error::internal("an RLE chunk has more runs than run lengths"));
548 }
549 let mut values = Vec::with_capacity(count);
550 for (value, length) in run_values.into_iter().zip(run_lengths) {
551 let length = usize::try_from(length)
552 .map_err(|_| Error::internal("a negative RLE run length"))?;
553 values.extend(std::iter::repeat_n(value, length));
554 }
555 check_count(values.len(), count)?;
556 Ok(values)
557 }
558 Kind::Dict => {
559 let dictionary = decode_chunk(reader, scratch)?;
560 let codes = decode_chunk(reader, scratch)?;
561 let mut values = Vec::with_capacity(count);
562 for code in codes {
563 let index =
564 usize::try_from(code).ok().and_then(|index| dictionary.get(index)).ok_or_else(
565 || Error::internal(format!("code {code} is not in the dictionary")),
566 )?;
567 values.push(*index);
568 }
569 check_count(values.len(), count)?;
570 Ok(values)
571 }
572 Kind::Sparse => {
573 let value = reader.i64()?;
574 let exception_count = reader.u32()? as usize;
575 let positions = decode_chunk(reader, scratch)?;
576 let exceptions = decode_chunk(reader, scratch)?;
577 if positions.len() != exception_count || exceptions.len() != exception_count {
578 return Err(Error::internal("a sparse chunk disagrees about its exception count"));
579 }
580 let mut values = vec![value; count];
581 for (position, exception) in positions.into_iter().zip(exceptions) {
582 let position = usize::try_from(position)
583 .ok()
584 .filter(|position| *position < count)
585 .ok_or_else(|| {
586 Error::internal(format!("exception at {position} is outside the chunk"))
587 })?;
588 values[position] = exception;
589 }
590 Ok(values)
591 }
592 Kind::Strided => {
593 let base = reader.i64()?;
594 let stride = reader.u64()?;
595 let steps = decode_chunk(reader, scratch)?;
596 check_count(steps.len(), count)?;
597 let mut values = Vec::with_capacity(count);
598 for step in steps {
599 let step = u64::try_from(step)
600 .map_err(|_| Error::internal("a negative number of strides"))?;
601 values.push(value_from(step.wrapping_mul(stride), base));
602 }
603 Ok(values)
604 }
605 }
606}
607
608fn describe_chunk(reader: &mut Reader<'_>) -> Result<String> {
609 let kind = Kind::from_tag(reader.u8()?)?;
610 let count = reader.u32()? as usize;
611 Ok(match kind {
612 Kind::Constant => {
613 reader.i64()?;
614 "CONSTANT".to_string()
615 }
616 Kind::Packed => {
617 let mut widths = Vec::new();
618 let mut seen = 0;
619 while seen < count {
620 reader.i64()?;
621 let width = reader.u8()? as usize;
622 let wanted = (count - seen).min(VALUES);
623 if wanted == VALUES {
624 for _ in 0..bitpack::packed_len::<u64>(width) {
625 reader.u64()?;
626 }
627 } else {
628 reader.bytes(bitpack::tail_len(wanted, width))?;
629 }
630 widths.push(width);
631 seen += wanted;
632 }
633 let low = widths.iter().copied().min().unwrap_or(0);
634 let high = widths.iter().copied().max().unwrap_or(0);
635 if low == high {
638 format!("FOR+BITPACK[{low}]")
639 } else {
640 format!("FOR+BITPACK[{low}..{high}]")
641 }
642 }
643 Kind::Delta => {
644 reader.i64()?;
645 format!("DELTA({})", describe_chunk(reader)?)
646 }
647 Kind::Rle => {
648 let values = describe_chunk(reader)?;
649 let lengths = describe_chunk(reader)?;
650 format!("RLE({values}, {lengths})")
651 }
652 Kind::Dict => {
653 let dictionary = describe_chunk(reader)?;
654 let codes = describe_chunk(reader)?;
655 format!("DICT({dictionary}, {codes})")
656 }
657 Kind::Sparse => {
658 reader.i64()?;
659 reader.u32()?;
660 let positions = describe_chunk(reader)?;
661 let exceptions = describe_chunk(reader)?;
662 format!("SPARSE({positions}, {exceptions})")
663 }
664 Kind::Strided => {
665 reader.i64()?;
666 let stride = reader.u64()?;
667 format!("STRIDE[{stride}]({})", describe_chunk(reader)?)
668 }
669 })
670}
671
672fn stride_of(values: &[i64]) -> Option<u64> {
684 let base = values.iter().min().copied()?;
685 let mut divisor = 0u64;
686 for value in values {
687 divisor = gcd(divisor, offset_from(*value, base));
688 if divisor == 1 {
689 return None;
690 }
691 }
692 (divisor > 1).then_some(divisor)
695}
696
697fn gcd(mut left: u64, mut right: u64) -> u64 {
699 if left == 0 {
700 return right;
701 }
702 if right == 0 {
703 return left;
704 }
705 let shift = (left | right).trailing_zeros();
706 left >>= left.trailing_zeros();
707 loop {
708 right >>= right.trailing_zeros();
709 if left > right {
710 std::mem::swap(&mut left, &mut right);
711 }
712 right -= left;
713 if right == 0 {
714 return left << shift;
715 }
716 }
717}
718
719fn offset_from(value: i64, base: i64) -> u64 {
722 (i128::from(value) - i128::from(base)) as u64
723}
724
725fn value_from(offset: u64, base: i64) -> i64 {
726 (i128::from(base) + i128::from(offset)) as i64
727}
728
729fn zigzag(value: i64) -> u64 {
732 ((value << 1) ^ (value >> 63)) as u64
733}
734
735fn unzigzag(value: u64) -> i64 {
736 ((value >> 1) as i64) ^ -((value & 1) as i64)
737}
738
739fn deltas_fit(values: &[i64]) -> bool {
751 values.windows(2).all(|pair| i64::try_from(i128::from(pair[1]) - i128::from(pair[0])).is_ok())
752}
753
754fn deltas(values: &[i64]) -> Option<Vec<i64>> {
755 let mut deltas = Vec::with_capacity(values.len().saturating_sub(1));
756 for pair in values.windows(2) {
757 let difference = i128::from(pair[1]) - i128::from(pair[0]);
758 let difference = i64::try_from(difference).ok()?;
759 deltas.push(zigzag(difference) as i64);
760 }
761 Some(deltas)
762}
763
764fn run_count(values: &[i64]) -> usize {
765 let mut runs = 0;
766 let mut previous = None;
767 for value in values {
768 if previous != Some(value) {
769 runs += 1;
770 previous = Some(value);
771 }
772 }
773 runs
774}
775
776fn runs(values: &[i64]) -> (Vec<i64>, Vec<i64>) {
777 let mut run_values: Vec<i64> = Vec::new();
778 let mut run_lengths: Vec<i64> = Vec::new();
779 for value in values {
780 if run_values.last() == Some(value) {
781 *run_lengths.last_mut().expect("a run length exists beside every run value") += 1;
782 } else {
783 run_values.push(*value);
784 run_lengths.push(1);
785 }
786 }
787 (run_values, run_lengths)
788}
789
790fn spread_of(values: &[i64]) -> (usize, Option<(i64, usize)>) {
805 let mut sorted = values.to_vec();
806 sorted.sort_unstable();
807 let mut distinct = 0;
808 let mut best: Option<(i64, usize)> = None;
809 let mut index = 0;
810 while index < sorted.len() {
811 let value = sorted[index];
812 let mut end = index;
813 while end < sorted.len() && sorted[end] == value {
814 end += 1;
815 }
816 distinct += 1;
817 let count = end - index;
818 if best.is_none_or(|(_, seen)| count > seen) {
819 best = Some((value, count));
820 }
821 index = end;
822 }
823 (distinct, best)
824}
825
826fn distinct_values(values: &[i64]) -> Vec<i64> {
829 let mut distinct = values.to_vec();
830 distinct.sort_unstable();
831 distinct.dedup();
832 distinct
833}
834
835fn codes_over(values: &[i64], dictionary: &[i64]) -> Vec<i64> {
845 values
846 .iter()
847 .map(|value| {
848 dictionary
849 .binary_search(value)
850 .expect("the dictionary is the distinct values of this chunk") as i64
851 })
852 .collect()
853}
854
855fn check_count(actual: usize, expected: usize) -> Result<()> {
856 if actual == expected {
857 Ok(())
858 } else {
859 Err(Error::internal(format!(
860 "a chunk says it holds {expected} values and decoded to {actual}"
861 )))
862 }
863}
864
865fn too_long(len: usize) -> Error {
866 Error::internal(format!("a chunk of {len} values is longer than the format allows"))
867}
868
869fn put_u8(out: &mut Vec<u8>, value: u8) {
870 out.push(value);
871}
872
873fn put_u32(out: &mut Vec<u8>, value: u32) {
874 out.extend_from_slice(&value.to_le_bytes());
875}
876
877fn put_u64(out: &mut Vec<u8>, value: u64) {
878 out.extend_from_slice(&value.to_le_bytes());
879}
880
881fn put_i64(out: &mut Vec<u8>, value: i64) {
882 out.extend_from_slice(&value.to_le_bytes());
883}
884
885#[cfg(test)]
886mod tests {
887 use super::*;
888
889 fn round_trip(values: &[i64]) -> Vec<u8> {
890 let bytes = encode(values).unwrap();
891 assert_eq!(decode(&bytes).unwrap(), values, "{}", describe(&bytes).unwrap());
892 bytes
893 }
894
895 fn kind_of(bytes: &[u8]) -> Kind {
896 Kind::from_tag(bytes[0]).unwrap()
897 }
898
899 struct Random(u64);
901
902 impl Random {
903 fn new() -> Self {
904 Self(0x9e37_79b9_7f4a_7c15)
905 }
906
907 fn next(&mut self) -> u64 {
908 self.0 ^= self.0 << 13;
909 self.0 ^= self.0 >> 7;
910 self.0 ^= self.0 << 17;
911 self.0
912 }
913 }
914
915 #[test]
916 fn the_dictionary_is_sorted_and_the_codes_point_back_at_the_values() {
917 let values = vec![30i64, 10, 30, 20, 10, -5];
918 let dictionary = distinct_values(&values);
919 let codes = codes_over(&values, &dictionary);
920 assert_eq!(dictionary, vec![-5, 10, 20, 30]);
921 assert_eq!(codes, vec![3, 1, 3, 2, 1, 0]);
922 for (code, value) in codes.iter().zip(&values) {
923 assert_eq!(dictionary[*code as usize], *value);
924 }
925 }
926
927 #[test]
928 fn one_sort_gives_the_distinct_count_and_the_most_frequent_value() {
929 let values = vec![7i64, 7, 7, 1, 2, 2];
930 assert_eq!(spread_of(&values), (3, Some((7, 3))));
931 assert_eq!(spread_of(&[]), (0, None));
932 assert_eq!(spread_of(&[9]), (1, Some((9, 1))));
933
934 assert_eq!(spread_of(&[4i64, 4, 8, 8]), (2, Some((4, 2))));
937 }
938
939 #[test]
940 fn deltas_that_do_not_fit_are_refused_before_they_are_built() {
941 assert!(deltas_fit(&[1i64, 2, 3]));
942 assert!(deltas_fit(&[i64::MAX, i64::MAX]));
943 assert!(!deltas_fit(&[i64::MIN, i64::MAX]));
944 assert_eq!(deltas_fit(&[i64::MIN, i64::MAX]), deltas(&[i64::MIN, i64::MAX]).is_some());
945 assert_eq!(deltas_fit(&[1i64, 2, 3]), deltas(&[1i64, 2, 3]).is_some());
946 }
947
948 #[test]
949 fn what_the_chooser_returns_is_the_smallest_of_what_it_was_offered() {
950 let mut random = Random::new();
954 let noise: Vec<i64> = (0..2000).map(|_| (random.next() % 5000) as i64).collect();
955 let runs: Vec<i64> = (0..2000).map(|index: i64| index / 100).collect();
956 let climbing: Vec<i64> = (0..2000).map(|index| 1_700_000_000 + index).collect();
957 for values in [noise, runs, climbing, vec![7; 300], Vec::new()] {
958 let chosen = encode(&values).unwrap();
959 let mut smallest: Option<Vec<u8>> = None;
960 for kind in offered(&values) {
961 let Some(bytes) = encode_only(kind, &values).unwrap() else {
962 continue;
963 };
964 if smallest.as_ref().is_none_or(|best| bytes.len() < best.len()) {
965 smallest = Some(bytes);
966 }
967 }
968 assert_eq!(smallest.as_deref(), Some(chosen.as_slice()), "{}", values.len());
969 }
970 }
971
972 #[test]
973 fn a_column_of_whole_seconds_in_microseconds_pays_nothing_for_the_zeroes() {
974 let mut random = Random::new();
978 let day = 1_374_000_000_000_000i64;
979 let values: Vec<i64> =
980 (0..100_000).map(|_| day + (random.next() % 68_400) as i64 * 1_000_000).collect();
981 let bytes = round_trip(&values);
982 assert_eq!(kind_of(&bytes), Kind::Strided);
983 assert!(describe(&bytes).unwrap().starts_with("STRIDE[1000000]"), "{:?}", describe(&bytes));
984 let strided = 100_000 * 17 / 8;
986 assert!(bytes.len() < strided + 2000, "{} bytes for {strided} of payload", bytes.len());
987
988 let plain = encode_only(Kind::Packed, &values).unwrap().expect("packing always applies");
989 assert!(
990 bytes.len() * 2 < plain.len(),
991 "{} strided against {} packed",
992 bytes.len(),
993 plain.len()
994 );
995 }
996
997 #[test]
998 fn a_stride_is_the_common_factor_of_the_distances_from_the_smallest_value() {
999 assert_eq!(stride_of(&[10i64, 20, 40]), Some(10));
1000 assert_eq!(stride_of(&[7i64, 17, 37]), Some(10));
1003 assert_eq!(stride_of(&[10i64, 20, 23]), None);
1004 assert_eq!(stride_of(&[5i64; 100]), None);
1007 assert_eq!(stride_of(&[]), None);
1008 assert_eq!(stride_of(&[i64::MIN, i64::MAX]), Some(u64::MAX));
1010 }
1011
1012 #[test]
1013 fn a_stride_across_the_whole_of_the_type_round_trips() {
1014 for values in [vec![i64::MIN, i64::MAX], vec![i64::MIN, 0, i64::MAX]] {
1017 let bytes = round_trip(&values);
1018 assert_eq!(decode(&bytes).unwrap(), values);
1019 }
1020 }
1021
1022 #[test]
1023 fn a_column_with_no_common_factor_is_not_offered_a_stride() {
1024 let mut random = Random::new();
1025 let values: Vec<i64> = (0..2000).map(|_| (random.next() % 1_000_000) as i64).collect();
1026 assert!(!offered(&values).contains(&Kind::Strided));
1027 assert!(encode_only(Kind::Strided, &values).unwrap().is_none());
1028 }
1029
1030 #[test]
1031 fn an_empty_chunk_round_trips() {
1032 let bytes = round_trip(&[]);
1033 assert_eq!(bytes.len(), 5);
1034 }
1035
1036 #[test]
1037 fn a_constant_column_costs_thirteen_bytes_however_long_it_is() {
1038 let bytes = round_trip(&vec![42; 1_000_000]);
1039 assert_eq!(kind_of(&bytes), Kind::Constant);
1040 assert_eq!(bytes.len(), 13);
1041 }
1042
1043 #[test]
1044 fn a_narrow_range_is_packed_at_the_width_of_the_range_and_not_of_the_type() {
1045 let mut random = Random::new();
1047 let values: Vec<i64> = (0..100_000).map(|_| 1000 + (random.next() % 64) as i64).collect();
1048 let bytes = round_trip(&values);
1049 assert_eq!(kind_of(&bytes), Kind::Packed);
1050 let packed = 100_000 * 6 / 8;
1051 assert!(bytes.len() < packed + 2000, "{} bytes for {packed} of payload", bytes.len());
1052 assert!(bytes.len() > packed, "{} bytes cannot hold {packed}", bytes.len());
1053 }
1054
1055 #[test]
1056 fn a_counter_becomes_deltas_and_then_a_constant() {
1057 let values: Vec<i64> = (0..1_000_000).collect();
1060 let bytes = round_trip(&values);
1061 assert_eq!(kind_of(&bytes), Kind::Delta);
1062 assert_eq!(describe(&bytes).unwrap(), "DELTA(CONSTANT)");
1063 assert!(bytes.len() < 40, "{} bytes for a counter", bytes.len());
1064 }
1065
1066 #[test]
1067 fn a_column_that_counts_down_is_as_cheap_as_one_that_counts_up() {
1068 let up: Vec<i64> = (0..100_000).collect();
1070 let down: Vec<i64> = (0..100_000).rev().collect();
1071 assert_eq!(round_trip(&up).len(), round_trip(&down).len());
1072 }
1073
1074 #[test]
1075 fn long_runs_become_rle() {
1076 let mut values = Vec::new();
1077 for run in 0..1000 {
1078 values.extend(std::iter::repeat_n(run % 7, 200));
1079 }
1080 let bytes = round_trip(&values);
1081 assert_eq!(kind_of(&bytes), Kind::Rle);
1082 assert!(bytes.len() < 2000, "{} bytes for 1000 runs", bytes.len());
1083 }
1084
1085 #[test]
1086 fn a_low_cardinality_column_becomes_a_dictionary() {
1087 let mut random = Random::new();
1093 let dictionary: Vec<i64> =
1094 (0..40).map(|_| 1_000_000_000 + (random.next() % (1 << 30)) as i64).collect();
1095 let values: Vec<i64> =
1096 (0..100_000).map(|_| dictionary[(random.next() % 40) as usize]).collect();
1097 let bytes = round_trip(&values);
1098 assert_eq!(kind_of(&bytes), Kind::Dict);
1099 assert!(bytes.len() < 100_000, "{} bytes", bytes.len());
1100 }
1101
1102 #[test]
1103 fn a_nearly_constant_column_becomes_sparse() {
1104 let mut values = vec![0i64; 100_000];
1105 for index in 0..300 {
1106 values[index * 331] = 1 << 40;
1107 }
1108 let bytes = round_trip(&values);
1109 assert_eq!(kind_of(&bytes), Kind::Sparse);
1110 assert!(bytes.len() < 3000, "{} bytes for 300 exceptions", bytes.len());
1111 }
1112
1113 #[test]
1114 fn the_cascade_goes_more_than_one_level_deep() {
1115 let mut values = Vec::new();
1118 for index in 0..2000i64 {
1119 values.extend(std::iter::repeat_n(1_000_000 + (index % 5) * 104_729, 100));
1120 }
1121 let bytes = round_trip(&values);
1122 let shape = describe(&bytes).unwrap();
1123 assert!(shape.contains('('), "{shape} is not a cascade");
1124 assert!(bytes.len() < 4000, "{} bytes: {shape}", bytes.len());
1125 }
1126
1127 #[test]
1128 fn random_data_is_packed_at_full_width_and_costs_what_it_costs() {
1129 let mut random = Random::new();
1132 let values: Vec<i64> = (0..10_000).map(|_| random.next() as i64).collect();
1133 let bytes = round_trip(&values);
1134 assert_eq!(kind_of(&bytes), Kind::Packed);
1135 assert!(bytes.len() < 10_000 * 8 + 1000, "{} bytes", bytes.len());
1136 }
1137
1138 #[test]
1139 fn the_extremes_of_the_type_survive() {
1140 let values = vec![i64::MIN, i64::MAX, 0, -1, i64::MIN, i64::MAX];
1143 round_trip(&values);
1144 round_trip(&[i64::MIN; 3]);
1145 round_trip(&[i64::MIN, i64::MIN + 1]);
1146 }
1147
1148 #[test]
1149 fn a_chunk_that_is_not_a_multiple_of_the_unit_round_trips() {
1150 for len in [1, 2, 1023, 1024, 1025, 2047, 2049] {
1151 let values: Vec<i64> = (0..len).map(|index| (index * 31 % 97) as i64).collect();
1152 round_trip(&values);
1153 }
1154 }
1155
1156 #[test]
1157 fn units_of_different_widths_in_one_chunk_do_not_read_each_others_leftovers() {
1158 let mut random = Random::new();
1170 let mut values = Vec::new();
1171 for width in [40u32, 3, 61, 1, 17, 40] {
1172 for _ in 0..1024 {
1173 values.push((random.next() & ((1u64 << width) - 1)) as i64);
1174 }
1175 }
1176 let bytes = encode(&values).unwrap();
1177 let described = describe(&bytes).unwrap();
1178 assert!(described.starts_with("FOR+BITPACK"), "expected one packed chunk, got {described}");
1179 assert_eq!(decode(&bytes).unwrap(), values, "{described}");
1180 }
1181
1182 #[test]
1183 fn a_cascade_decodes_the_same_through_a_shared_scratch_as_through_its_own() {
1184 let mut values = Vec::new();
1189 for index in 0..8192i64 {
1190 values.push(1_600_000_000 + index / 4 + (index % 7) * 1_000);
1191 }
1192 let bytes = encode(&values).unwrap();
1193 let described = describe(&bytes).unwrap();
1194 assert!(described.contains('('), "expected a cascade, got {described}");
1195 assert_eq!(decode(&bytes).unwrap(), values, "{described}");
1196 }
1197
1198 #[test]
1199 fn a_partial_unit_costs_its_own_values_and_not_a_whole_unit() {
1200 let values = vec![1i64 << 39, (1 << 39) + 7, 1 << 38];
1204 let bytes = encode_only(Kind::Packed, &values).unwrap().unwrap();
1205 assert_eq!(bytes.len(), 5 + 9 + 15);
1206 assert_eq!(decode(&bytes).unwrap(), values);
1207 }
1208
1209 #[test]
1210 fn the_frame_of_reference_is_per_unit_and_not_per_chunk() {
1211 let values: Vec<i64> =
1215 (0..4096i64).map(|index| (index / 1024) * 1_000_000 + (index % 1024)).collect();
1216 let bytes = encode_only(Kind::Packed, &values).unwrap().unwrap();
1217 assert_eq!(describe(&bytes).unwrap(), "FOR+BITPACK[10]");
1218 assert_eq!(decode(&bytes).unwrap(), values);
1219 }
1220
1221 #[test]
1222 fn every_candidate_that_applies_decodes_to_the_input() {
1223 let mut values = vec![5i64; 3000];
1227 for (index, value) in values.iter_mut().enumerate() {
1228 if index % 500 == 0 {
1229 *value = index as i64;
1230 }
1231 }
1232 let applicable = candidates(&values, 0);
1233 assert!(applicable.len() >= 4, "{applicable:?}");
1234 for kind in applicable {
1235 let bytes = encode_only(kind, &values).unwrap().unwrap();
1236 assert_eq!(decode(&bytes).unwrap(), values, "{}", kind.name());
1237 }
1238 }
1239
1240 #[test]
1245 fn every_kind_that_applies_decodes_to_what_it_was_given() {
1246 let shapes: Vec<Vec<i64>> = vec![
1247 Vec::new(),
1248 vec![5; 1024],
1249 vec![i64::MIN, i64::MAX, 0, -1],
1250 (0..1024).map(|at| at * 7).collect(),
1251 (0..1024).map(|at| at % 17).collect(),
1252 (0..1024).map(|at| if at % 100 == 0 { at } else { 3 }).collect(),
1253 (0..1024).map(|at| -at * 1_000_003).collect(),
1254 (0..1024_i64)
1255 .map(|at| {
1256 at.wrapping_mul(6_364_136_223_846_793_005)
1257 .wrapping_add(1_442_695_040_888_963_407)
1258 })
1259 .collect(),
1260 ];
1261 let kinds =
1262 [Kind::Constant, Kind::Packed, Kind::Delta, Kind::Rle, Kind::Dict, Kind::Sparse];
1263 for values in &shapes {
1264 for kind in kinds {
1265 let Some(bytes) = encode_only(kind, values).unwrap() else {
1266 continue;
1267 };
1268 assert_eq!(
1269 &decode(&bytes).unwrap(),
1270 values,
1271 "{} over {} values",
1272 kind.name(),
1273 values.len()
1274 );
1275 }
1276 }
1277 }
1278
1279 #[test]
1280 fn the_chooser_picks_the_smallest_candidate_rather_than_the_first_that_applies() {
1281 let mut values = vec![5i64; 3000];
1282 values[1500] = 9;
1283 let chosen = encode(&values).unwrap();
1284 for (_, size) in candidate_sizes(&values).unwrap() {
1285 assert!(chosen.len() <= size);
1286 }
1287 }
1288
1289 #[test]
1290 fn a_truncated_chunk_is_an_error_and_not_a_panic() {
1291 let bytes = encode(&[1, 2, 3, 4, 5]).unwrap();
1292 for len in 0..bytes.len() {
1293 let error = decode(&bytes[..len]).unwrap_err();
1294 assert!(error.message().contains("chunk"), "{error}");
1295 }
1296 }
1297
1298 #[test]
1299 fn trailing_bytes_are_an_error() {
1300 let mut bytes = encode(&[1, 2, 3]).unwrap();
1301 bytes.push(0);
1302 let error = decode(&bytes).unwrap_err();
1303 assert!(error.message().contains("left over"), "{error}");
1304 }
1305
1306 #[test]
1307 fn an_unknown_tag_is_an_error() {
1308 let error = decode(&[99, 0, 0, 0, 0]).unwrap_err();
1309 assert!(error.message().contains("unknown encoding tag"), "{error}");
1310 }
1311
1312 #[test]
1313 fn a_dictionary_code_outside_the_dictionary_is_an_error() {
1314 let mut bytes = vec![Kind::Dict.tag()];
1319 put_u32(&mut bytes, 1);
1320 bytes.extend_from_slice(&encode(&[10]).unwrap());
1321 bytes.extend_from_slice(&encode(&[5]).unwrap());
1322 let error = decode(&bytes).unwrap_err();
1323 assert!(error.message().contains("not in the dictionary"), "{error}");
1324 }
1325
1326 #[test]
1327 fn a_negative_run_length_is_an_error() {
1328 let mut bytes = vec![Kind::Rle.tag()];
1331 put_u32(&mut bytes, 4);
1332 bytes.extend_from_slice(&encode(&[7]).unwrap());
1333 bytes.extend_from_slice(&encode(&[-4]).unwrap());
1334 let error = decode(&bytes).unwrap_err();
1335 assert!(error.message().contains("negative"), "{error}");
1336 }
1337
1338 #[test]
1339 fn the_cascade_depth_is_bounded() {
1340 let values: Vec<i64> = (0..50_000).map(|index| (index / 100) % 250).collect();
1344 let bytes = round_trip(&values);
1345 let shape = describe(&bytes).unwrap();
1346 let depth = shape.matches('(').count();
1347 assert!(depth <= MAX_DEPTH as usize, "{shape} is {depth} deep");
1348 }
1349
1350 #[test]
1351 fn candidate_sizes_reports_what_the_chooser_looked_at() {
1352 let values: Vec<i64> = (0..5000).map(|index| index % 17).collect();
1353 let sizes = candidate_sizes(&values).unwrap();
1354 assert!(sizes.iter().any(|(kind, _)| *kind == Kind::Dict));
1355 assert!(sizes.iter().any(|(kind, _)| *kind == Kind::Packed));
1356 assert!(sizes.iter().all(|(_, size)| *size > 0));
1357 }
1358
1359 #[test]
1360 fn a_chunk_can_be_read_from_the_front_of_a_longer_buffer() {
1361 let first = encode(&[1, 2, 3]).unwrap();
1364 let second: Vec<i64> = (0..3000).map(|index| index % 11).collect();
1365 let second_bytes = encode(&second).unwrap();
1366 let mut joined = first.clone();
1367 joined.extend_from_slice(&second_bytes);
1368 joined.extend_from_slice(b"and then something else");
1369
1370 let (values, used) = decode_prefix(&joined).unwrap();
1371 assert_eq!(values, vec![1, 2, 3]);
1372 assert_eq!(used, first.len());
1373 let (more, used_again) = decode_prefix(&joined[used..]).unwrap();
1374 assert_eq!(more, second);
1375 assert_eq!(used_again, second_bytes.len());
1376
1377 let (text, described) = describe_prefix(&joined).unwrap();
1378 assert_eq!(described, first.len());
1379 assert_eq!(text, describe(&first).unwrap());
1380 }
1381
1382 #[test]
1383 fn a_truncated_chunk_is_still_an_error_when_read_as_a_prefix() {
1384 let bytes = encode(&(0..2000).collect::<Vec<i64>>()).unwrap();
1385 for len in 0..bytes.len() {
1386 assert!(decode_prefix(&bytes[..len]).is_err(), "{len} bytes decoded");
1387 }
1388 }
1389}