1191 lines
40 KiB
Rust
1191 lines
40 KiB
Rust
use codec::{Decode, Encode};
|
|
use num_traits::PrimInt;
|
|
use scale_info::TypeInfo;
|
|
|
|
use sp_arithmetic::traits::AtLeast8BitUnsigned;
|
|
use sp_runtime::{traits::UniqueSaturatedInto, RuntimeDebug};
|
|
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, RuntimeDebug, 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, 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>,
|
|
{
|
|
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 from_bitmask<Outer>(values: &Vec<Outer>) -> Self
|
|
where
|
|
Outer: AtLeast8BitUnsigned + PrimInt,
|
|
{
|
|
let value_bits = inner_bits::<Outer>();
|
|
let n = values.iter().enumerate().rev()
|
|
.find(|(_, &val)| val != Outer::zero())
|
|
.map(|(idx, &val)| {
|
|
let active_bits = value_bits - (val.leading_zeros() as usize);
|
|
idx.saturating_mul(value_bits).saturating_add(active_bits)
|
|
})
|
|
.unwrap_or(0);
|
|
|
|
let mut new_bitmap = Self::empty(n);
|
|
|
|
for (value_index, value) in values.iter().enumerate() {
|
|
for bit_index in 0..value_bits {
|
|
let bit_mask = Outer::one() << bit_index;
|
|
if (*value & bit_mask) == Outer::zero() {
|
|
continue;
|
|
}
|
|
|
|
let index = value_index
|
|
.saturating_mul(value_bits)
|
|
.saturating_add(bit_index);
|
|
|
|
if let None = new_bitmap.insert(index as u32) {
|
|
return new_bitmap;
|
|
}
|
|
}
|
|
}
|
|
|
|
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<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<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_bitmask<Outer>(values_ref: &Vec<Outer>) -> Self
|
|
where
|
|
Outer: AtLeast8BitUnsigned + PrimInt,
|
|
{
|
|
Self::from_bitmask(values_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_from_bitmask_where_each_u8_is_a_bit() {
|
|
let byte1 = 77u8;
|
|
let byte2 = 42u8;
|
|
let byte3 = 69u8;
|
|
|
|
let raw_bits: Vec<u8> = vec![byte1, byte2, byte3];
|
|
let bitmap = TestBitmap::from_bitmask(&raw_bits);
|
|
|
|
let count_ones = raw_bits.iter().map(|b| b.count_ones()).sum::<u32>();
|
|
let filled_bits = (raw_bits.len() as u32 - 1) * 8;
|
|
let expected_bits = filled_bits + (8 - byte3.leading_zeros());
|
|
|
|
assert_eq!(bitmap.active_bits_count(), expected_bits);
|
|
assert_eq!(bitmap.count_ones::<u32>(), count_ones);
|
|
|
|
// 77 - 10110010
|
|
assert!(bitmap.contains(0u32));
|
|
assert!(!bitmap.contains(1u32));
|
|
assert!(bitmap.contains(2u32));
|
|
assert!(bitmap.contains(3u32));
|
|
assert!(!bitmap.contains(4u32));
|
|
assert!(!bitmap.contains(5u32));
|
|
assert!(bitmap.contains(6u32));
|
|
assert!(!bitmap.contains(7u32));
|
|
|
|
// 42 - 01010100
|
|
assert!(!bitmap.contains(8u32));
|
|
assert!(bitmap.contains(9u32));
|
|
assert!(!bitmap.contains(10u32));
|
|
assert!(bitmap.contains(11u32));
|
|
assert!(!bitmap.contains(12u32));
|
|
assert!(bitmap.contains(13u32));
|
|
assert!(!bitmap.contains(14u32));
|
|
assert!(!bitmap.contains(15u32));
|
|
|
|
// 69 - 10100010
|
|
assert!(bitmap.contains(16u32));
|
|
assert!(!bitmap.contains(17u32));
|
|
assert!(bitmap.contains(18u32));
|
|
assert!(!bitmap.contains(19u32));
|
|
assert!(!bitmap.contains(20u32));
|
|
assert!(!bitmap.contains(21u32));
|
|
assert!(bitmap.contains(22u32));
|
|
assert!(!bitmap.contains(23u32));
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
// 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);
|
|
}
|