1use yo_common::{Code, Error, Result};
53
54pub const P: u32 = 14;
56pub const REGISTERS: usize = 1 << P;
58pub const Q: u32 = 64 - P;
60const BITS: usize = 6;
62const REGISTER_MAX: u32 = 63;
64pub const HDR: usize = 16;
66pub const DENSE: usize = HDR + REGISTERS * BITS / 8;
68pub const SPARSE_MAX: usize = 3000;
74
75const MAGIC: [u8; 4] = *b"HYLL";
77const DENSE_TAG: u8 = 0;
79const SPARSE_TAG: u8 = 1;
81const SEED: u64 = 0xadc8_3b19;
83
84const XZERO_BIT: u8 = 0x40;
86const VAL_BIT: u8 = 0x80;
88const ZERO_MAX: usize = 64;
90const VAL_MAX: u8 = 32;
92const VAL_MAX_LEN: usize = 4;
94
95const NOT_HLL: &str = "Key is not a valid HyperLogLog string value.";
101const CORRUPT: &str = "Corrupted HLL object detected";
103
104#[derive(Debug, Clone, Copy, PartialEq, Eq)]
106pub enum Encoding {
107 Dense,
109 Sparse,
112}
113
114impl Encoding {
115 #[must_use]
117 pub const fn name(self) -> &'static str {
118 match self {
119 Encoding::Dense => "dense",
120 Encoding::Sparse => "sparse",
121 }
122 }
123}
124
125#[must_use]
127pub fn not_hll() -> Error {
128 Error::new(Code::WrongType, NOT_HLL)
129}
130
131#[must_use]
138pub fn corrupt() -> Error {
139 Error::new(Code::Corrupt, CORRUPT)
140}
141
142#[must_use]
149pub fn hash(ele: &[u8]) -> u64 {
150 const M: u64 = 0xc6a4_a793_5bd1_e995;
151 const R: u32 = 47;
152 let mut h = SEED ^ (ele.len() as u64).wrapping_mul(M);
153 let (blocks, tail) = ele.as_chunks::<8>();
154 for block in blocks {
155 let mut k = u64::from_le_bytes(*block);
156 k = k.wrapping_mul(M);
157 k ^= k >> R;
158 k = k.wrapping_mul(M);
159 h ^= k;
160 h = h.wrapping_mul(M);
161 }
162 if !tail.is_empty() {
163 for (i, &b) in tail.iter().enumerate() {
164 h ^= u64::from(b) << (8 * i);
165 }
166 h = h.wrapping_mul(M);
167 }
168 h ^= h >> R;
169 h = h.wrapping_mul(M);
170 h ^= h >> R;
171 h
172}
173
174#[must_use]
181pub fn place(ele: &[u8]) -> (usize, u8) {
182 let h = hash(ele);
183 let index = (h & (REGISTERS as u64 - 1)) as usize;
184 let rest = (h >> P) | (1 << Q);
185 (index, rest.trailing_zeros() as u8 + 1)
186}
187
188pub fn empty(out: &mut Vec<u8>) {
190 out.clear();
191 out.extend_from_slice(&MAGIC);
192 out.push(SPARSE_TAG);
193 out.extend_from_slice(&[0; 3]);
194 out.extend_from_slice(&[0; 8]);
195 let mut left = REGISTERS;
196 while left > 0 {
197 let run = left.min(1 << P);
198 out.extend_from_slice(&xzero_bytes(run));
199 left -= run;
200 }
201}
202
203pub fn check(bytes: &[u8]) -> Result<Encoding> {
210 if bytes.len() < HDR || bytes[..4] != MAGIC {
211 return Err(not_hll());
212 }
213 match bytes[4] {
214 DENSE_TAG if bytes.len() == DENSE => Ok(Encoding::Dense),
215 SPARSE_TAG => Ok(Encoding::Sparse),
216 _ => Err(not_hll()),
217 }
218}
219
220#[must_use]
222pub fn cached(bytes: &[u8]) -> Option<u64> {
223 let card = u64::from_le_bytes(bytes[8..16].try_into().expect("eight bytes"));
224 (card >> 63 == 0).then_some(card)
225}
226
227pub fn cache(bytes: &mut [u8], n: u64) {
229 bytes[8..16].copy_from_slice(&(n & !(1 << 63)).to_le_bytes());
230}
231
232pub fn invalidate(bytes: &mut [u8]) {
234 bytes[15] |= 0x80;
235}
236
237#[must_use]
244#[inline]
245pub fn dense_get(regs: &[u8], index: usize) -> u8 {
246 let bit = index * BITS;
247 let (byte, shift) = (bit / 8, (bit % 8) as u32);
248 let low = u32::from(regs[byte]);
249 let high = regs.get(byte + 1).map_or(0, |&b| u32::from(b));
250 (((low >> shift) | (high << (8 - shift))) & REGISTER_MAX) as u8
251}
252
253#[inline]
258pub fn dense_set(regs: &mut [u8], index: usize, val: u8) -> bool {
259 if dense_get(regs, index) >= val {
260 return false;
261 }
262 let bit = index * BITS;
263 let (byte, shift) = (bit / 8, (bit % 8) as u32);
264 let v = u32::from(val);
265 regs[byte] = ((u32::from(regs[byte]) & !(REGISTER_MAX << shift)) | (v << shift)) as u8;
266 if shift > 2 {
267 let rest = 8 - shift;
268 let high = &mut regs[byte + 1];
269 *high = ((u32::from(*high) & !(REGISTER_MAX >> rest)) | (v >> rest)) as u8;
270 }
271 true
272}
273
274const fn is_zero(b: u8) -> bool {
276 b & 0xc0 == 0
277}
278
279const fn is_xzero(b: u8) -> bool {
281 b & 0xc0 == XZERO_BIT
282}
283
284const fn is_val(b: u8) -> bool {
286 b & VAL_BIT != 0
287}
288
289const fn zero_len(b: u8) -> usize {
291 (b & 0x3f) as usize + 1
292}
293
294const fn xzero_len(a: u8, b: u8) -> usize {
296 (((a & 0x3f) as usize) << 8 | b as usize) + 1
297}
298
299const fn val_value(b: u8) -> u8 {
301 ((b >> 2) & 0x1f) + 1
302}
303
304const fn val_len(b: u8) -> usize {
306 (b & 3) as usize + 1
307}
308
309const fn val_byte(val: u8, len: usize) -> u8 {
311 ((val - 1) << 2) | (len as u8 - 1) | VAL_BIT
312}
313
314const fn zero_byte(len: usize) -> u8 {
316 (len - 1) as u8
317}
318
319const fn xzero_bytes(len: usize) -> [u8; 2] {
321 let n = len - 1;
322 [((n >> 8) as u8) | XZERO_BIT, (n & 0xff) as u8]
323}
324
325fn opcode(sparse: &[u8], at: usize) -> Option<(usize, usize)> {
327 let b = *sparse.get(at)?;
328 if is_zero(b) {
329 Some((zero_len(b), 1))
330 } else if is_xzero(b) {
331 Some((xzero_len(b, *sparse.get(at + 1)?), 2))
332 } else {
333 Some((val_len(b), 1))
334 }
335}
336
337fn walk(sparse: &[u8], mut each: impl FnMut(u8, usize, usize)) -> bool {
343 let mut at = 0;
344 let mut index = 0;
345 while at < sparse.len() {
346 let b = sparse[at];
347 if is_val(b) {
348 let len = val_len(b);
349 if index + len > REGISTERS {
350 return false;
351 }
352 each(val_value(b), index, len);
353 index += len;
354 at += 1;
355 } else if is_zero(b) {
356 index += zero_len(b);
357 at += 1;
358 } else {
359 let Some(&next) = sparse.get(at + 1) else {
360 return false;
361 };
362 index += xzero_len(b, next);
363 at += 2;
364 }
365 }
366 index == REGISTERS
367}
368
369pub fn to_dense(buf: &mut Vec<u8>) -> bool {
375 if buf[4] == DENSE_TAG {
376 return true;
377 }
378 let mut regs = [0u8; REGISTERS];
379 if !walk(&buf[HDR..], |val, at, len| {
380 regs[at..at + len].fill(val);
381 }) {
382 return false;
383 }
384 buf.truncate(HDR);
385 buf.resize(DENSE, 0);
386 buf[4] = DENSE_TAG;
387 let body = &mut buf[HDR..];
388 for (i, &val) in regs.iter().enumerate() {
389 if val != 0 {
390 dense_set(body, i, val);
391 }
392 }
393 true
394}
395
396pub fn set(buf: &mut Vec<u8>, index: usize, val: u8) -> Option<bool> {
402 if buf[4] == DENSE_TAG {
403 let changed = dense_set(&mut buf[HDR..], index, val);
404 if changed {
405 invalidate(buf);
406 }
407 return Some(changed);
408 }
409 if val > VAL_MAX {
410 return promote(buf, index, val);
411 }
412
413 let (mut at, mut first, mut prev, mut span) = (HDR, 0usize, None, 0usize);
416 while at < buf.len() {
417 let (covers, bytes) = opcode(buf, at)?;
418 span = covers;
419 if index < first + span {
420 break;
421 }
422 prev = Some(at);
423 at += bytes;
424 first += span;
425 }
426 if span == 0 || at >= buf.len() {
427 return None;
428 }
429
430 let here = buf[at];
431 let (zero, xzero, run) = if is_val(here) {
432 (false, false, val_len(here))
433 } else if is_zero(here) {
434 (true, false, zero_len(here))
435 } else {
436 (false, true, xzero_len(here, *buf.get(at + 1)?))
437 };
438
439 if is_val(here) {
443 if val_value(here) >= val {
444 return Some(false);
445 }
446 if run == 1 {
447 buf[at] = val_byte(val, 1);
448 return Some(finish(buf, prev));
449 }
450 }
451 if zero && run == 1 {
452 buf[at] = val_byte(val, 1);
453 return Some(finish(buf, prev));
454 }
455
456 let mut seq = [0u8; 5];
459 let mut n = 0;
460 let last = first + span - 1;
461 let gap = |seq: &mut [u8; 5], n: &mut usize, len: usize| {
462 if len > ZERO_MAX {
463 seq[*n..*n + 2].copy_from_slice(&xzero_bytes(len));
464 *n += 2;
465 } else {
466 seq[*n] = zero_byte(len);
467 *n += 1;
468 }
469 };
470 if zero || xzero {
471 if index != first {
472 gap(&mut seq, &mut n, index - first);
473 }
474 seq[n] = val_byte(val, 1);
475 n += 1;
476 if index != last {
477 gap(&mut seq, &mut n, last - index);
478 }
479 } else {
480 let had = val_value(here);
481 if index != first {
482 seq[n] = val_byte(had, index - first);
483 n += 1;
484 }
485 seq[n] = val_byte(val, 1);
486 n += 1;
487 if index != last {
488 seq[n] = val_byte(had, last - index);
489 n += 1;
490 }
491 }
492
493 let old = if xzero { 2 } else { 1 };
497 let end = buf.len();
498 if n > old && end + (n - old) > SPARSE_MAX {
499 return promote(buf, index, val);
500 }
501 if n > old {
502 buf.resize(end + (n - old), 0);
503 buf.copy_within(at + old..end, at + n);
504 } else if n < old {
505 buf.copy_within(at + old..end, at + n);
506 buf.truncate(end - (old - n));
507 }
508 buf[at..at + n].copy_from_slice(&seq[..n]);
509 Some(finish(buf, prev))
510}
511
512fn promote(buf: &mut Vec<u8>, index: usize, val: u8) -> Option<bool> {
514 if !to_dense(buf) {
515 return None;
516 }
517 let changed = dense_set(&mut buf[HDR..], index, val);
518 invalidate(buf);
519 Some(changed)
520}
521
522fn finish(buf: &mut Vec<u8>, prev: Option<usize>) -> bool {
530 let mut at = prev.unwrap_or(HDR);
531 let mut left = 5;
532 while at < buf.len() && left > 0 {
533 left -= 1;
534 let b = buf[at];
535 if is_xzero(b) {
536 at += 2;
537 continue;
538 }
539 if is_zero(b) {
540 at += 1;
541 continue;
542 }
543 if let Some(&next) = buf.get(at + 1)
544 && is_val(next)
545 && val_value(b) == val_value(next)
546 {
547 let len = val_len(b) + val_len(next);
548 if len <= VAL_MAX_LEN {
549 buf[at + 1] = val_byte(val_value(b), len);
550 let end = buf.len();
551 buf.copy_within(at + 1..end, at);
552 buf.truncate(end - 1);
553 continue;
556 }
557 }
558 at += 1;
559 }
560 invalidate(buf);
561 true
562}
563
564fn histogram(bytes: &[u8], enc: Encoding) -> Option<[u32; 64]> {
568 let mut hist = [0u32; 64];
569 match enc {
570 Encoding::Dense => {
571 let regs = &bytes[HDR..];
572 for i in 0..REGISTERS {
573 hist[dense_get(regs, i) as usize] += 1;
574 }
575 }
576 Encoding::Sparse => {
577 let mut seen = 0;
578 if !walk(&bytes[HDR..], |val, _, len| {
579 hist[val as usize] += len as u32;
580 seen += len as u32;
581 }) {
582 return None;
583 }
584 hist[0] = REGISTERS as u32 - seen;
585 }
586 }
587 Some(hist)
588}
589
590pub fn merge(max: &mut [u8; REGISTERS], bytes: &[u8], enc: Encoding) -> bool {
596 match enc {
597 Encoding::Dense => {
598 let regs = &bytes[HDR..];
599 for (i, slot) in max.iter_mut().enumerate() {
600 *slot = (*slot).max(dense_get(regs, i));
601 }
602 true
603 }
604 Encoding::Sparse => walk(&bytes[HDR..], |val, at, len| {
605 for slot in &mut max[at..at + len] {
606 *slot = (*slot).max(val);
607 }
608 }),
609 }
610}
611
612fn tau(mut x: f64) -> f64 {
614 if x == 0.0 || x == 1.0 {
615 return 0.0;
616 }
617 let mut y = 1.0;
618 let mut z = 1.0 - x;
619 loop {
620 x = x.sqrt();
621 let was = z;
622 y *= 0.5;
623 z -= (1.0 - x).powi(2) * y;
624 if was == z {
625 return z / 3.0;
626 }
627 }
628}
629
630fn sigma(mut x: f64) -> f64 {
632 if x == 1.0 {
633 return f64::INFINITY;
634 }
635 let mut y = 1.0;
636 let mut z = x;
637 loop {
638 x *= x;
639 let was = z;
640 z += x * y;
641 y += y;
642 if was == z {
643 return z;
644 }
645 }
646}
647
648#[must_use]
657pub fn estimate(hist: &[u32; 64]) -> u64 {
658 const ALPHA_INF: f64 = 0.721_347_520_444_481_7;
662 let m = REGISTERS as f64;
663 let mut z = m * tau((m - f64::from(hist[Q as usize + 1])) / m);
664 for j in (1..=Q as usize).rev() {
665 z += f64::from(hist[j]);
666 z *= 0.5;
667 }
668 z += m * sigma(f64::from(hist[0]) / m);
669 (ALPHA_INF * m * m / z).round() as u64
670}
671
672pub fn count(bytes: &[u8], enc: Encoding) -> Result<u64> {
674 match histogram(bytes, enc) {
675 Some(hist) => Ok(estimate(&hist)),
676 None => Err(corrupt()),
677 }
678}
679
680pub fn decode(bytes: &[u8], out: &mut Vec<u8>) {
688 use std::io::Write;
689 let sparse = &bytes[HDR..];
690 let mut at = 0;
691 while at < sparse.len() {
692 if !out.is_empty() {
693 out.push(b' ');
694 }
695 let b = sparse[at];
696 if is_val(b) {
697 let _ = write!(out, "v:{},{}", val_value(b), val_len(b));
698 at += 1;
699 } else if is_zero(b) {
700 let _ = write!(out, "z:{}", zero_len(b));
701 at += 1;
702 } else {
703 let Some(&next) = sparse.get(at + 1) else {
704 return;
705 };
706 let _ = write!(out, "Z:{}", xzero_len(b, next));
707 at += 2;
708 }
709 }
710}
711
712#[cfg(test)]
713mod tests {
714 use super::*;
715 use crate::many;
716
717 #[test]
723 fn an_element_lands_where_a_real_server_puts_it() {
724 assert_eq!(place(b"a"), (12711, 2));
725 assert_eq!(place(b"b"), (15780, 1));
726 assert_eq!(place(b"c"), (8436, 1));
727 }
728
729 #[test]
737 fn a_sketch_is_the_bytes_a_real_server_writes() {
738 let mut buf = Vec::new();
739 empty(&mut buf);
740 assert_eq!(buf.len(), 18);
741 assert_eq!(&buf[..], b"HYLL\x01\0\0\0\0\0\0\0\0\0\0\0\x7f\xff");
742 invalidate(&mut buf);
743 assert_eq!(&buf[..], b"HYLL\x01\0\0\0\0\0\0\0\0\0\0\x80\x7f\xff");
744
745 for ele in [&b"a"[..], b"b", b"c"] {
746 let (index, val) = place(ele);
747 assert_eq!(set(&mut buf, index, val), Some(true));
748 }
749 assert_eq!(
750 &buf[..],
751 b"HYLL\x01\0\0\0\0\0\0\0\0\0\0\x80\x60\xf3\x80\x50\xb1\x84\x4b\xfb\x80\x42\x5a"
752 );
753 }
754
755 #[test]
757 fn writing_the_same_element_twice_is_not_a_change() {
758 let mut buf = Vec::new();
759 empty(&mut buf);
760 let (index, val) = place(b"a");
761 assert_eq!(set(&mut buf, index, val), Some(true));
762 let before = buf.clone();
763 assert_eq!(set(&mut buf, index, val), Some(false));
764 assert_eq!(buf, before);
765 }
766
767 #[test]
769 fn a_dense_register_is_six_bits_packed_from_the_bottom() {
770 let mut regs = vec![0u8; REGISTERS * BITS / 8];
771 let mut want = vec![0u8; REGISTERS];
772 for (i, slot) in want.iter_mut().enumerate() {
773 *slot = ((i * 7 + 1) % 52) as u8;
774 }
775 for step in [1usize, 3, 5] {
778 let mut i = 0;
779 while i < REGISTERS {
780 let val = want[i];
781 if val > dense_get(®s, i) {
782 assert!(dense_set(&mut regs, i, val));
783 }
784 i += step;
785 }
786 }
787 for (i, &val) in want.iter().enumerate() {
788 assert_eq!(dense_get(®s, i), val, "register {i}");
789 }
790 assert!(!dense_set(&mut regs, 5, 0));
792 }
793
794 #[test]
796 fn turning_dense_keeps_every_register() {
797 let mut buf = Vec::new();
798 empty(&mut buf);
799 let mut want = [0u8; REGISTERS];
800 for i in 0..400 {
801 let ele = format!("e:{i}");
802 let (index, val) = place(ele.as_bytes());
803 set(&mut buf, index, val).expect("a write");
804 want[index] = want[index].max(val);
805 }
806 let sparse = count(&buf, Encoding::Sparse).expect("a count");
807
808 assert!(to_dense(&mut buf));
809 assert_eq!(buf.len(), DENSE);
810 assert_eq!(check(&buf).expect("a sketch"), Encoding::Dense);
811 for (i, &val) in want.iter().enumerate() {
812 assert_eq!(dense_get(&buf[HDR..], i), val, "register {i}");
813 }
814 assert_eq!(count(&buf, Encoding::Dense).expect("a count"), sparse);
815 }
816
817 #[test]
819 #[cfg_attr(
820 miri,
821 ignore = "fewer elements do not outgrow the sparse form, which is the claim"
822 )]
823 fn a_sketch_turns_dense_when_it_outgrows_the_sparse_form() {
824 let mut buf = Vec::new();
825 empty(&mut buf);
826 for i in 0..2000 {
827 let ele = format!("e:{i}");
828 let (index, val) = place(ele.as_bytes());
829 set(&mut buf, index, val).expect("a write");
830 assert!(buf.len() <= SPARSE_MAX || buf.len() == DENSE);
831 }
832 assert_eq!(check(&buf).expect("a sketch"), Encoding::Dense);
833 }
834
835 #[test]
837 fn a_large_register_turns_the_sketch_dense() {
838 let mut buf = Vec::new();
839 empty(&mut buf);
840 assert_eq!(set(&mut buf, 100, VAL_MAX), Some(true));
841 assert_eq!(check(&buf).expect("a sketch"), Encoding::Sparse);
842 assert_eq!(set(&mut buf, 200, VAL_MAX + 1), Some(true));
843 assert_eq!(check(&buf).expect("a sketch"), Encoding::Dense);
844 assert_eq!(dense_get(&buf[HDR..], 100), VAL_MAX);
845 assert_eq!(dense_get(&buf[HDR..], 200), VAL_MAX + 1);
846 }
847
848 #[test]
853 fn neighbouring_runs_of_the_same_value_are_joined() {
854 let mut buf = Vec::new();
855 empty(&mut buf);
856 for i in 0..4 {
857 set(&mut buf, 100 + i, 1).expect("a write");
858 }
859 let mut decoded = Vec::new();
860 decode(&buf, &mut decoded);
861 assert_eq!(decoded, b"Z:100 v:1,4 Z:16280");
862 }
863
864 #[test]
871 fn all_three_opcodes_decode_the_way_a_real_server_prints_them() {
872 let mut buf = Vec::new();
873 empty(&mut buf);
874 buf.truncate(HDR);
875 buf.extend_from_slice(&xzero_bytes(100));
876 buf.push(val_byte(1, 4));
877 buf.push(zero_byte(10));
878 buf.push(val_byte(3, 2));
879 buf.extend_from_slice(&xzero_bytes(REGISTERS - 100 - 4 - 10 - 2));
880
881 let mut decoded = Vec::new();
882 decode(&buf, &mut decoded);
883 assert_eq!(decoded, b"Z:100 v:1,4 z:10 v:3,2 Z:16268");
884 assert_eq!(count(&buf, Encoding::Sparse).expect("a count"), 6);
885 }
886
887 #[test]
893 #[cfg_attr(
894 miri,
895 ignore = "an error bound only means something at the sizes that produce it"
896 )]
897 fn the_estimate_is_close_to_the_truth() {
898 for n in [10usize, 100, 1000, 10_000, 100_000] {
899 let mut buf = Vec::new();
900 empty(&mut buf);
901 for i in 0..n {
902 let ele = format!("element:{i}");
903 let (index, val) = place(ele.as_bytes());
904 set(&mut buf, index, val).expect("a write");
905 }
906 let enc = check(&buf).expect("a sketch");
907 let got = count(&buf, enc).expect("a count") as f64;
908 let off = (got - n as f64).abs() / n as f64;
909 assert!(off < 0.02, "{n} counted as {got}");
910 }
911 }
912
913 #[test]
918 #[cfg_attr(
919 miri,
920 ignore = "the counts are the claim, so there is no smaller version of it"
921 )]
922 fn the_estimate_is_the_number_a_real_server_gives() {
923 for (n, want) in [(100usize, 100u64), (1000, 995), (10_000, 10_077)] {
924 let mut buf = Vec::new();
925 empty(&mut buf);
926 for i in 0..n {
927 let ele = format!("e:{i}");
928 let (index, val) = place(ele.as_bytes());
929 set(&mut buf, index, val).expect("a write");
930 }
931 let enc = check(&buf).expect("a sketch");
932 assert_eq!(count(&buf, enc).expect("a count"), want, "{n} elements");
933 }
934 }
935
936 #[test]
938 #[cfg_attr(
939 miri,
940 ignore = "the sizes are the claim, and only these counts reach them"
941 )]
942 fn the_two_sizes_are_the_ones_a_real_server_has() {
943 let build = |n: usize| {
944 let mut buf = Vec::new();
945 empty(&mut buf);
946 for i in 0..n {
947 let ele = format!("e:{i}");
948 let (index, val) = place(ele.as_bytes());
949 set(&mut buf, index, val).expect("a write");
950 }
951 buf
952 };
953 assert_eq!(build(1000).len(), 1880);
954 assert_eq!(build(10_000).len(), DENSE);
955 assert_eq!(DENSE, 12304);
956 const { assert!(1880 <= SPARSE_MAX) };
957 }
958
959 #[test]
961 fn a_string_that_is_not_a_sketch_is_refused() {
962 assert!(check(b"").is_err());
963 assert!(check(b"HYLL").is_err());
964 assert!(check(b"NOPE\x01\0\0\0\0\0\0\0\0\0\0\0\x7f\xff").is_err());
965 assert!(check(b"HYLL\x02\0\0\0\0\0\0\0\0\0\0\0\x7f\xff").is_err());
966 assert!(check(b"HYLL\0\0\0\0\0\0\0\0\0\0\0\0\x7f\xff").is_err());
968
969 let mut buf = Vec::new();
970 empty(&mut buf);
971 assert_eq!(cached(&buf), Some(0));
972 cache(&mut buf, 12345);
973 assert_eq!(cached(&buf), Some(12345));
974 invalidate(&mut buf);
975 assert_eq!(cached(&buf), None);
976 }
977
978 #[test]
980 fn a_body_that_does_not_add_up_is_corrupt() {
981 let mut buf = Vec::new();
982 empty(&mut buf);
983 buf.truncate(buf.len() - 1);
984 assert!(count(&buf, Encoding::Sparse).is_err());
985 let mut short = Vec::new();
986 empty(&mut short);
987 short.pop();
988 short.pop();
989 assert!(count(&short, Encoding::Sparse).is_err());
990 }
991
992 #[test]
994 fn merging_takes_the_larger_of_every_register() {
995 let build = |from: usize, to: usize| {
996 let mut buf = Vec::new();
997 empty(&mut buf);
998 for i in from..to {
999 let ele = format!("e:{i}");
1000 let (index, val) = place(ele.as_bytes());
1001 set(&mut buf, index, val).expect("a write");
1002 }
1003 buf
1004 };
1005 let (mid, end) = (many(400usize), many(900usize));
1008 let a = build(0, end - mid);
1009 let b = build(mid, end);
1010 let mut max = [0u8; REGISTERS];
1011 assert!(merge(&mut max, &a, Encoding::Sparse));
1012 assert!(merge(&mut max, &b, Encoding::Sparse));
1013
1014 let both = build(0, end);
1015 let mut want = [0u8; REGISTERS];
1016 assert!(merge(&mut want, &both, check(&both).expect("a sketch")));
1017 assert_eq!(max, want);
1018 }
1019}