use std::{
fmt::Binary,
ops::{BitAndAssign, Not, Shl, ShlAssign, ShrAssign},
};
use num_traits::PrimInt;
use super::NativeType;
pub trait BitChunk:
super::private::Sealed
+ PrimInt
+ NativeType
+ Binary
+ ShlAssign
+ Not<Output = Self>
+ ShrAssign<usize>
+ ShlAssign<usize>
+ Shl<usize, Output = Self>
+ BitAndAssign
{
fn to_ne_bytes(self) -> Self::Bytes;
fn from_ne_bytes(v: Self::Bytes) -> Self;
}
macro_rules! bit_chunk {
($ty:ty) => {
impl BitChunk for $ty {
#[inline(always)]
fn to_ne_bytes(self) -> Self::Bytes {
self.to_ne_bytes()
}
#[inline(always)]
fn from_ne_bytes(v: Self::Bytes) -> Self {
Self::from_ne_bytes(v)
}
}
};
}
bit_chunk!(u8);
bit_chunk!(u16);
bit_chunk!(u32);
bit_chunk!(u64);
pub struct BitChunkIter<T: BitChunk> {
value: T,
mask: T,
remaining: usize,
}
impl<T: BitChunk> BitChunkIter<T> {
#[inline]
pub fn new(value: T, len: usize) -> Self {
assert!(len <= std::mem::size_of::<T>() * 8);
Self {
value,
remaining: len,
mask: T::one(),
}
}
}
impl<T: BitChunk> Iterator for BitChunkIter<T> {
type Item = bool;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.remaining == 0 {
return None;
};
let result = Some(self.value & self.mask != T::zero());
self.remaining -= 1;
self.mask <<= 1;
result
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(self.remaining, Some(self.remaining))
}
}
unsafe impl<T: BitChunk> crate::trusted_len::TrustedLen for BitChunkIter<T> {}
pub struct BitChunkOnes<T: BitChunk> {
value: T,
remaining: usize,
}
impl<T: BitChunk> BitChunkOnes<T> {
#[inline]
pub fn new(value: T) -> Self {
Self {
value,
remaining: value.count_ones() as usize,
}
}
#[inline]
#[cfg(feature = "compute_filter")]
pub(crate) fn from_known_count(value: T, remaining: usize) -> Self {
Self { value, remaining }
}
}
impl<T: BitChunk> Iterator for BitChunkOnes<T> {
type Item = usize;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.remaining == 0 {
return None;
}
let v = self.value.trailing_zeros() as usize;
self.value &= self.value - T::one();
self.remaining -= 1;
Some(v)
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(self.remaining, Some(self.remaining))
}
}
unsafe impl<T: BitChunk> crate::trusted_len::TrustedLen for BitChunkOnes<T> {}