ghost-node/pallets/helpers/src/bounded_bitmap.rs
Uncle Stretch d83ee59508
let the EXODUS begin...
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2026-08-29 14:48:50 +03:00

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);
}