1use std::{marker::PhantomData, ops::RangeInclusive, ptr::NonNull};
7
8use diskann_utils::{Reborrow, ReborrowMut};
9use thiserror::Error;
10
11use super::{
12 length::{Dynamic, Length},
13 packing,
14 ptr::{AsMutPtr, AsPtr, MutSlicePtr, Precursor, SlicePtr},
15};
16use crate::{
17 alloc::{AllocatorCore, AllocatorError, GlobalAllocator, Poly},
18 utils,
19};
20
21pub trait Representation<const NBITS: usize> {
27 type Domain: Iterator<Item = i64>;
29
30 fn encode(value: i64) -> Result<u8, EncodingError>;
33
34 fn encode_unchecked(value: i64) -> u8;
41
42 fn decode(raw: u8) -> i64;
49
50 fn check(value: i64) -> bool;
52
53 fn domain() -> Self::Domain;
55}
56
57#[derive(Debug, Error, Clone, Copy)]
58#[error("value {} is not in the encodable range of {}", got, domain)]
59pub struct EncodingError {
60 got: i64,
61 domain: &'static &'static str,
67}
68
69impl EncodingError {
70 fn new(got: i64, domain: &'static &'static str) -> Self {
71 Self { got, domain }
72 }
73}
74
75#[derive(Debug, Clone, Copy)]
84pub struct Unsigned;
85
86impl Unsigned {
87 pub const fn domain_const<const NBITS: usize>() -> std::ops::RangeInclusive<i64> {
89 0..=2i64.pow(NBITS as u32) - 1
90 }
91
92 #[expect(clippy::panic)]
93 const fn domain_str(nbits: usize) -> &'static &'static str {
94 match nbits {
95 8 => &"[0, 255]",
96 7 => &"[0, 127]",
97 6 => &"[0, 63]",
98 5 => &"[0, 31]",
99 4 => &"[0, 15]",
100 3 => &"[0, 7]",
101 2 => &"[0, 3]",
102 1 => &"[0, 1]",
103 _ => panic!("unimplemented"),
104 }
105 }
106}
107
108macro_rules! repr_unsigned {
109 ($N:literal) => {
110 impl Representation<$N> for Unsigned {
111 type Domain = RangeInclusive<i64>;
112
113 fn encode(value: i64) -> Result<u8, EncodingError> {
114 if !<Self as Representation<$N>>::check(value) {
115 let domain = Self::domain_str($N);
118 Err(EncodingError::new(value, domain))
119 } else {
120 Ok(<Self as Representation<$N>>::encode_unchecked(value))
121 }
122 }
123
124 fn encode_unchecked(value: i64) -> u8 {
125 debug_assert!(<Self as Representation<$N>>::check(value));
126 value as u8
127 }
128
129 fn decode(raw: u8) -> i64 {
130 let raw: i64 = raw.into();
132 debug_assert!(<Self as Representation<$N>>::check(raw));
133 raw
134 }
135
136 fn check(value: i64) -> bool {
137 <Self as Representation<$N>>::domain().contains(&value)
138 }
139
140 fn domain() -> Self::Domain {
141 Self::domain_const::<$N>()
142 }
143 }
144 };
145 ($N:literal, $($Ns:literal),+) => {
146 repr_unsigned!($N);
147 $(repr_unsigned!($Ns);)+
148 };
149}
150
151repr_unsigned!(1, 2, 3, 4, 5, 6, 7, 8);
152
153#[derive(Debug, Clone, Copy)]
159pub struct Binary;
160
161impl Representation<1> for Binary {
162 type Domain = std::array::IntoIter<i64, 2>;
163
164 fn encode(value: i64) -> Result<u8, EncodingError> {
165 if !Self::check(value) {
166 const DOMAIN: &str = "{-1, 1}";
167 Err(EncodingError::new(value, &DOMAIN))
168 } else {
169 Ok(Self::encode_unchecked(value))
170 }
171 }
172
173 fn encode_unchecked(value: i64) -> u8 {
174 debug_assert!(Self::check(value));
175 value.clamp(0, 1) as u8
177 }
178
179 fn decode(raw: u8) -> i64 {
180 let raw: i64 = raw.into();
183 (raw << 1) - 1
184 }
185
186 fn check(value: i64) -> bool {
187 value == -1 || value == 1
188 }
189
190 fn domain() -> Self::Domain {
194 [-1, 1].into_iter()
195 }
196}
197
198pub unsafe trait PermutationStrategy<const NBITS: usize> {
218 fn bytes(count: usize) -> usize;
220
221 unsafe fn pack(s: &mut [u8], i: usize, value: u8);
230
231 unsafe fn unpack(s: &[u8], i: usize) -> u8;
241}
242
243#[derive(Debug, Clone, Copy)]
247pub struct Dense;
248
249impl Dense {
250 fn bytes<const NBITS: usize>(count: usize) -> usize {
251 utils::div_round_up(NBITS * count, 8)
252 }
253}
254
255unsafe impl<const NBITS: usize> PermutationStrategy<NBITS> for Dense {
257 fn bytes(count: usize) -> usize {
258 Self::bytes::<NBITS>(count)
259 }
260
261 unsafe fn pack(data: &mut [u8], i: usize, encoded: u8) {
262 let bitaddress = NBITS * i;
263
264 let bytestart = bitaddress / 8;
265 let bytestop = (bitaddress + NBITS - 1) / 8;
266 let bitstart = bitaddress - 8 * bytestart;
267 debug_assert!(bytestop < data.len());
268
269 if bytestart == bytestop {
270 let raw = unsafe { data.as_ptr().add(bytestart).read() };
279 let packed = packing::pack_u8::<NBITS>(raw, encoded, bitstart);
280
281 unsafe { data.as_mut_ptr().add(bytestart).write(packed) };
285 } else {
286 let raw = unsafe { data.as_ptr().add(bytestart).cast::<u16>().read_unaligned() };
294 let packed = packing::pack_u16::<NBITS>(raw, encoded, bitstart);
295
296 unsafe {
300 data.as_mut_ptr()
301 .add(bytestart)
302 .cast::<u16>()
303 .write_unaligned(packed)
304 };
305 }
306 }
307
308 unsafe fn unpack(data: &[u8], i: usize) -> u8 {
309 let bitaddress = NBITS * i;
310
311 let bytestart = bitaddress / 8;
312 let bytestop = (bitaddress + NBITS - 1) / 8;
313 debug_assert!(bytestop < data.len());
314 if bytestart == bytestop {
315 let raw = unsafe { data.as_ptr().add(bytestart).read() };
317 packing::unpack_u8::<NBITS>(raw, bitaddress - 8 * bytestart)
318 } else {
319 let raw = unsafe { data.as_ptr().add(bytestart).cast::<u16>().read_unaligned() };
321 packing::unpack_u16::<NBITS>(raw, bitaddress - 8 * bytestart)
322 }
323 }
324}
325
326#[derive(Debug, Clone, Copy)]
340pub struct BitTranspose;
341
342unsafe impl PermutationStrategy<4> for BitTranspose {
345 fn bytes(count: usize) -> usize {
346 32 * utils::div_round_up(count, 64)
347 }
348
349 unsafe fn pack(data: &mut [u8], i: usize, encoded: u8) {
350 let block_start = 32 * (i / 64);
352 let byte_start = block_start + (i % 64) / 8;
354 let bit = i % 8;
356
357 let mask: u8 = 0x1 << bit;
358 for p in 0..4 {
359 let mut v = data[byte_start + 8 * p];
360 v = (v & !mask) | (((encoded >> p) & 0x1) << bit);
361 data[byte_start + 8 * p] = v;
362 }
363 }
364
365 unsafe fn unpack(data: &[u8], i: usize) -> u8 {
366 let block_start = 32 * (i / 64);
368 let byte_start = block_start + (i % 64) / 8;
370 let bit = i % 8;
372
373 let mut output: u8 = 0;
374 for p in 0..4 {
375 let v = data[byte_start + 8 * p];
376 output |= ((v >> bit) & 0x1) << p
377 }
378 output
379 }
380}
381
382#[derive(Debug, Clone, Copy, PartialEq, Eq, Error)]
387#[error("decoded output has {output} elements, expected {input}")]
388pub(crate) struct DecodeLengthMismatch {
389 input: usize,
390 output: usize,
391}
392
393#[derive(Debug, Error, Clone, Copy)]
394#[error("input span has length {got} bytes but expected {expected}")]
395pub struct ConstructionError {
396 got: usize,
397 expected: usize,
398}
399
400#[derive(Debug, Error, Clone, Copy)]
401#[error("index {index} exceeds the maximum length of {len}")]
402pub struct IndexOutOfBounds {
403 index: usize,
404 len: usize,
405}
406
407impl IndexOutOfBounds {
408 fn new(index: usize, len: usize) -> Self {
409 Self { index, len }
410 }
411}
412
413#[derive(Debug, Error, Clone, Copy)]
414#[error("error setting index in bitslice")]
415#[non_exhaustive]
416pub enum SetError {
417 IndexError(#[from] IndexOutOfBounds),
418 EncodingError(#[from] EncodingError),
419}
420
421#[derive(Debug, Error, Clone, Copy)]
422#[error("error getting index in bitslice")]
423pub enum GetError {
424 IndexError(#[from] IndexOutOfBounds),
425}
426
427#[derive(Debug, Clone, Copy)]
525pub struct BitSliceBase<const NBITS: usize, Repr, Ptr, Perm = Dense, Len = Dynamic>
526where
527 Repr: Representation<NBITS>,
528 Ptr: AsPtr<Type = u8>,
529 Perm: PermutationStrategy<NBITS>,
530 Len: Length,
531{
532 ptr: Ptr,
533 len: Len,
534 repr: PhantomData<Repr>,
535 packing: PhantomData<Perm>,
536}
537
538impl<const NBITS: usize, Repr, Ptr, Perm, Len> BitSliceBase<NBITS, Repr, Ptr, Perm, Len>
539where
540 Repr: Representation<NBITS>,
541 Ptr: AsPtr<Type = u8>,
542 Perm: PermutationStrategy<NBITS>,
543 Len: Length,
544{
545 const _CHECK: () = assert!(NBITS > 0 && NBITS <= 8);
547
548 pub fn bytes_for(count: usize) -> usize {
550 Perm::bytes(count)
551 }
552
553 unsafe fn new_unchecked_internal(ptr: Ptr, len: Len) -> Self {
560 Self {
561 ptr,
562 len,
563 repr: PhantomData,
564 packing: PhantomData,
565 }
566 }
567
568 pub unsafe fn new_unchecked<Pre, Count>(precursor: Pre, count: Count) -> Self
578 where
579 Count: Into<Len>,
580 Pre: Precursor<Ptr>,
581 {
582 let count: Len = count.into();
583 debug_assert_eq!(precursor.precursor_len(), Self::bytes_for(count.value()));
584
585 unsafe { Self::new_unchecked_internal(precursor.precursor_into(), count) }
587 }
588
589 pub fn new<Pre, Count>(precursor: Pre, count: Count) -> Result<Self, ConstructionError>
599 where
600 Count: Into<Len>,
601 Pre: Precursor<Ptr>,
602 {
603 let count: Len = count.into();
605
606 if precursor.precursor_len() != Self::bytes_for(count.value()) {
608 Err(ConstructionError {
609 got: precursor.precursor_len(),
610 expected: Self::bytes_for(count.value()),
611 })
612 } else {
613 Ok(unsafe { Self::new_unchecked(precursor, count) })
618 }
619 }
620
621 pub fn len(&self) -> usize {
623 self.len.value()
624 }
625
626 pub fn is_empty(&self) -> bool {
628 self.len() == 0
629 }
630
631 pub fn bytes(&self) -> usize {
633 Self::bytes_for(self.len())
634 }
635
636 pub fn get(&self, i: usize) -> Result<i64, GetError> {
638 if i >= self.len() {
639 Err(IndexOutOfBounds::new(i, self.len()).into())
640 } else {
641 Ok(unsafe { self.get_unchecked(i) })
643 }
644 }
645
646 pub unsafe fn get_unchecked(&self, i: usize) -> i64 {
652 debug_assert!(i < self.len());
653 debug_assert_eq!(self.as_slice().len(), Perm::bytes(self.len()));
654
655 Repr::decode(unsafe { Perm::unpack(self.as_slice(), i) })
660 }
661
662 pub fn set(&mut self, i: usize, value: i64) -> Result<(), SetError>
664 where
665 Ptr: AsMutPtr<Type = u8>,
666 {
667 if i >= self.len() {
668 return Err(IndexOutOfBounds::new(i, self.len()).into());
669 }
670
671 let encoded = Repr::encode(value)?;
672
673 unsafe { self.set_unchecked(i, encoded) }
675 Ok(())
676 }
677
678 pub unsafe fn set_unchecked(&mut self, i: usize, encoded: u8)
684 where
685 Ptr: AsMutPtr<Type = u8>,
686 {
687 debug_assert!(i < self.len());
688 debug_assert_eq!(self.as_slice().len(), Perm::bytes(self.len()));
689
690 unsafe { Perm::pack(self.as_mut_slice(), i, encoded) }
695 }
696
697 pub fn domain(&self) -> Repr::Domain {
699 Repr::domain()
700 }
701
702 pub(crate) fn as_slice(&self) -> &'_ [u8] {
703 unsafe { std::slice::from_raw_parts(self.ptr.as_ptr(), self.bytes()) }
707 }
708
709 pub fn as_ptr(&self) -> *const u8 {
716 self.ptr.as_ptr()
717 }
718
719 pub(super) fn as_mut_slice(&mut self) -> &'_ mut [u8]
721 where
722 Ptr: AsMutPtr,
723 {
724 unsafe { std::slice::from_raw_parts_mut(self.ptr.as_mut_ptr(), self.bytes()) }
731 }
732
733 fn as_mut_ptr(&mut self) -> *mut u8
735 where
736 Ptr: AsMutPtr,
737 {
738 self.ptr.as_mut_ptr()
739 }
740}
741
742impl<const NBITS: usize, Repr, Perm, Len>
743 BitSliceBase<NBITS, Repr, Poly<[u8], GlobalAllocator>, Perm, Len>
744where
745 Repr: Representation<NBITS>,
746 Perm: PermutationStrategy<NBITS>,
747 Len: Length,
748{
749 pub fn new_boxed<Count>(count: Count) -> Self
768 where
769 Count: Into<Len>,
770 {
771 let count: Len = count.into();
772 let bytes = Self::bytes_for(count.value());
773 let storage: Box<[u8]> = (0..bytes).map(|_| 0).collect();
774
775 unsafe { Self::new_unchecked(Poly::from(storage), count) }
780 }
781}
782
783impl<const NBITS: usize, Repr, Perm, Len, A> BitSliceBase<NBITS, Repr, Poly<[u8], A>, Perm, Len>
784where
785 Repr: Representation<NBITS>,
786 Perm: PermutationStrategy<NBITS>,
787 Len: Length,
788 A: AllocatorCore,
789{
790 pub fn new_in<Count>(count: Count, allocator: A) -> Result<Self, AllocatorError>
814 where
815 Count: Into<Len>,
816 {
817 let count: Len = count.into();
818 let bytes = Self::bytes_for(count.value());
819 let storage = Poly::broadcast(0, bytes, allocator)?;
820
821 Ok(unsafe { Self::new_unchecked(storage, count) })
826 }
827
828 pub fn into_inner(self) -> Poly<[u8], A> {
830 self.ptr
831 }
832}
833
834pub type BitSlice<'a, const N: usize, Repr, Perm = Dense, Len = Dynamic> =
836 BitSliceBase<N, Repr, SlicePtr<'a, u8>, Perm, Len>;
837
838pub type MutBitSlice<'a, const N: usize, Repr, Perm = Dense, Len = Dynamic> =
840 BitSliceBase<N, Repr, MutSlicePtr<'a, u8>, Perm, Len>;
841
842pub type PolyBitSlice<const N: usize, Repr, A, Perm = Dense, Len = Dynamic> =
844 BitSliceBase<N, Repr, Poly<[u8], A>, Perm, Len>;
845
846pub type BoxedBitSlice<const N: usize, Repr, Perm = Dense, Len = Dynamic> =
848 PolyBitSlice<N, Repr, GlobalAllocator, Perm, Len>;
849
850impl<const NBITS: usize> BitSlice<'_, NBITS, Unsigned, Dense>
851where
852 Unsigned: Representation<NBITS>,
853{
854 #[inline]
861 pub(crate) fn decode_into<T>(
862 &self,
863 output: &mut [T],
864 mut convert: impl FnMut(u8) -> T,
865 ) -> Result<(), DecodeLengthMismatch> {
866 if output.len() != self.len() {
867 return Err(DecodeLengthMismatch {
868 input: self.len(),
869 output: output.len(),
870 });
871 }
872 let packed = self.as_slice();
873 let divisor = 1usize << NBITS.trailing_zeros();
874 let codes_per_block = 8 / divisor;
875 let bytes_per_block = NBITS / divisor;
876 let blocks = output.len() / codes_per_block;
877 let (output, tail) = output.split_at_mut(blocks * codes_per_block);
878 let (packed, rest) = packed.split_at(blocks * bytes_per_block);
879 let mask = (1u64 << NBITS) - 1;
880 for (block, bytes) in output
882 .chunks_exact_mut(codes_per_block)
883 .zip(packed.chunks_exact(bytes_per_block))
884 {
885 let mut word = [0u8; 8];
886 word[..bytes_per_block].copy_from_slice(bytes);
887 let word = u64::from_le_bytes(word);
888 for (i, out) in block.iter_mut().enumerate() {
889 *out = convert(((word >> (i * NBITS)) & mask) as u8);
890 }
891 }
892 let word = rest
893 .iter()
894 .enumerate()
895 .fold(0u64, |word, (i, &byte)| word | (u64::from(byte) << (8 * i)));
896 for (i, out) in tail.iter_mut().enumerate() {
897 *out = convert(((word >> (i * NBITS)) & mask) as u8);
898 }
899 Ok(())
900 }
901}
902
903impl<'a, Ptr> From<&'a BitSliceBase<8, Unsigned, Ptr>> for &'a [u8]
908where
909 Ptr: AsPtr<Type = u8>,
910{
911 fn from(slice: &'a BitSliceBase<8, Unsigned, Ptr>) -> Self {
912 unsafe { std::slice::from_raw_parts(slice.as_ptr(), slice.len()) }
918 }
919}
920
921impl<'this, const NBITS: usize, Repr, Ptr, Perm, Len> Reborrow<'this>
922 for BitSliceBase<NBITS, Repr, Ptr, Perm, Len>
923where
924 Repr: Representation<NBITS>,
925 Ptr: AsPtr<Type = u8>,
926 Perm: PermutationStrategy<NBITS>,
927 Len: Length,
928{
929 type Target = BitSlice<'this, NBITS, Repr, Perm, Len>;
930
931 fn reborrow(&'this self) -> Self::Target {
932 let ptr: *const u8 = self.as_ptr();
933 debug_assert!(!ptr.is_null());
934
935 let nonnull = unsafe { NonNull::new_unchecked(ptr.cast_mut()) };
939
940 let ptr = unsafe { SlicePtr::new_unchecked(nonnull) };
947
948 Self::Target {
949 ptr,
950 len: self.len,
951 repr: PhantomData,
952 packing: PhantomData,
953 }
954 }
955}
956
957impl<'this, const NBITS: usize, Repr, Ptr, Perm, Len> ReborrowMut<'this>
958 for BitSliceBase<NBITS, Repr, Ptr, Perm, Len>
959where
960 Repr: Representation<NBITS>,
961 Ptr: AsMutPtr<Type = u8>,
962 Perm: PermutationStrategy<NBITS>,
963 Len: Length,
964{
965 type Target = MutBitSlice<'this, NBITS, Repr, Perm, Len>;
966
967 fn reborrow_mut(&'this mut self) -> Self::Target {
968 let ptr: *mut u8 = self.as_mut_ptr();
969 debug_assert!(!ptr.is_null());
970
971 let nonnull = unsafe { NonNull::new_unchecked(ptr) };
973
974 let ptr = unsafe { MutSlicePtr::new_unchecked(nonnull) };
984
985 Self::Target {
986 ptr,
987 len: self.len,
988 repr: PhantomData,
989 packing: PhantomData,
990 }
991 }
992}
993
994#[cfg(test)]
999mod tests {
1000 use rand::{
1001 Rng, SeedableRng,
1002 distr::{Distribution, Uniform},
1003 rngs::StdRng,
1004 seq::{IndexedRandom, SliceRandom},
1005 };
1006
1007 use super::*;
1008 use crate::{bits::Static, test_util::AlwaysFails};
1009
1010 fn check_bulk_decoding<const NBITS: usize>()
1011 where
1012 Unsigned: Representation<NBITS>,
1013 {
1014 for len in [0, 1, 2, 3, 7, 8, 9, 15, 16, 17, 255, 256, 257, 513] {
1015 for offset in [0, 1, 7] {
1016 let byte_count = BitSlice::<NBITS, Unsigned>::bytes_for(len);
1017 let mut bytes = vec![0xff; offset + byte_count];
1018 let bytes = &mut bytes[offset..];
1019 let mut codes = MutBitSlice::<NBITS, Unsigned>::new(bytes, len).unwrap();
1020 for i in 0..len {
1021 codes
1022 .set(i, ((i * 37 + i / 2) & ((1 << NBITS) - 1)) as i64)
1023 .unwrap();
1024 }
1025 let expected: Vec<_> = (0..len).map(|i| codes.get(i).unwrap()).collect();
1026 let mut guarded = vec![i64::MIN; len + 2];
1027 let mut calls = 0;
1028 codes
1029 .reborrow()
1030 .decode_into(&mut guarded[1..=len], |value| {
1031 assert_eq!(i64::from(value), expected[calls]);
1032 calls += 1;
1033 i64::from(value)
1034 })
1035 .unwrap();
1036 assert_eq!(calls, len);
1037 assert_eq!(&guarded[1..=len], expected);
1038 assert_eq!(guarded[0], i64::MIN);
1039 assert_eq!(guarded[len + 1], i64::MIN);
1040 }
1041 }
1042 }
1043
1044 #[test]
1045 fn test_decode_into_preserves_order_tails_and_bounds() {
1046 check_bulk_decoding::<1>();
1047 check_bulk_decoding::<2>();
1048 check_bulk_decoding::<3>();
1049 check_bulk_decoding::<4>();
1050 check_bulk_decoding::<5>();
1051 check_bulk_decoding::<6>();
1052 check_bulk_decoding::<7>();
1053 check_bulk_decoding::<8>();
1054 }
1055
1056 #[test]
1057 fn test_decode_into_applies_conversion() {
1058 let codes = BitSlice::<8, Unsigned>::new(&[0, 128, 255][..], 3).unwrap();
1059 let mut output = [0i16; 3];
1060 codes
1061 .decode_into(&mut output, |value| i16::from(value) * 3)
1062 .unwrap();
1063 assert_eq!(output, [0, 384, 765]);
1064 let codes = BoxedBitSlice::<4, Unsigned>::new_boxed(2);
1065 let mut output = [1u8; 2];
1066 codes
1067 .reborrow()
1068 .decode_into(&mut output, |value| value)
1069 .unwrap();
1070 assert_eq!(output, [0, 0]);
1071 }
1072
1073 #[test]
1074 fn test_decode_into_length_mismatch_does_not_write_or_convert() {
1075 let codes = BitSlice::<4, Unsigned>::new(&[0x21u8][..], 2).unwrap();
1076 for len in [0, 1, 3] {
1077 let mut output = vec![99; len];
1078 let mut calls = 0;
1079 let error = codes
1080 .decode_into(&mut output, |value| {
1081 calls += 1;
1082 value
1083 })
1084 .unwrap_err();
1085 assert_eq!(
1086 error,
1087 DecodeLengthMismatch {
1088 input: 2,
1089 output: len
1090 }
1091 );
1092 assert_eq!(calls, 0);
1093 assert_eq!(output, vec![99; len]);
1094 }
1095 }
1096
1097 const BOUNDS: &str = "special bounds";
1102
1103 #[test]
1104 fn test_encoding_error() {
1105 assert_eq!(std::mem::size_of::<EncodingError>(), 16);
1106 assert_eq!(
1107 std::mem::size_of::<Option<EncodingError>>(),
1108 16,
1109 "expected EncodingError to have the niche optimization"
1110 );
1111 let err = EncodingError::new(7, &BOUNDS);
1112 assert_eq!(
1113 err.to_string(),
1114 "value 7 is not in the encodable range of special bounds"
1115 );
1116 }
1117
1118 fn assert_send_and_sync<T: Send + Sync>(_x: &T) {}
1120
1121 #[test]
1126 fn test_binary_repr() {
1127 assert_eq!(Binary::encode(-1).unwrap(), 0);
1128 assert_eq!(Binary::encode(1).unwrap(), 1);
1129 assert_eq!(Binary::decode(0), -1);
1130 assert_eq!(Binary::decode(1), 1);
1131
1132 assert!(Binary::check(-1));
1133 assert!(Binary::check(1));
1134 assert!(!Binary::check(0));
1135 assert!(!Binary::check(-2));
1136 assert!(!Binary::check(2));
1137
1138 let domain: Vec<_> = Binary::domain().collect();
1139 assert_eq!(domain, &[-1, 1]);
1140 }
1141
1142 #[test]
1147 fn test_sizes() {
1148 assert_eq!(std::mem::size_of::<BitSlice<'static, 8, Unsigned>>(), 16);
1149 assert_eq!(std::mem::size_of::<MutBitSlice<'static, 8, Unsigned>>(), 16);
1150
1151 assert_eq!(
1153 std::mem::size_of::<Option<BitSlice<'static, 8, Unsigned>>>(),
1154 16
1155 );
1156 assert_eq!(
1157 std::mem::size_of::<Option<MutBitSlice<'static, 8, Unsigned>>>(),
1158 16
1159 );
1160
1161 assert_eq!(
1162 std::mem::size_of::<BitSlice<'static, 8, Unsigned, Dense, Static<128>>>(),
1163 8
1164 );
1165 }
1166
1167 cfg_if::cfg_if! {
1172 if #[cfg(miri)] {
1173 const MAX_DIM: usize = 160;
1174 const FUZZ_ITERATIONS: usize = 1;
1175 } else if #[cfg(debug_assertions)] {
1176 const MAX_DIM: usize = 128;
1177 const FUZZ_ITERATIONS: usize = 10;
1178 } else {
1179 const MAX_DIM: usize = 256;
1180 const FUZZ_ITERATIONS: usize = 100;
1181 }
1182 }
1183
1184 fn test_send_and_sync<const NBITS: usize, Repr, Perm>()
1185 where
1186 Repr: Representation<NBITS> + Send + Sync,
1187 Perm: PermutationStrategy<NBITS> + Send + Sync,
1188 {
1189 let mut x = BoxedBitSlice::<NBITS, Repr, Perm>::new_boxed(1);
1190 assert_send_and_sync(&x);
1191 assert_send_and_sync(&x.reborrow());
1192 assert_send_and_sync(&x.reborrow_mut());
1193 }
1194
1195 fn test_empty<const NBITS: usize, Repr, Perm>()
1196 where
1197 Repr: Representation<NBITS>,
1198 Perm: PermutationStrategy<NBITS>,
1199 {
1200 let base: &mut [u8] = &mut [];
1201 let mut slice = MutBitSlice::<NBITS, Repr, Perm>::new(base, 0).unwrap();
1202 assert_eq!(slice.len(), 0);
1203 assert!(slice.is_empty());
1204
1205 {
1206 let reborrow = slice.reborrow();
1207 assert_eq!(reborrow.len(), 0);
1208 assert!(reborrow.is_empty());
1209 }
1210
1211 {
1212 let reborrow = slice.reborrow_mut();
1213 assert_eq!(reborrow.len(), 0);
1214 assert!(reborrow.is_empty());
1215 }
1216 }
1217
1218 fn test_construction_errors<const NBITS: usize, Repr, Perm>()
1220 where
1221 Repr: Representation<NBITS>,
1222 Perm: PermutationStrategy<NBITS>,
1223 {
1224 let len: usize = 10;
1225 let bytes = Perm::bytes(len);
1226
1227 let box_big = Poly::broadcast(0u8, bytes + 1, GlobalAllocator).unwrap();
1229 let box_small = Poly::broadcast(0u8, bytes - 1, GlobalAllocator).unwrap();
1230 let box_right = Poly::broadcast(0u8, bytes, GlobalAllocator).unwrap();
1231
1232 let result = BoxedBitSlice::<NBITS, Repr, Perm>::new(box_big, len);
1233 match result {
1234 Err(ConstructionError { got, expected }) => {
1235 assert_eq!(got, bytes + 1);
1236 assert_eq!(expected, bytes);
1237 }
1238 _ => panic!("shouldn't have reached here!"),
1239 };
1240
1241 let result = BoxedBitSlice::<NBITS, Repr, Perm>::new(box_small, len);
1242 match result {
1243 Err(ConstructionError { got, expected }) => {
1244 assert_eq!(got, bytes - 1);
1245 assert_eq!(expected, bytes);
1246 }
1247 _ => panic!("shouldn't have reached here!"),
1248 };
1249
1250 let mut base = BoxedBitSlice::<NBITS, Repr, Perm>::new(box_right, len).unwrap();
1251 let ptr = base.as_ptr();
1252 assert_eq!(base.len(), len);
1253
1254 {
1256 let borrowed = base.reborrow_mut();
1258 assert_eq!(borrowed.as_ptr(), ptr);
1259 assert_eq!(borrowed.len(), len);
1260
1261 let borrowed = MutBitSlice::<NBITS, Repr, Perm>::new(base.as_mut_slice(), len).unwrap();
1263 assert_eq!(borrowed.as_ptr(), ptr);
1264 assert_eq!(borrowed.len(), len);
1265 }
1266
1267 {
1269 let mut oversized = vec![0; bytes + 1];
1271 let result = MutBitSlice::<NBITS, Repr, Perm>::new(oversized.as_mut_slice(), len);
1272 match result {
1273 Err(ConstructionError { got, expected }) => {
1274 assert_eq!(got, bytes + 1);
1275 assert_eq!(expected, bytes);
1276 }
1277 _ => panic!("shouldn't have reached here!"),
1278 };
1279
1280 let mut undersized = vec![0; bytes - 1];
1281 let result = MutBitSlice::<NBITS, Repr, Perm>::new(undersized.as_mut_slice(), len);
1282 match result {
1283 Err(ConstructionError { got, expected }) => {
1284 assert_eq!(got, bytes - 1);
1285 assert_eq!(expected, bytes);
1286 }
1287 _ => panic!("shouldn't have reached here!"),
1288 };
1289 }
1290
1291 {
1293 let borrowed = base.reborrow();
1295 assert_eq!(borrowed.as_ptr(), ptr);
1296 assert_eq!(borrowed.len(), len);
1297
1298 let borrowed = BitSlice::<NBITS, Repr, Perm>::new(base.as_slice(), len).unwrap();
1300 assert_eq!(borrowed.as_ptr(), ptr);
1301 assert_eq!(borrowed.len(), len);
1302
1303 let borrowed = BitSlice::<NBITS, Repr, Perm>::new(base.as_mut_slice(), len).unwrap();
1305 assert_eq!(borrowed.as_ptr(), ptr);
1306 assert_eq!(borrowed.len(), len);
1307 }
1308
1309 {
1311 let mut oversized = vec![0; bytes + 1];
1313 let result = BitSlice::<NBITS, Repr, Perm>::new(oversized.as_mut_slice(), len);
1314 match result {
1315 Err(ConstructionError { got, expected }) => {
1316 assert_eq!(got, bytes + 1);
1317 assert_eq!(expected, bytes);
1318 }
1319 _ => panic!("shouldn't have reached here!"),
1320 };
1321
1322 let result = BitSlice::<NBITS, Repr, Perm>::new(oversized.as_slice(), len);
1323 match result {
1324 Err(ConstructionError { got, expected }) => {
1325 assert_eq!(got, bytes + 1);
1326 assert_eq!(expected, bytes);
1327 }
1328 _ => panic!("shouldn't have reached here!"),
1329 };
1330
1331 let mut undersized = vec![0; bytes - 1];
1333 let result = BitSlice::<NBITS, Repr, Perm>::new(undersized.as_mut_slice(), len);
1334 match result {
1335 Err(ConstructionError { got, expected }) => {
1336 assert_eq!(got, bytes - 1);
1337 assert_eq!(expected, bytes);
1338 }
1339 _ => panic!("shouldn't have reached here!"),
1340 };
1341
1342 let result = BitSlice::<NBITS, Repr, Perm>::new(undersized.as_slice(), len);
1343 match result {
1344 Err(ConstructionError { got, expected }) => {
1345 assert_eq!(got, bytes - 1);
1346 assert_eq!(expected, bytes);
1347 }
1348 _ => panic!("shouldn't have reached here!"),
1349 };
1350 }
1351 }
1352
1353 fn run_overwrite_test<const NBITS: usize, Perm, Len, R>(
1356 base: &mut BoxedBitSlice<NBITS, Unsigned, Perm, Len>,
1357 num_iterations: usize,
1358 rng: &mut R,
1359 ) where
1360 Unsigned: Representation<NBITS, Domain = RangeInclusive<i64>>,
1361 Len: Length,
1362 Perm: PermutationStrategy<NBITS>,
1363 R: Rng,
1364 {
1365 let mut expected: Vec<i64> = vec![0; base.len()];
1366 let mut indices: Vec<usize> = (0..base.len()).collect();
1367 for i in 0..base.len() {
1368 base.set(i, 0).unwrap();
1369 }
1370
1371 for i in 0..base.len() {
1372 assert_eq!(base.get(i).unwrap(), 0, "failed to initialize bit vector");
1373 }
1374
1375 let domain = base.domain();
1376 assert_eq!(domain, 0..=2i64.pow(NBITS as u32) - 1);
1377 let distribution = Uniform::new_inclusive(*domain.start(), *domain.end()).unwrap();
1378
1379 for iter in 0..num_iterations {
1380 indices.shuffle(rng);
1382
1383 for &i in indices.iter() {
1385 let value = distribution.sample(rng);
1386 expected[i] = value;
1387 base.set(i, value).unwrap();
1388 }
1389
1390 for (i, &expect) in expected.iter().enumerate() {
1392 let value = base.get(i).unwrap();
1393 assert_eq!(
1394 value, expect,
1395 "retrieval failed on iteration {iter} at index {i}"
1396 );
1397 }
1398
1399 let borrowed = base.reborrow();
1401 for (i, &expect) in expected.iter().enumerate() {
1402 let value = borrowed.get(i).unwrap();
1403 assert_eq!(
1404 value, expect,
1405 "reborrow retrieval failed on iteration {iter} at index {i}"
1406 );
1407 }
1408 }
1409 }
1410
1411 fn run_overwrite_binary_test<Perm, Len, R>(
1412 base: &mut BoxedBitSlice<1, Binary, Perm, Len>,
1413 num_iterations: usize,
1414 rng: &mut R,
1415 ) where
1416 Len: Length,
1417 Perm: PermutationStrategy<1>,
1418 R: Rng,
1419 {
1420 let mut expected: Vec<i64> = vec![0; base.len()];
1421 let mut indices: Vec<usize> = (0..base.len()).collect();
1422 for i in 0..base.len() {
1423 base.set(i, -1).unwrap();
1424 }
1425
1426 for i in 0..base.len() {
1427 assert_eq!(base.get(i).unwrap(), -1, "failed to initialize bit vector");
1428 }
1429
1430 let distribution: [i64; 2] = [-1, 1];
1431
1432 for iter in 0..num_iterations {
1433 indices.shuffle(rng);
1435
1436 for &i in indices.iter() {
1438 let value = distribution.choose(rng).unwrap();
1439 expected[i] = *value;
1440 base.set(i, *value).unwrap();
1441 }
1442
1443 for (i, &expect) in expected.iter().enumerate() {
1445 let value = base.get(i).unwrap();
1446 assert_eq!(
1447 value, expect,
1448 "retrieval failed on iteration {iter} at index {i}"
1449 );
1450 }
1451
1452 let borrowed = base.reborrow();
1454 for (i, &expect) in expected.iter().enumerate() {
1455 let value = borrowed.get(i).unwrap();
1456 assert_eq!(
1457 value, expect,
1458 "reborrow retrieval failed on iteration {iter} at index {i}"
1459 );
1460 }
1461 }
1462 }
1463
1464 fn test_unsigned_dense<const NBITS: usize, Len, R>(
1469 len: Len,
1470 minimum: i64,
1471 maximum: i64,
1472 rng: &mut R,
1473 ) where
1474 Unsigned: Representation<NBITS, Domain = RangeInclusive<i64>>,
1475 Dense: PermutationStrategy<NBITS>,
1476 Len: Length,
1477 R: Rng,
1478 {
1479 test_send_and_sync::<NBITS, Unsigned, Dense>();
1480 test_empty::<NBITS, Unsigned, Dense>();
1481 test_construction_errors::<NBITS, Unsigned, Dense>();
1482 assert_eq!(Unsigned::domain_const::<NBITS>(), Unsigned::domain(),);
1483
1484 match PolyBitSlice::<NBITS, Unsigned, _, Dense, Len>::new_in(len, AlwaysFails) {
1485 Ok(_) => {
1486 if len.value() != 0 {
1487 panic!("zero sized allocations don't require an allocator");
1488 }
1489 }
1490 Err(AllocatorError) => {
1491 if len.value() == 0 {
1492 panic!("allocation should have failed");
1493 }
1494 }
1495 }
1496
1497 let mut base =
1498 PolyBitSlice::<NBITS, Unsigned, _, Dense, Len>::new_in(len, GlobalAllocator).unwrap();
1499 assert_eq!(
1500 base.len(),
1501 len.value(),
1502 "BoxedBitSlice returned the incorrect length"
1503 );
1504
1505 let expected_bytes = BitSlice::<'static, NBITS, Unsigned>::bytes_for(len.value());
1506 assert_eq!(
1507 base.bytes(),
1508 expected_bytes,
1509 "BoxedBitSlice has the incorrect number of bytes"
1510 );
1511
1512 assert_eq!(base.domain(), minimum..=maximum);
1514
1515 if len.value() == 0 {
1516 return;
1517 }
1518
1519 let ptr = base.as_ptr();
1520
1521 {
1524 let mut borrowed = base.reborrow_mut();
1525
1526 assert_eq!(
1528 borrowed.as_ptr(),
1529 ptr,
1530 "pointer was not preserved during borrowing!"
1531 );
1532 assert_eq!(
1533 borrowed.len(),
1534 len.value(),
1535 "borrowing did not preserve length!"
1536 );
1537
1538 borrowed.set(0, 0).unwrap();
1539 assert_eq!(borrowed.get(0).unwrap(), 0);
1540
1541 borrowed.set(0, 1).unwrap();
1542 assert_eq!(borrowed.get(0).unwrap(), 1);
1543
1544 borrowed.set(0, 0).unwrap();
1545 assert_eq!(borrowed.get(0).unwrap(), 0);
1546
1547 let result = borrowed.set(0, minimum - 1);
1549 assert!(matches!(result, Err(SetError::EncodingError { .. })));
1550
1551 let result = borrowed.set(0, maximum + 1);
1552 assert!(matches!(result, Err(SetError::EncodingError { .. })));
1553
1554 let result = borrowed.set(borrowed.len(), 0);
1556 assert!(matches!(result, Err(SetError::IndexError { .. })));
1557
1558 let result = borrowed.get(borrowed.len());
1560 assert!(matches!(result, Err(GetError::IndexError { .. })));
1561 }
1562
1563 {
1564 let borrowed =
1566 MutBitSlice::<NBITS, Unsigned, Dense, Len>::new(base.as_mut_slice(), len).unwrap();
1567
1568 assert_eq!(
1569 borrowed.as_ptr(),
1570 ptr,
1571 "pointer was not preserved during borrowing!"
1572 );
1573 assert_eq!(
1574 borrowed.len(),
1575 len.value(),
1576 "borrowing did not preserve length!"
1577 );
1578 }
1579
1580 {
1581 let borrowed = base.reborrow();
1582
1583 assert_eq!(
1585 borrowed.as_ptr(),
1586 ptr,
1587 "pointer was not preserved during borrowing!"
1588 );
1589
1590 assert_eq!(
1591 borrowed.len(),
1592 len.value(),
1593 "borrowing did not preserve length!"
1594 );
1595
1596 let result = borrowed.get(borrowed.len());
1598 assert!(matches!(result, Err(GetError::IndexError { .. })));
1599 }
1600
1601 {
1602 let borrowed =
1604 BitSlice::<NBITS, Unsigned, Dense, Len>::new(base.as_slice(), len).unwrap();
1605
1606 assert_eq!(
1607 borrowed.as_ptr(),
1608 ptr,
1609 "pointer was not preserved during borrowing!"
1610 );
1611 assert_eq!(
1612 borrowed.len(),
1613 len.value(),
1614 "borrowing did not preserve length!"
1615 );
1616 }
1617
1618 {
1619 let borrowed =
1621 BitSlice::<NBITS, Unsigned, Dense, Len>::new(base.as_mut_slice(), len).unwrap();
1622
1623 assert_eq!(
1624 borrowed.as_ptr(),
1625 ptr,
1626 "pointer was not preserved during borrowing!"
1627 );
1628 assert_eq!(
1629 borrowed.len(),
1630 len.value(),
1631 "borrowing did not preserve length!"
1632 );
1633 }
1634
1635 run_overwrite_test(&mut base, FUZZ_ITERATIONS, rng);
1637 }
1638
1639 macro_rules! generate_unsigned_test {
1640 ($name:ident, $NBITS:literal, $MIN:literal, $MAX:literal, $SEED:literal) => {
1641 #[test]
1642 fn $name() {
1643 let mut rng = StdRng::seed_from_u64($SEED);
1644 for dim in 0..MAX_DIM {
1645 test_unsigned_dense::<$NBITS, Dynamic, _>(dim.into(), $MIN, $MAX, &mut rng);
1646 }
1647 }
1648 };
1649 }
1650
1651 generate_unsigned_test!(test_unsigned_8bit, 8, 0, 0xff, 0xc652f2a1018f442b);
1652 generate_unsigned_test!(test_unsigned_7bit, 7, 0, 0x7f, 0xb732e59fec6d6c9c);
1653 generate_unsigned_test!(test_unsigned_6bit, 6, 0, 0x3f, 0x35d9380d0a318f21);
1654 generate_unsigned_test!(test_unsigned_5bit, 5, 0, 0x1f, 0xfb09895183334304);
1655 generate_unsigned_test!(test_unsigned_4bit, 4, 0, 0x0f, 0x38dfcf9e82c33f48);
1656 generate_unsigned_test!(test_unsigned_3bit, 3, 0, 0x07, 0xf9a94c8c749ee26c);
1657 generate_unsigned_test!(test_unsigned_2bit, 2, 0, 0x03, 0xbba03db62cecf4cf);
1658 generate_unsigned_test!(test_unsigned_1bit, 1, 0, 0x01, 0x54ea2a07d7c67f37);
1659
1660 #[test]
1661 fn test_binary_dense() {
1662 let mut rng = StdRng::seed_from_u64(0xb3c95e8e19d3842e);
1663 for len in 0..MAX_DIM {
1664 test_send_and_sync::<1, Binary, Dense>();
1665 test_empty::<1, Binary, Dense>();
1666 test_construction_errors::<1, Binary, Dense>();
1667
1668 let mut base = BoxedBitSlice::<1, Binary>::new_boxed(len);
1670 assert_eq!(
1671 base.len(),
1672 len,
1673 "BoxedBitSlice returned the incorrect length"
1674 );
1675
1676 assert_eq!(base.bytes(), len.div_ceil(8));
1677
1678 let bytes = BitSlice::<'static, 1, Binary>::bytes_for(len);
1679 assert_eq!(
1680 bytes,
1681 len.div_ceil(8),
1682 "BoxedBitSlice has the incorrect number of bytes"
1683 );
1684
1685 if len == 0 {
1686 continue;
1687 }
1688
1689 let result = base.set(0, 0);
1691 assert!(matches!(result, Err(SetError::EncodingError { .. })));
1692
1693 let result = base.set(base.len(), -1);
1695 assert!(matches!(result, Err(SetError::IndexError { .. })));
1696
1697 let result = base.get(base.len());
1699 assert!(matches!(result, Err(GetError::IndexError { .. })));
1700
1701 run_overwrite_binary_test(&mut base, FUZZ_ITERATIONS, &mut rng);
1703 }
1704 }
1705
1706 #[test]
1707 fn test_4bit_bit_transpose() {
1708 let mut rng = StdRng::seed_from_u64(0xb3c95e8e19d3842e);
1709 for len in 0..MAX_DIM {
1710 test_send_and_sync::<4, Unsigned, BitTranspose>();
1711 test_empty::<4, Unsigned, BitTranspose>();
1712 test_construction_errors::<4, Unsigned, BitTranspose>();
1713
1714 let mut base = BoxedBitSlice::<4, Unsigned, BitTranspose>::new_boxed(len);
1716 assert_eq!(
1717 base.len(),
1718 len,
1719 "BoxedBitSlice returned the incorrect length"
1720 );
1721
1722 assert_eq!(base.bytes(), 32 * len.div_ceil(64));
1723
1724 let bytes = BitSlice::<'static, 4, Unsigned, BitTranspose>::bytes_for(len);
1725 assert_eq!(
1726 bytes,
1727 32 * len.div_ceil(64),
1728 "BoxedBitSlice has the incorrect number of bytes"
1729 );
1730
1731 if len == 0 {
1732 continue;
1733 }
1734
1735 let result = base.set(0, -1);
1737 assert!(matches!(result, Err(SetError::EncodingError { .. })));
1738
1739 let result = base.set(base.len(), -1);
1741 assert!(matches!(result, Err(SetError::IndexError { .. })));
1742
1743 let result = base.get(base.len());
1745 assert!(matches!(result, Err(GetError::IndexError { .. })));
1746
1747 run_overwrite_test(&mut base, FUZZ_ITERATIONS, &mut rng);
1749 }
1750 }
1751}