1230 lines
42 KiB
Rust
1230 lines
42 KiB
Rust
use codec::{Decode, Encode};
|
|
use num_traits::PrimInt;
|
|
use scale_info::TypeInfo;
|
|
|
|
use sp_runtime::traits::UniqueSaturatedInto;
|
|
use sp_arithmetic::traits::AtLeast8BitUnsigned;
|
|
use sp_std::{cmp::{min, max}, marker::PhantomData, vec, vec::Vec};
|
|
|
|
use ghost_traits::bounded_bitmap as traits;
|
|
|
|
use frame_support::{pallet_prelude::MaxEncodedLen, traits::Get, BoundedVec};
|
|
|
|
use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not, Shl, Shr};
|
|
|
|
const fn inner_bits<Inner>() -> usize {
|
|
core::mem::size_of::<Inner>() * 8
|
|
}
|
|
|
|
const fn inner_mask<Inner>() -> usize {
|
|
let bits_per_element = inner_bits::<Inner>();
|
|
bits_per_element - 1
|
|
}
|
|
|
|
const fn inner_shift<Inner>() -> u32 {
|
|
let bits_per_element = inner_bits::<Inner>();
|
|
bits_per_element.trailing_zeros()
|
|
}
|
|
|
|
pub fn validate_bitmap_sizes<B: traits::BoundedBitmapMetadata>(authorities: u32) {
|
|
assert!(
|
|
B::total_bits_capacity() >= authorities,
|
|
"CRITICAL CONFIG ERROR: max authorities does not fit into max chunks!",
|
|
);
|
|
}
|
|
|
|
#[derive(Encode, Decode, TypeInfo, MaxEncodedLen)]
|
|
#[scale_info(skip_type_params(MaxChunks))]
|
|
pub struct BoundedBitmap<Inner, MaxChunks>
|
|
where
|
|
MaxChunks: Get<u32>,
|
|
{
|
|
data: BoundedVec<Inner, MaxChunks>,
|
|
active_bits_count: u32,
|
|
}
|
|
|
|
impl<Inner: core::fmt::Debug, MaxChunks> core::fmt::Debug for BoundedBitmap<Inner, MaxChunks>
|
|
where
|
|
MaxChunks: frame_support::traits::Get<u32>,
|
|
{
|
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
|
let slice: &[Inner] = &self.data;
|
|
f.debug_struct("BoundedBitmap")
|
|
.field("data", &slice)
|
|
.field("active_bits_count", &self.active_bits_count)
|
|
.finish()
|
|
}
|
|
}
|
|
|
|
impl<Inner, MaxChunks> BoundedBitmap<Inner, MaxChunks>
|
|
where
|
|
MaxChunks: Get<u32>,
|
|
Inner: AtLeast8BitUnsigned + PrimInt + Copy + core::fmt::Debug,
|
|
Inner: BitAnd<Output = Inner>
|
|
+ BitOr<Output = Inner>
|
|
+ BitXor<Output = Inner>
|
|
+ Not<Output = Inner>,
|
|
Inner: BitAndAssign + BitOrAssign + BitXorAssign,
|
|
Inner: Shl<usize, Output = Inner> + Shr<usize, Output = Inner>,
|
|
{
|
|
pub fn inner_as_ref(&self) -> &[u8] {
|
|
let slice: &[Inner] = self.data.as_ref();
|
|
let byte_len = slice.len() * core::mem::size_of::<Inner>();
|
|
|
|
unsafe {
|
|
core::slice::from_raw_parts(slice.as_ptr() as *const u8, byte_len)
|
|
}
|
|
}
|
|
|
|
fn combine<F>(&self, rhs: &Self, op: F) -> Self
|
|
where
|
|
Inner: Copy,
|
|
F: Fn(Inner, Inner) -> Inner,
|
|
{
|
|
let active_bits_count = max(self.active_bits_count, rhs.active_bits_count);
|
|
let bounded_len = min(MaxChunks::get() as usize, max(self.data.len(), rhs.data.len()));
|
|
|
|
let mut raw_vec = vec![Inner::zero(); bounded_len];
|
|
|
|
for index in 0..bounded_len {
|
|
let a = self.data.get(index).copied().unwrap_or_else(Inner::zero);
|
|
let b = rhs.data.get(index).copied().unwrap_or_else(Inner::zero);
|
|
raw_vec[index] = op(a, b);
|
|
}
|
|
|
|
let active_bits_count_usize: usize = active_bits_count.unique_saturated_into();
|
|
|
|
let target_chunk = active_bits_count_usize >> inner_shift::<Inner>();
|
|
let reminder = active_bits_count_usize & inner_mask::<Inner>();
|
|
|
|
if reminder > 0 {
|
|
if target_chunk < raw_vec.len() {
|
|
let mask_u64 = (Inner::one() << reminder) - Inner::one();
|
|
let masked: Inner = mask_u64.unique_saturated_into();
|
|
raw_vec[target_chunk] &= masked;
|
|
}
|
|
|
|
let after_target_chunk = target_chunk.saturating_add(1);
|
|
if after_target_chunk < raw_vec.len() {
|
|
raw_vec[after_target_chunk..].fill(Inner::zero());
|
|
}
|
|
}
|
|
|
|
Self {
|
|
active_bits_count,
|
|
data: BoundedVec::<Inner, MaxChunks>::try_from(raw_vec)
|
|
.expect("Should never happen because bounded_len caps at MaxChunks"),
|
|
}
|
|
}
|
|
|
|
fn empty<N>(n: N) -> Self
|
|
where
|
|
N: UniqueSaturatedInto<usize>,
|
|
{
|
|
let mut n: usize = n.unique_saturated_into();
|
|
|
|
let max_chunks: usize = MaxChunks::get().unique_saturated_into();
|
|
let max_bits = max_chunks.saturating_mul(inner_bits::<Inner>());
|
|
if n > max_bits {
|
|
n = max_bits;
|
|
}
|
|
|
|
let reminder = n & inner_mask::<Inner>();
|
|
let elements = n >> inner_shift::<Inner>();
|
|
|
|
let total_size = if reminder > 0 {
|
|
elements.saturating_add(1)
|
|
} else {
|
|
elements
|
|
};
|
|
|
|
let raw_vec = vec![Inner::zero(); min(total_size, MaxChunks::get() as usize)];
|
|
let bounded_data = BoundedVec::<Inner, MaxChunks>::try_from(raw_vec)
|
|
.expect("Should never happen because bounded_len caps at MaxChunks");
|
|
|
|
Self {
|
|
data: bounded_data,
|
|
active_bits_count: n.unique_saturated_into(),
|
|
}
|
|
}
|
|
|
|
fn empty_from(bitmap: &Self) -> Self {
|
|
Self::empty(bitmap.active_bits_count())
|
|
}
|
|
|
|
fn from_vec<Outer>(values: &Vec<Outer>) -> Self
|
|
where
|
|
Outer: AtLeast8BitUnsigned + TryInto<usize> + PartialEq + Copy,
|
|
{
|
|
let value_bits = inner_bits::<Outer>();
|
|
let n = values.len().saturating_mul(value_bits);
|
|
|
|
let mut new_bitmap = Self::empty(n);
|
|
|
|
for value in values.iter() {
|
|
new_bitmap.insert(*value);
|
|
}
|
|
|
|
new_bitmap
|
|
}
|
|
|
|
fn all_ones<N>(n: N) -> Self
|
|
where
|
|
N: UniqueSaturatedInto<usize>,
|
|
{
|
|
let n: usize = n.unique_saturated_into();
|
|
let mut new_bitmap = Self::empty(n);
|
|
let reminder = n & inner_mask::<Inner>();
|
|
|
|
new_bitmap
|
|
.data
|
|
.iter_mut()
|
|
.rev()
|
|
.skip(if reminder > 0 { 1 } else { 0 })
|
|
.for_each(|inner| *inner = !Inner::zero());
|
|
|
|
if reminder > 0 {
|
|
if let Some(inner) = new_bitmap.data.iter_mut().last() {
|
|
let mask_u64 = (1u64 << reminder) - 1;
|
|
let masked: Inner = mask_u64.unique_saturated_into();
|
|
*inner = masked;
|
|
}
|
|
}
|
|
|
|
new_bitmap
|
|
}
|
|
|
|
fn nullify(&mut self) {
|
|
self.data
|
|
.iter_mut()
|
|
.for_each(|inner| *inner = Inner::zero());
|
|
}
|
|
|
|
fn truncate(&mut self) {
|
|
let Some(highest_bit) = self.highest_bit::<usize>() else {
|
|
self.active_bits_count = 0;
|
|
return;
|
|
};
|
|
|
|
let element_index: usize = highest_bit >> inner_shift::<Inner>();
|
|
let required_elements_count = element_index.saturating_add(1);
|
|
let new_highest_bit = highest_bit.saturating_add(1);
|
|
let reminder = new_highest_bit & inner_mask::<Inner>();
|
|
|
|
self.data.truncate(required_elements_count);
|
|
|
|
if reminder > 0 {
|
|
if let Some(target_element) = self.data.get_mut(element_index) {
|
|
let mask_u64 = (1u64 << reminder) - 1;
|
|
let masked: Inner = mask_u64.unique_saturated_into();
|
|
*target_element &= masked;
|
|
}
|
|
}
|
|
|
|
self.active_bits_count = new_highest_bit as u32;
|
|
}
|
|
|
|
fn insert<N: Copy + TryInto<usize>>(&mut self, i: N) -> Option<N> {
|
|
let index: usize = i.try_into().ok()?;
|
|
|
|
if index >= self.active_bits_count as usize {
|
|
return None;
|
|
}
|
|
|
|
let element_index = index >> inner_shift::<Inner>();
|
|
let bit_shift = index & inner_mask::<Inner>();
|
|
|
|
self.data.get_mut(element_index).map(|element| {
|
|
*element |= Inner::one() << bit_shift;
|
|
i
|
|
})
|
|
}
|
|
|
|
fn remove<N: Copy + TryInto<usize>>(&mut self, i: N) -> Option<N> {
|
|
let index: usize = i.try_into().ok()?;
|
|
|
|
if index >= self.active_bits_count as usize {
|
|
return None;
|
|
}
|
|
|
|
let element_index = (index >> inner_shift::<Inner>()) as usize;
|
|
let bit_shift = index & inner_mask::<Inner>();
|
|
|
|
self.data.get_mut(element_index).map(|element| {
|
|
*element &= !(Inner::one() << bit_shift);
|
|
i
|
|
})
|
|
}
|
|
|
|
fn active_bits_count(&self) -> u32 {
|
|
self.active_bits_count
|
|
}
|
|
|
|
fn highest_bit<N>(&self) -> Option<N>
|
|
where
|
|
usize: UniqueSaturatedInto<N>,
|
|
{
|
|
let shift = inner_shift::<Inner>();
|
|
|
|
self.data
|
|
.iter()
|
|
.enumerate()
|
|
.rev()
|
|
.find_map(|(element_index, &element)| {
|
|
if element.is_zero() {
|
|
return None;
|
|
}
|
|
|
|
let mut temp = element;
|
|
let mut bit_index = 0;
|
|
|
|
loop {
|
|
temp = temp >> 1u32;
|
|
if temp.is_zero() {
|
|
break;
|
|
}
|
|
bit_index += 1;
|
|
}
|
|
|
|
let bit_offset = element_index.checked_shl(shift).unwrap_or(usize::MAX);
|
|
|
|
let index = bit_offset.saturating_add(bit_index);
|
|
|
|
Some(index.unique_saturated_into())
|
|
})
|
|
}
|
|
|
|
fn count_ones_before<N>(&self, index: N) -> Option<N>
|
|
where
|
|
usize: UniqueSaturatedInto<N>,
|
|
N: UniqueSaturatedInto<usize>,
|
|
{
|
|
let index: usize = index.unique_saturated_into();
|
|
|
|
if index >= self.active_bits_count as usize { return None; }
|
|
|
|
let shift = inner_shift::<Inner>();
|
|
let element_index = index >> shift;
|
|
|
|
let bit_index = index & ((1 << shift) - 1);
|
|
|
|
let current_element = self.data.get(element_index)?;
|
|
let lower_bits_mask = (Inner::one() << bit_index) - Inner::one();
|
|
let bits_before = *current_element & lower_bits_mask;
|
|
|
|
self.data.get(0..element_index)?
|
|
.iter()
|
|
.try_fold(0usize, |acc, &element| {
|
|
acc.checked_add(element.count_ones() as usize)
|
|
})
|
|
.and_then(|popcount| {
|
|
popcount.checked_add(bits_before.count_ones() as usize)
|
|
})
|
|
.map(|total| total.unique_saturated_into())
|
|
}
|
|
|
|
fn count_ones<N>(&self) -> N
|
|
where
|
|
u32: UniqueSaturatedInto<N>,
|
|
{
|
|
let ones = self
|
|
.data
|
|
.iter()
|
|
.map(|&element| element.count_ones())
|
|
.sum::<u32>();
|
|
|
|
ones.unique_saturated_into()
|
|
}
|
|
|
|
fn count_zeros<N>(&self) -> N
|
|
where
|
|
u32: UniqueSaturatedInto<N>,
|
|
{
|
|
let zeros = self
|
|
.active_bits_count
|
|
.saturating_sub(self.count_ones::<u32>());
|
|
|
|
zeros.unique_saturated_into()
|
|
}
|
|
|
|
fn is_empty(&self) -> bool {
|
|
self.data.iter().all(|inner| *inner == Inner::zero())
|
|
}
|
|
|
|
fn contains<N>(&self, index: N) -> bool
|
|
where
|
|
N: UniqueSaturatedInto<usize>,
|
|
{
|
|
let index: usize = index.unique_saturated_into();
|
|
|
|
if index >= self.active_bits_count as usize {
|
|
return false;
|
|
}
|
|
|
|
let element_index = (index >> inner_shift::<Inner>()) as usize;
|
|
let bit_shift = index & inner_mask::<Inner>();
|
|
|
|
self.data
|
|
.get(element_index)
|
|
.map(|element| {
|
|
let mask = Inner::one() << bit_shift;
|
|
(*element & mask) != Inner::zero()
|
|
})
|
|
.unwrap_or(false)
|
|
}
|
|
}
|
|
|
|
impl<Inner, MaxChunks> traits::BoundedBitmapMetadata for BoundedBitmap<Inner, MaxChunks>
|
|
where
|
|
MaxChunks: Get<u32>,
|
|
Inner: AtLeast8BitUnsigned + PrimInt + Copy + core::fmt::Debug,
|
|
{
|
|
fn total_bits_capacity() -> u32 {
|
|
let inner_bits = inner_bits::<Inner>() as u32;
|
|
MaxChunks::get().saturating_mul(inner_bits)
|
|
}
|
|
|
|
fn chunk_size() -> u32 {
|
|
inner_bits::<Inner>() as u32
|
|
}
|
|
}
|
|
|
|
impl<Inner, MaxChunks> traits::BoundedBitmapWriter for BoundedBitmap<Inner, MaxChunks>
|
|
where
|
|
MaxChunks: Get<u32>,
|
|
Inner: AtLeast8BitUnsigned + PrimInt + Copy + core::fmt::Debug,
|
|
Inner: BitAnd<Output = Inner>
|
|
+ BitOr<Output = Inner>
|
|
+ BitXor<Output = Inner>
|
|
+ Not<Output = Inner>,
|
|
Inner: BitAndAssign + BitOrAssign + BitXorAssign,
|
|
Inner: Shl<usize, Output = Inner> + Shr<usize, Output = Inner>,
|
|
{
|
|
fn insert<N: Copy + TryInto<usize>>(&mut self, i: N) -> Option<N> {
|
|
self.insert(i)
|
|
}
|
|
|
|
fn remove<N: Copy + TryInto<usize>>(&mut self, i: N) -> Option<N> {
|
|
self.remove(i)
|
|
}
|
|
|
|
fn truncate(&mut self) {
|
|
self.truncate();
|
|
}
|
|
fn nullify(&mut self) {
|
|
self.nullify();
|
|
}
|
|
}
|
|
|
|
impl<Inner, MaxChunks> traits::BoundedBitmapReader for BoundedBitmap<Inner, MaxChunks>
|
|
where
|
|
MaxChunks: Get<u32>,
|
|
Inner: AtLeast8BitUnsigned + PrimInt + Copy + core::fmt::Debug,
|
|
Inner: BitAnd<Output = Inner>
|
|
+ BitOr<Output = Inner>
|
|
+ BitXor<Output = Inner>
|
|
+ Not<Output = Inner>,
|
|
Inner: BitAndAssign + BitOrAssign + BitXorAssign,
|
|
Inner: Shl<usize, Output = Inner> + Shr<usize, Output = Inner>,
|
|
{
|
|
fn active_bits_count(&self) -> u32 {
|
|
self.active_bits_count()
|
|
}
|
|
fn is_empty(&self) -> bool {
|
|
self.is_empty()
|
|
}
|
|
|
|
fn highest_bit<N>(&self) -> Option<N>
|
|
where
|
|
usize: UniqueSaturatedInto<N>,
|
|
{
|
|
self.highest_bit()
|
|
}
|
|
|
|
fn count_ones_before<N>(&self, index: N) -> Option<N>
|
|
where
|
|
usize: UniqueSaturatedInto<N>,
|
|
N: UniqueSaturatedInto<usize>,
|
|
{
|
|
self.count_ones_before(index)
|
|
}
|
|
|
|
fn count_ones<N>(&self) -> N
|
|
where
|
|
u32: UniqueSaturatedInto<N>,
|
|
{
|
|
self.count_ones()
|
|
}
|
|
|
|
fn count_zeros<N>(&self) -> N
|
|
where
|
|
u32: UniqueSaturatedInto<N>,
|
|
{
|
|
self.count_zeros()
|
|
}
|
|
|
|
fn contains<N>(&self, index: N) -> bool
|
|
where
|
|
N: UniqueSaturatedInto<usize>,
|
|
{
|
|
self.contains(index)
|
|
}
|
|
}
|
|
|
|
impl<Inner, MaxChunks> traits::BoundedBitmapGenerator for BoundedBitmap<Inner, MaxChunks>
|
|
where
|
|
MaxChunks: Get<u32>,
|
|
Inner: AtLeast8BitUnsigned + PrimInt + Copy + core::fmt::Debug,
|
|
Inner: BitAnd<Output = Inner>
|
|
+ BitOr<Output = Inner>
|
|
+ BitXor<Output = Inner>
|
|
+ Not<Output = Inner>,
|
|
Inner: BitAndAssign + BitOrAssign + BitXorAssign,
|
|
Inner: Shl<usize, Output = Inner> + Shr<usize, Output = Inner>,
|
|
{
|
|
fn empty<N>(n: N) -> Self
|
|
where
|
|
N: UniqueSaturatedInto<usize>,
|
|
{
|
|
Self::empty(n)
|
|
}
|
|
|
|
fn all_ones<N>(n: N) -> Self
|
|
where
|
|
N: UniqueSaturatedInto<usize>,
|
|
{
|
|
Self::all_ones(n)
|
|
}
|
|
|
|
fn empty_from(bitmap_ref: &Self) -> Self {
|
|
Self::empty_from(bitmap_ref)
|
|
}
|
|
|
|
fn from_vec<Outer>(values_ref: &Vec<Outer>) -> Self
|
|
where
|
|
Outer: AtLeast8BitUnsigned + TryInto<usize> + PartialEq + Copy,
|
|
{
|
|
Self::from_vec(values_ref)
|
|
}
|
|
}
|
|
|
|
impl<Inner, MaxChunks> traits::BoundedBitmapIterable for BoundedBitmap<Inner, MaxChunks>
|
|
where
|
|
MaxChunks: Get<u32>,
|
|
Inner: AtLeast8BitUnsigned + PrimInt + Copy + core::fmt::Debug,
|
|
Inner: BitAnd<Output = Inner>
|
|
+ BitOr<Output = Inner>
|
|
+ BitXor<Output = Inner>
|
|
+ Not<Output = Inner>,
|
|
Inner: BitAndAssign + BitOrAssign + BitXorAssign,
|
|
Inner: Shl<usize, Output = Inner> + Shr<usize, Output = Inner>,
|
|
{
|
|
type IntoIter<'a, ItemType> = BoundedBitmapIter<'a, Inner, MaxChunks, ItemType>
|
|
where
|
|
Self: 'a,
|
|
ItemType: 'static,
|
|
u32: UniqueSaturatedInto<ItemType>;
|
|
|
|
fn iter<ItemType>(&self) -> Self::IntoIter<'_, ItemType>
|
|
where
|
|
ItemType: 'static,
|
|
u32: UniqueSaturatedInto<ItemType>,
|
|
{
|
|
BoundedBitmapIter {
|
|
bounded_bitmap: self,
|
|
current_bit: 0,
|
|
_marker: sp_std::marker::PhantomData,
|
|
}
|
|
}
|
|
}
|
|
|
|
macro_rules! impl_bitmap_binary_ops {
|
|
($trait:ident, $method:ident, $trait_assign:ident, $method_assign:ident, $op:tt) => (
|
|
impl<Inner, MaxChunks> $trait for BoundedBitmap<Inner, MaxChunks>
|
|
where
|
|
MaxChunks: Get<u32>,
|
|
Inner: AtLeast8BitUnsigned + PrimInt + Copy + core::fmt::Debug,
|
|
Inner: BitAnd<Output = Inner> + BitOr<Output = Inner> + BitXor<Output = Inner> + Not<Output = Inner>,
|
|
Inner: BitAndAssign + BitOrAssign + BitXorAssign,
|
|
Inner: Shl<usize, Output = Inner> + Shr<usize, Output = Inner>,
|
|
{
|
|
type Output = BoundedBitmap<Inner, MaxChunks>;
|
|
fn $method(self, rhs: Self) -> Self::Output {
|
|
self.combine(&rhs, |a, b| a $op b)
|
|
}
|
|
}
|
|
|
|
impl<'a, Inner, MaxChunks> $trait<&'a BoundedBitmap<Inner, MaxChunks>> for BoundedBitmap<Inner, MaxChunks>
|
|
where
|
|
MaxChunks: Get<u32>,
|
|
Inner: AtLeast8BitUnsigned + PrimInt + Copy + core::fmt::Debug,
|
|
Inner: BitAnd<Output = Inner> + BitOr<Output = Inner> + BitXor<Output = Inner> + Not<Output = Inner>,
|
|
Inner: BitAndAssign + BitOrAssign + BitXorAssign,
|
|
Inner: Shl<usize, Output = Inner> + Shr<usize, Output = Inner>,
|
|
{
|
|
type Output = BoundedBitmap<Inner, MaxChunks>;
|
|
fn $method(self, rhs: &'a BoundedBitmap<Inner, MaxChunks>) -> Self::Output {
|
|
self.combine(&rhs, |a, b| a $op b)
|
|
}
|
|
}
|
|
|
|
impl<Inner, MaxChunks> $trait_assign for BoundedBitmap<Inner, MaxChunks>
|
|
where
|
|
MaxChunks: Get<u32>,
|
|
Inner: AtLeast8BitUnsigned + PrimInt + Copy + core::fmt::Debug,
|
|
Inner: BitAnd<Output = Inner> + BitOr<Output = Inner> + BitXor<Output = Inner> + Not<Output = Inner>,
|
|
Inner: BitAndAssign + BitOrAssign + BitXorAssign,
|
|
Inner: Shl<usize, Output = Inner> + Shr<usize, Output = Inner>,
|
|
{
|
|
fn $method_assign(&mut self, rhs: BoundedBitmap<Inner, MaxChunks>) {
|
|
*self = self.combine(&rhs, |a, b| a $op b)
|
|
}
|
|
}
|
|
|
|
impl<'a, Inner, MaxChunks> $trait_assign<&'a BoundedBitmap<Inner, MaxChunks>> for BoundedBitmap<Inner, MaxChunks>
|
|
where
|
|
MaxChunks: Get<u32>,
|
|
Inner: AtLeast8BitUnsigned + PrimInt + Copy + core::fmt::Debug,
|
|
Inner: BitAnd<Output = Inner> + BitOr<Output = Inner> + BitXor<Output = Inner> + Not<Output = Inner>,
|
|
Inner: BitAndAssign + BitOrAssign + BitXorAssign,
|
|
Inner: Shl<usize, Output = Inner> + Shr<usize, Output = Inner>,
|
|
{
|
|
fn $method_assign(&mut self, rhs: &'a BoundedBitmap<Inner, MaxChunks>) {
|
|
*self = self.combine(rhs, |a, b| a $op b)
|
|
}
|
|
}
|
|
|
|
impl<'a, 'b, Inner, MaxChunks> $trait<&'b BoundedBitmap<Inner, MaxChunks>> for &'a BoundedBitmap<Inner, MaxChunks>
|
|
where
|
|
MaxChunks: Get<u32>,
|
|
Inner: AtLeast8BitUnsigned + PrimInt + Copy + core::fmt::Debug,
|
|
Inner: BitAnd<Output = Inner> + BitOr<Output = Inner> + BitXor<Output = Inner> + Not<Output = Inner>,
|
|
Inner: BitAndAssign + BitOrAssign + BitXorAssign,
|
|
Inner: Shl<usize, Output = Inner> + Shr<usize, Output = Inner>,
|
|
{
|
|
type Output = BoundedBitmap<Inner, MaxChunks>;
|
|
|
|
fn $method(
|
|
self,
|
|
rhs: &'b BoundedBitmap<Inner, MaxChunks>,
|
|
) -> Self::Output {
|
|
self.combine(rhs, |a, b| a $op b)
|
|
}
|
|
}
|
|
|
|
impl<'a, Inner, MaxChunks> $trait<BoundedBitmap<Inner, MaxChunks>> for &'a BoundedBitmap<Inner, MaxChunks>
|
|
where
|
|
MaxChunks: Get<u32>,
|
|
Inner: AtLeast8BitUnsigned + PrimInt + Copy + core::fmt::Debug,
|
|
Inner: BitAnd<Output = Inner> + BitOr<Output = Inner> + BitXor<Output = Inner> + Not<Output = Inner>,
|
|
Inner: BitAndAssign + BitOrAssign + BitXorAssign,
|
|
Inner: Shl<usize, Output = Inner> + Shr<usize, Output = Inner>,
|
|
{
|
|
type Output = BoundedBitmap<Inner, MaxChunks>;
|
|
|
|
fn $method(
|
|
self,
|
|
rhs: BoundedBitmap<Inner, MaxChunks>,
|
|
) -> Self::Output {
|
|
self.combine(&rhs, |a, b| a $op b)
|
|
}
|
|
}
|
|
);
|
|
}
|
|
|
|
impl_bitmap_binary_ops!(BitOr, bitor, BitOrAssign, bitor_assign, |);
|
|
impl_bitmap_binary_ops!(BitAnd, bitand, BitAndAssign, bitand_assign, &);
|
|
impl_bitmap_binary_ops!(BitXor, bitxor, BitXorAssign, bitxor_assign, ^);
|
|
|
|
impl<Inner, MaxChunks> Clone for BoundedBitmap<Inner, MaxChunks>
|
|
where
|
|
MaxChunks: Get<u32>,
|
|
Inner: Copy,
|
|
{
|
|
fn clone(&self) -> Self {
|
|
let raw_vec: Vec<Inner> = self.data.to_vec();
|
|
let bounded_data = BoundedVec::<Inner, MaxChunks>::try_from(raw_vec).unwrap_or_default();
|
|
|
|
Self {
|
|
data: bounded_data,
|
|
active_bits_count: self.active_bits_count,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<Inner, MaxChunks> Not for BoundedBitmap<Inner, MaxChunks>
|
|
where
|
|
MaxChunks: Get<u32>,
|
|
Inner: AtLeast8BitUnsigned + PrimInt + Copy + core::fmt::Debug,
|
|
Inner: BitAnd<Output = Inner>
|
|
+ BitOr<Output = Inner>
|
|
+ BitXor<Output = Inner>
|
|
+ Not<Output = Inner>,
|
|
Inner: BitAndAssign + BitOrAssign + BitXorAssign,
|
|
Inner: Shl<usize, Output = Inner> + Shr<usize, Output = Inner>,
|
|
{
|
|
type Output = Self;
|
|
|
|
fn not(self) -> Self::Output {
|
|
let n = self.active_bits_count;
|
|
let full_bitmap = BoundedBitmap::<Inner, MaxChunks>::all_ones(n);
|
|
|
|
full_bitmap ^ self
|
|
}
|
|
}
|
|
|
|
impl<'a, Inner, MaxChunks> Not for &'a BoundedBitmap<Inner, MaxChunks>
|
|
where
|
|
MaxChunks: Get<u32>,
|
|
Inner: AtLeast8BitUnsigned + PrimInt + Copy + core::fmt::Debug,
|
|
Inner: BitAnd<Output = Inner>
|
|
+ BitOr<Output = Inner>
|
|
+ BitXor<Output = Inner>
|
|
+ Not<Output = Inner>,
|
|
Inner: BitAndAssign + BitOrAssign + BitXorAssign,
|
|
Inner: Shl<usize, Output = Inner> + Shr<usize, Output = Inner>,
|
|
{
|
|
type Output = BoundedBitmap<Inner, MaxChunks>;
|
|
|
|
fn not(self) -> Self::Output {
|
|
let n = self.active_bits_count;
|
|
let full_bitmap = BoundedBitmap::<Inner, MaxChunks>::all_ones(n);
|
|
|
|
full_bitmap ^ self
|
|
}
|
|
}
|
|
|
|
impl<Inner, MaxChunks> PartialEq for BoundedBitmap<Inner, MaxChunks>
|
|
where
|
|
MaxChunks: Get<u32>,
|
|
Inner: AtLeast8BitUnsigned + Copy + PartialEq,
|
|
{
|
|
fn eq(&self, other: &Self) -> bool {
|
|
self.active_bits_count == other.active_bits_count && self.data == other.data
|
|
}
|
|
}
|
|
|
|
impl<Inner, MaxChunks> Eq for BoundedBitmap<Inner, MaxChunks>
|
|
where
|
|
MaxChunks: Get<u32>,
|
|
Inner: AtLeast8BitUnsigned + Copy + Eq,
|
|
{
|
|
}
|
|
|
|
impl<Inner, MaxChunks> Default for BoundedBitmap<Inner, MaxChunks>
|
|
where
|
|
MaxChunks: Get<u32>,
|
|
Inner: AtLeast8BitUnsigned + PrimInt + Copy + core::fmt::Debug,
|
|
Inner: BitAnd<Output = Inner>
|
|
+ BitOr<Output = Inner>
|
|
+ BitXor<Output = Inner>
|
|
+ Not<Output = Inner>,
|
|
Inner: BitAndAssign + BitOrAssign + BitXorAssign,
|
|
Inner: Shl<usize, Output = Inner> + Shr<usize, Output = Inner>,
|
|
{
|
|
fn default() -> Self {
|
|
let num_chunks = MaxChunks::get() as usize;
|
|
let bits_per_chunk = inner_bits::<Inner>();
|
|
let total_bits = num_chunks * bits_per_chunk;
|
|
Self::empty(total_bits)
|
|
}
|
|
}
|
|
|
|
pub struct BoundedBitmapIter<'a, Inner, MaxChunks, ItemType>
|
|
where
|
|
MaxChunks: Get<u32>,
|
|
{
|
|
bounded_bitmap: &'a BoundedBitmap<Inner, MaxChunks>,
|
|
current_bit: u32,
|
|
_marker: PhantomData<ItemType>,
|
|
}
|
|
|
|
impl<'a, Inner, MaxChunks, ItemType> Iterator for BoundedBitmapIter<'a, Inner, MaxChunks, ItemType>
|
|
where
|
|
MaxChunks: Get<u32>,
|
|
Inner: AtLeast8BitUnsigned + Copy,
|
|
Inner: BitAnd<Output = Inner> + Not<Output = Inner>,
|
|
u32: UniqueSaturatedInto<ItemType>,
|
|
{
|
|
type Item = ItemType;
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
while self.current_bit < self.bounded_bitmap.active_bits_count {
|
|
let index_u32 = self.current_bit;
|
|
let index_usize = index_u32 as usize;
|
|
self.current_bit = self.current_bit.saturating_add(1);
|
|
|
|
let element_index = index_usize >> inner_shift::<Inner>();
|
|
let bit_shift = (index_usize & inner_mask::<Inner>()) as u32;
|
|
|
|
match self.bounded_bitmap.data.get(element_index) {
|
|
Some(element) => {
|
|
if let Some(mask) = Inner::one().checked_shl(bit_shift) {
|
|
if !(*element & mask).is_zero() {
|
|
return Some(index_u32.unique_saturated_into());
|
|
}
|
|
}
|
|
}
|
|
None => {
|
|
self.current_bit = self.bounded_bitmap.active_bits_count;
|
|
return None;
|
|
}
|
|
}
|
|
}
|
|
None
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use frame_support::traits::Get;
|
|
use sp_runtime::traits::{One, Zero};
|
|
|
|
use super::traits::*;
|
|
|
|
#[derive(Clone, Copy, PartialEq, Eq, core::fmt::Debug, Encode, Decode, MaxEncodedLen)]
|
|
pub struct Entries4;
|
|
impl Get<u32> for Entries4 {
|
|
fn get() -> u32 {
|
|
4
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Copy, PartialEq, Eq, core::fmt::Debug, Encode, Decode, MaxEncodedLen)]
|
|
pub struct Entries8;
|
|
impl Get<u32> for Entries8 {
|
|
fn get() -> u32 {
|
|
8
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Copy, PartialEq, Eq, core::fmt::Debug, Encode, Decode, MaxEncodedLen)]
|
|
pub struct Entries16;
|
|
impl Get<u32> for Entries16 {
|
|
fn get() -> u32 {
|
|
16
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Copy, PartialEq, Eq, core::fmt::Debug, Encode, Decode, MaxEncodedLen)]
|
|
pub struct Entries128;
|
|
impl Get<u32> for Entries128 {
|
|
fn get() -> u32 {
|
|
128
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Copy, PartialEq, Eq, core::fmt::Debug, Encode, Decode, MaxEncodedLen)]
|
|
pub struct Entries512;
|
|
impl Get<u32> for Entries512 {
|
|
fn get() -> u32 {
|
|
512
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Copy, PartialEq, Eq, core::fmt::Debug, Encode, Decode, MaxEncodedLen)]
|
|
pub struct Entries1024;
|
|
impl Get<u32> for Entries1024 {
|
|
fn get() -> u32 {
|
|
1024
|
|
}
|
|
}
|
|
|
|
macro_rules! test_bitmap {
|
|
($mod_name:ident, $inner_type:ty, $max_chunks:ty) => {
|
|
mod $mod_name {
|
|
use super::*;
|
|
|
|
type TestBitmap = BoundedBitmap<$inner_type, $max_chunks>;
|
|
|
|
#[test]
|
|
fn test_empty_initialization_and_saturation() {
|
|
let bits_per_element = inner_bits::<$inner_type>();
|
|
let max_allowed_elements = <$max_chunks>::get() as usize;
|
|
let absolute_max_bits = max_allowed_elements.saturating_mul(bits_per_element);
|
|
|
|
let bitmap = TestBitmap::empty(3usize);
|
|
assert_eq!(bitmap.active_bits_count(), 3);
|
|
assert_eq!(bitmap.data.len(), 1);
|
|
|
|
let huge_bitmap = TestBitmap::empty(absolute_max_bits + 1000);
|
|
assert_eq!(huge_bitmap.active_bits_count, absolute_max_bits as u32);
|
|
assert_eq!(huge_bitmap.data.len(), max_allowed_elements);
|
|
}
|
|
|
|
#[test]
|
|
fn test_sequential_insert_and_out_of_bounds() {
|
|
let bits_per_element = inner_bits::<$inner_type>();
|
|
let mut bitmap = TestBitmap::empty(bits_per_element * 2);
|
|
|
|
assert!(bitmap.insert(0u32).is_some());
|
|
assert_eq!(bitmap.count_ones::<u32>(), 1);
|
|
|
|
let boundary_bit = bits_per_element as u32;
|
|
assert!(bitmap.insert(boundary_bit).is_some());
|
|
assert_eq!(bitmap.count_ones::<u32>(), 2);
|
|
|
|
let out_of_bounds_bit = (bits_per_element * 2) as u32;
|
|
assert!(bitmap.insert(out_of_bounds_bit).is_none());
|
|
assert_eq!(bitmap.count_ones::<u32>(), 2);
|
|
}
|
|
|
|
#[test]
|
|
fn test_truncate_and_memory_releasing() {
|
|
let bits_per_element = inner_bits::<$inner_type>();
|
|
let mut bitmap = TestBitmap::empty(bits_per_element * 2);
|
|
assert_eq!(bitmap.data.len(), 2);
|
|
|
|
bitmap.insert(0u32).unwrap();
|
|
bitmap.truncate();
|
|
assert_eq!(bitmap.data.len(), 1);
|
|
assert_eq!(bitmap.active_bits_count, 1);
|
|
}
|
|
|
|
#[test]
|
|
fn test_not_inversion_and_tail_nullifying() {
|
|
let mut bitmap = TestBitmap::empty(5usize);
|
|
bitmap.insert(0u32).unwrap();
|
|
|
|
let inverted = !bitmap;
|
|
|
|
if let Some(&last_element) = inverted.data.get(0) {
|
|
let expected_mask = (<$inner_type>::one() << 5) - <$inner_type>::one();
|
|
assert_eq!(last_element & !expected_mask, <$inner_type>::zero());
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_bitor_different_sizes() {
|
|
let bits_per_element = inner_bits::<$inner_type>();
|
|
let mut bitmap_a = TestBitmap::empty(5usize);
|
|
bitmap_a.insert(2u32).unwrap();
|
|
|
|
let mut bitmap_b = TestBitmap::empty(bits_per_element + 5);
|
|
let far_bit = (bits_per_element + 1) as u32;
|
|
bitmap_b.insert(far_bit).unwrap();
|
|
|
|
let result = bitmap_a | bitmap_b;
|
|
assert_eq!(result.active_bits_count, (bits_per_element + 5) as u32);
|
|
assert_eq!(result.count_ones::<u32>(), 2);
|
|
assert_eq!(result.data.len(), 2);
|
|
}
|
|
|
|
#[test]
|
|
fn test_bitxor_different_sizes() {
|
|
let bits_per_element = inner_bits::<$inner_type>();
|
|
let mut bitmap_a = TestBitmap::empty(10usize);
|
|
let mut bitmap_b = TestBitmap::empty(bits_per_element + 10);
|
|
|
|
bitmap_a.insert(5u32).unwrap();
|
|
bitmap_b.insert(5u32).unwrap();
|
|
bitmap_a.insert(8u32).unwrap();
|
|
|
|
let far_bit = (bits_per_element + 2) as u32;
|
|
bitmap_b.insert(far_bit).unwrap();
|
|
|
|
let result = bitmap_a ^ bitmap_b;
|
|
assert_eq!(result.active_bits_count, (bits_per_element + 10) as u32);
|
|
assert_eq!(result.count_ones::<u32>(), 2);
|
|
}
|
|
|
|
#[test]
|
|
fn test_bitand_different_sizes() {
|
|
let bits_per_element = inner_bits::<$inner_type>();
|
|
let bigger_length = (bits_per_element + 5) as u32;
|
|
|
|
let mut bitmap_a = TestBitmap::empty(5usize);
|
|
bitmap_a.insert(2u32).unwrap();
|
|
|
|
let mut bitmap_b = TestBitmap::empty(bigger_length);
|
|
bitmap_b.insert(2u32).unwrap();
|
|
|
|
let far_bit = (bits_per_element + 1) as u32;
|
|
bitmap_b.insert(far_bit).unwrap();
|
|
|
|
let mut result = bitmap_a & bitmap_b;
|
|
assert_eq!(result.count_ones::<u32>(), 1);
|
|
assert_eq!(result.active_bits_count, bigger_length);
|
|
|
|
result.truncate();
|
|
assert_eq!(result.data.len(), 1);
|
|
}
|
|
|
|
#[test]
|
|
fn test_bitor_assign_different_sizes() {
|
|
let bits_per_element = inner_bits::<$inner_type>();
|
|
let mut bitmap_a = TestBitmap::empty(5usize);
|
|
bitmap_a.insert(1u32).unwrap();
|
|
|
|
let mut bitmap_b = TestBitmap::empty(bits_per_element + 5);
|
|
let far_bit = (bits_per_element + 1) as u32;
|
|
bitmap_b.insert(far_bit).unwrap();
|
|
|
|
bitmap_a |= bitmap_b;
|
|
assert_eq!(bitmap_a.active_bits_count, (bits_per_element + 5) as u32);
|
|
assert_eq!(bitmap_a.count_ones::<u32>(), 2);
|
|
assert_eq!(bitmap_a.data.len(), 2);
|
|
}
|
|
|
|
#[test]
|
|
fn test_and_assign_different_sizes() {
|
|
let bits_per_element = inner_bits::<$inner_type>();
|
|
let bigger_length = (bits_per_element + 5) as u32;
|
|
|
|
let mut bitmap_a = TestBitmap::empty(5usize);
|
|
bitmap_a.insert(2u32).unwrap();
|
|
|
|
let mut bitmap_b = TestBitmap::empty(bigger_length);
|
|
bitmap_b.insert(2u32).unwrap();
|
|
|
|
let far_bit = (bits_per_element + 1) as u32;
|
|
bitmap_b.insert(far_bit).unwrap();
|
|
|
|
bitmap_a &= bitmap_b;
|
|
assert_eq!(bitmap_a.active_bits_count(), bigger_length);
|
|
assert_eq!(bitmap_a.count_ones::<u32>(), 1);
|
|
|
|
bitmap_a.truncate();
|
|
assert_eq!(bitmap_a.active_bits_count(), 3);
|
|
assert_eq!(bitmap_a.data.len(), 1);
|
|
}
|
|
|
|
#[test]
|
|
fn test_xor_assign_different_sizes() {
|
|
let bits_per_element = inner_bits::<$inner_type>();
|
|
let bigger_length = (bits_per_element + 5) as u32;
|
|
|
|
let mut bitmap_a = TestBitmap::empty(10usize);
|
|
let mut bitmap_b = TestBitmap::empty(bigger_length);
|
|
|
|
bitmap_a.insert(5u32).unwrap();
|
|
bitmap_b.insert(5u32).unwrap();
|
|
|
|
bitmap_a.insert(8u32).unwrap();
|
|
|
|
let far_bit = (bits_per_element + 2) as u32;
|
|
bitmap_b.insert(far_bit).unwrap();
|
|
|
|
bitmap_a ^= bitmap_b;
|
|
assert_eq!(bitmap_a.active_bits_count(), bigger_length);
|
|
assert_eq!(bitmap_a.count_ones::<u32>(), 2);
|
|
assert_eq!(bitmap_a.data.len(), 2);
|
|
}
|
|
|
|
#[test]
|
|
fn test_iterator_only_iterates_over_ones() {
|
|
let max_allowed_chunks = <$max_chunks>::get();
|
|
let mut bitmap = TestBitmap::default();
|
|
|
|
let bit_1 = 0u32;
|
|
let bit_2 = max_allowed_chunks.saturating_div(2);
|
|
let bit_3 = max_allowed_chunks.saturating_sub(1);
|
|
|
|
bitmap.insert(bit_1).unwrap();
|
|
bitmap.insert(bit_2).unwrap();
|
|
bitmap.insert(bit_3).unwrap();
|
|
|
|
let mut iter = bitmap.iter();
|
|
|
|
assert_eq!(iter.next(), Some(bit_1));
|
|
assert_eq!(iter.next(), Some(bit_2));
|
|
assert_eq!(iter.next(), Some(bit_3));
|
|
assert_eq!(iter.next(), None);
|
|
}
|
|
|
|
#[test]
|
|
fn test_default_and_nullify_and_contains() {
|
|
let default_bitmap = TestBitmap::default();
|
|
let num_chunks = <$max_chunks>::get();
|
|
let bits_per_chunk = inner_bits::<$inner_type>();
|
|
let total_bits = (num_chunks as usize) * bits_per_chunk;
|
|
|
|
assert_eq!(default_bitmap.active_bits_count(), total_bits as u32);
|
|
assert_eq!(default_bitmap.count_ones::<u32>(), 0);
|
|
|
|
let reminder = total_bits & inner_mask::<$inner_type>();
|
|
let mut expected = total_bits >> inner_shift::<$inner_type>();
|
|
if reminder > 0 {
|
|
expected = expected.saturating_add(1);
|
|
}
|
|
assert_eq!(default_bitmap.data.len(), expected);
|
|
|
|
let mut bitmap = TestBitmap::empty(10usize);
|
|
assert!(!bitmap.contains(5u32));
|
|
|
|
bitmap.insert(5u32).unwrap();
|
|
assert!(bitmap.contains(5u32));
|
|
assert!(!bitmap.contains(6u32));
|
|
|
|
bitmap.remove(5u32);
|
|
assert!(!bitmap.contains(5u32));
|
|
assert_eq!(bitmap.count_ones::<u32>(), 0);
|
|
|
|
let mut bitmap_to_nullify = TestBitmap::empty(30usize);
|
|
bitmap_to_nullify.insert(14u32).unwrap();
|
|
bitmap_to_nullify.insert(15u32).unwrap();
|
|
|
|
bitmap_to_nullify.nullify();
|
|
assert_eq!(bitmap_to_nullify.count_ones::<u32>(), 0);
|
|
assert_eq!(bitmap_to_nullify.active_bits_count(), 30);
|
|
for element in bitmap_to_nullify.data.iter() {
|
|
assert_eq!(*element, <$inner_type>::zero());
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_count_zeros() {
|
|
let bits_per_element = inner_bits::<$inner_type>();
|
|
let bitmap = TestBitmap::empty(bits_per_element + 10);
|
|
|
|
let total_zeros: u32 = bitmap.count_zeros();
|
|
assert_eq!(total_zeros, (bits_per_element + 10) as u32);
|
|
|
|
let mut mut_bitmap = TestBitmap::empty(10usize);
|
|
mut_bitmap.insert(3u32).unwrap();
|
|
mut_bitmap.insert(7u32).unwrap();
|
|
|
|
let zeros: u32 = mut_bitmap.count_zeros();
|
|
assert_eq!(zeros, 8);
|
|
}
|
|
|
|
#[test]
|
|
fn test_empty_from() {
|
|
let mut original = TestBitmap::empty(25usize);
|
|
original.insert(10u32).unwrap();
|
|
|
|
let brand_new = TestBitmap::empty_from(&original);
|
|
assert_eq!(brand_new.active_bits_count(), 25);
|
|
assert_eq!(brand_new.count_ones::<u32>(), 0);
|
|
}
|
|
|
|
#[test]
|
|
fn test_from_vec() {
|
|
let values_vec: Vec<u8> = (0..10).filter(|i| i % 2 == 1).collect();
|
|
let bitmap = TestBitmap::from_vec(&values_vec);
|
|
|
|
(0..10).for_each(|i| {
|
|
if i % 2 == 0 {
|
|
assert!(!bitmap.contains(i));
|
|
} else {
|
|
assert!(bitmap.contains(i));
|
|
}
|
|
});
|
|
|
|
assert_eq!(bitmap.count_ones::<usize>(), values_vec.len());
|
|
}
|
|
|
|
#[test]
|
|
fn test_count_ones_before_basic() {
|
|
let w = <$inner_type>::BITS as usize;
|
|
let idx = |x: usize| -> $inner_type {
|
|
x.try_into().ok().expect("bit index fits inner type")
|
|
};
|
|
|
|
let mut indices: Vec<$inner_type> = vec![
|
|
0u8.into(),
|
|
1u8.into(),
|
|
3u8.into()
|
|
];
|
|
|
|
indices.extend([idx(w), idx(w + 1), idx(w + 3)] as [$inner_type; 3]);
|
|
let bitmap = TestBitmap::from_vec(&indices);
|
|
|
|
assert_eq!(bitmap.count_ones_before(0), Some(0));
|
|
assert_eq!(bitmap.count_ones_before(1), Some(1));
|
|
assert_eq!(bitmap.count_ones_before(2), Some(2));
|
|
assert_eq!(bitmap.count_ones_before(3), Some(2));
|
|
assert_eq!(bitmap.count_ones_before(4), Some(3));
|
|
assert_eq!(bitmap.count_ones_before(w), Some(3));
|
|
|
|
assert_eq!(bitmap.count_ones_before(w + 1), Some(4));
|
|
assert_eq!(bitmap.count_ones_before(w + 4), Some(6));
|
|
assert_eq!(bitmap.count_ones_before(2 * w), Some(6));
|
|
}
|
|
|
|
#[test]
|
|
fn test_count_ones_before_crossing_elements() {
|
|
let w = <$inner_type>::BITS as usize;
|
|
let idx = |x: usize| -> $inner_type {
|
|
x.try_into().ok().expect("bit index fits inner type")
|
|
};
|
|
|
|
let mut bitmap = TestBitmap::empty(2 * w + 1);
|
|
for i in [0usize, 1, w, w + 1, w + 2] {
|
|
bitmap.insert(idx(i));
|
|
}
|
|
|
|
let bits_per_element = core::mem::size_of::<$inner_type>() * 8;
|
|
|
|
assert_eq!(bitmap.count_ones_before(bits_per_element), Some(2));
|
|
assert_eq!(bitmap.count_ones_before(bits_per_element + 1), Some(3));
|
|
assert_eq!(bitmap.count_ones_before(bits_per_element + 3), Some(5));
|
|
assert_eq!(bitmap.count_ones_before(2 * bits_per_element), Some(5));
|
|
|
|
assert_eq!(bitmap.count_ones_before(2 * bits_per_element + 1), None);
|
|
}
|
|
|
|
#[test]
|
|
fn test_count_ones_before_bounds_and_overflow() {
|
|
let w = <$inner_type>::BITS as usize;
|
|
let idx = |x: usize| -> $inner_type {
|
|
x.try_into().ok().expect("bit index fits inner type")
|
|
};
|
|
|
|
let mut bitmap = TestBitmap::empty(w);
|
|
for i in 0..w {
|
|
bitmap.insert(idx(i));
|
|
}
|
|
|
|
let bits_per_element = (core::mem::size_of::<$inner_type>() * 8) as u32;
|
|
|
|
assert_eq!(bitmap.count_ones_before(bits_per_element - 1), Some(bits_per_element - 1));
|
|
assert_eq!(bitmap.count_ones_before(bits_per_element), None);
|
|
assert_eq!(bitmap.count_ones_before(10000u32), None);
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
// 1. Matrix rows for u8
|
|
test_bitmap!(matrix_u8_entries4, u8, Entries4);
|
|
test_bitmap!(matrix_u8_entries8, u8, Entries8);
|
|
test_bitmap!(matrix_u8_entries16, u8, Entries16);
|
|
test_bitmap!(matrix_u8_entries128, u8, Entries128);
|
|
test_bitmap!(matrix_u8_entries512, u8, Entries512);
|
|
test_bitmap!(matrix_u8_entries1024, u8, Entries1024);
|
|
|
|
// 2. Matrix rows for u16
|
|
test_bitmap!(matrix_u16_entries4, u16, Entries4);
|
|
test_bitmap!(matrix_u16_entries8, u16, Entries8);
|
|
test_bitmap!(matrix_u16_entries16, u16, Entries16);
|
|
test_bitmap!(matrix_u16_entries128, u16, Entries128);
|
|
test_bitmap!(matrix_u16_entries512, u16, Entries512);
|
|
test_bitmap!(matrix_u16_entries1024, u16, Entries1024);
|
|
|
|
// 3. Matrix rows for u32
|
|
test_bitmap!(matrix_u32_entries4, u32, Entries4);
|
|
test_bitmap!(matrix_u32_entries8, u32, Entries8);
|
|
test_bitmap!(matrix_u32_entries16, u32, Entries16);
|
|
test_bitmap!(matrix_u32_entries128, u32, Entries128);
|
|
test_bitmap!(matrix_u32_entries512, u32, Entries512);
|
|
test_bitmap!(matrix_u32_entries1024, u32, Entries1024);
|
|
|
|
// 4. Matrix rows for u64
|
|
test_bitmap!(matrix_u64_entries4, u64, Entries4);
|
|
test_bitmap!(matrix_u64_entries8, u64, Entries8);
|
|
test_bitmap!(matrix_u64_entries16, u64, Entries16);
|
|
test_bitmap!(matrix_u64_entries128, u64, Entries128);
|
|
test_bitmap!(matrix_u64_entries512, u64, Entries512);
|
|
test_bitmap!(matrix_u64_entries1024, u64, Entries1024);
|
|
|
|
// 5. Matrix rows for u128
|
|
test_bitmap!(matrix_u128_entries4, u128, Entries4);
|
|
test_bitmap!(matrix_u128_entries8, u128, Entries8);
|
|
test_bitmap!(matrix_u128_entries16, u128, Entries16);
|
|
test_bitmap!(matrix_u128_entries128, u128, Entries128);
|
|
test_bitmap!(matrix_u128_entries512, u128, Entries512);
|
|
test_bitmap!(matrix_u128_entries1024, u128, Entries1024);
|
|
}
|