use std::any::Any; use std::borrow::Borrow; use std::marker::PhantomData; use std::ops::{BitAnd, BitOr, Mul}; use criterion::{black_box, Criterion, criterion_group, criterion_main}; use rand::{Rng, SeedableRng}; use hi_sparse_array::{apply, BitBlock, Empty, fold, SparseArray}; use hi_sparse_array::level_block::{Block, SmallBlock}; use hi_sparse_array::Iter; use hi_sparse_array::const_utils::{ConstFalse, ConstTrue}; use hi_sparse_array::level::{IntrusiveListLevel, SingleBlockLevel}; use hi_sparse_array::BinaryOp; use hi_sparse_array::compact_sparse_array2::CompactSparseArray; use hi_sparse_array::ops::union2::union2; use hi_sparse_array::ops::union::union; use hi_sparse_array::sparse_hierarchy::{SparseHierarchy, SparseHierarchyCursor}; use hi_sparse_array::utils::Take; type Lvl0Block = Block; type Lvl1Block = Block; type SmallLvl1Block = SmallBlock; /*type Lvl0Block = Block; type Lvl1Block = Block;*/ #[derive(Clone, Default)] struct DataBlock(u64); impl BitAnd for DataBlock{ type Output = Self; #[inline] fn bitand(self, rhs: Self) -> Self::Output { Self(self.0 & rhs.0) } } impl BitAnd for &DataBlock{ type Output = DataBlock; #[inline] fn bitand(self, rhs: Self) -> Self::Output { DataBlock(self.0 & rhs.0) } } impl BitOr for DataBlock{ type Output = Self; #[inline] fn bitor(self, rhs: Self) -> Self::Output { Self(self.0 | rhs.0) } } impl Empty for DataBlock{ fn empty() -> Self { Self(0) } fn is_empty(&self) -> bool { todo!() } } type BlockArray = SparseArray<(SingleBlockLevel, IntrusiveListLevel), /*IntrusiveListLevel<*/DataBlock/*>*/>; type SmallBlockArray = SparseArray<(SingleBlockLevel, IntrusiveListLevel), DataBlock>; type CompactArray = CompactSparseArray; pub struct AndOp(PhantomData<(M, LD)>); impl Default for AndOp{ fn default() -> Self { Self(PhantomData) } } impl BinaryOp for AndOp where M: BitBlock + BitAnd, LD: BitAnd + Empty, for<'a> &'a LD: BitAnd<&'a LD, Output = LD> { const EXACT_HIERARCHY: bool = true; type SKIP_EMPTY_HIERARCHIES = ConstTrue; type LevelMask = M; #[inline] fn lvl_op(&self, left: impl Take, right: impl Take) -> Self::LevelMask { left.take_or_clone() | right.take_or_clone() } type Left = LD; type Right = LD; type Out = LD; #[inline] fn data_op(&self, left: impl Borrow, right: impl Borrow) -> Self::Out { //left.into_owned() & right.into_owned() left.borrow() & right.borrow() } } /*pub struct OrOp(PhantomData<(L0, L1, L2, LD)>); impl Default for OrOp { fn default() -> Self { Self(PhantomData) } } impl Op for OrOp where L0: BitBlock + BitOr, L1: BitBlock + BitOr, L2: BitBlock + BitOr, LD: BitOr { const EXACT_HIERARCHY: bool = false; const SKIP_EMPTY_HIERARCHIES: bool = false; type Level0Mask = L0; #[inline] fn lvl0_op(&self, left: impl IntoOwned, right: impl IntoOwned) -> Self::Level0Mask { left.into_owned() | right.into_owned() } type Level1Mask = L1; #[inline] fn lvl1_op(&self, left: impl IntoOwned, right: impl IntoOwned) -> Self::Level1Mask { left.into_owned() | right.into_owned() } type Level2Mask = L2; #[inline] fn lvl2_op(&self, left: impl IntoOwned, right: impl IntoOwned) -> Self::Level2Mask { left.into_owned() | right.into_owned() } type DataBlock = LD; #[inline] fn data_op(&self, left: impl Borrow + IntoOwned, right: impl Borrow + IntoOwned) -> Self::DataBlock { left.into_owned() | right.into_owned() } } */ fn fold_iter(list: &[BlockArray]) -> impl Any { let op = AndOp(PhantomData); let init = unsafe{ list.get_unchecked(0) }; let other = unsafe{ list.get_unchecked(1..) }; let fold = fold(op, init, other.iter()); let mut s = 0; for (_, i) in Iter::new(&fold){ s += i.0; } s } /*fn fold_w_empty_iter(list: &[BlockArray]) -> u64 { let and_op: OrOp = OrOp(PhantomData); let empty = Empty::::default(); let fold = fold(and_op, &empty, list.iter()); let mut s = 0; for (_, i) in CachingBlockIter::new(&fold){ s += i.0; } s }*/ fn apply_small_iter(array1: &SmallBlockArray, array2: &SmallBlockArray) -> u64 { let and_op = AndOp(PhantomData); let reduce = apply(and_op, array1, array2); let mut s = 0; for (_, i) in Iter::new(&reduce){ s += i.0; } s } fn apply_iter(array1: &BlockArray, array2: &BlockArray) -> u64 { let and_op = AndOp(PhantomData); let reduce = apply(and_op, array1, array2); let mut s = 0; for (_, i) in Iter::new(&reduce){ s += i.0; } s } fn union2_iter(array1: &A1, array2: &A2) -> u64 where A1: SparseHierarchy, A2: SparseHierarchy { let union = union(array1, array2, |v0, v1|{ let v0 = v0.map_or(0, |v|v.0); let v1 = v1.map_or(0, |v|v.0); DataBlock(v0 + v1) }); let mut s = 0; for (_, i) in union.iter(){ s += i.0; } s } pub fn bench_iter(c: &mut Criterion) { let mut block_array1 = BlockArray::default(); let mut block_array2 = BlockArray::default(); let mut block_array3 = BlockArray::default(); let mut block_array4 = BlockArray::default(); let mut small_block_array1 = SmallBlockArray::default(); let mut small_block_array2 = SmallBlockArray::default(); let mut compact_array1 = CompactArray::default(); let mut compact_array2 = CompactArray::default(); let mut rng = rand::rngs::StdRng::seed_from_u64(0xe15bb9db3dee3a0f); for _ in 0..100{ let i1 = rng.gen_range(0..100); let i2 = rng.gen_range(0..100); let i3 = rng.gen_range(0..100); let i4 = rng.gen_range(0..100); *block_array1.get_mut(i1*20) = DataBlock(i1 as u64); *block_array2.get_mut(i2*20) = DataBlock(i2 as u64); *block_array3.get_mut(i3*20) = DataBlock(i3 as u64); *block_array4.get_mut(i4*20) = DataBlock(i4 as u64); *small_block_array1.get_mut(i1*20) = DataBlock(i1 as u64); *small_block_array2.get_mut(i2*20) = DataBlock(i2 as u64); *compact_array1.get_or_insert(i1*20) = DataBlock(i1 as u64); *compact_array2.get_or_insert(i2*20) = DataBlock(i2 as u64); } let arrays = [block_array1, block_array2/*, block_array3*/]; //c.bench_function("fold", |b| b.iter(|| fold_iter(black_box(&arrays)))); c.bench_function("apply", |b| b.iter(|| apply_iter(black_box(&arrays[0]), black_box(&arrays[1])))); c.bench_function("array union2", |b| b.iter(|| union2_iter(black_box(&arrays[0]), black_box(&arrays[1])))); //return; //c.bench_function("apply_small", |b| b.iter(|| apply_small_iter(black_box(&small_block_array1), black_box(&small_block_array2)))); c.bench_function("union2", |b| b.iter(|| union2_iter(black_box(&compact_array1), black_box(&compact_array2)))); //c.bench_function("fold_w_empty", |b| b.iter(|| fold_w_empty_iter(black_box(&arrays)))); } criterion_group!(benches_iter, bench_iter); criterion_main!(benches_iter);