use std::marker::PhantomData; use std::mem::MaybeUninit; use std::ops::ControlFlow; use crate::BitBlock; use crate::const_utils::{const_for_rev, ConstIntVisitor}; use crate::const_utils::const_int::{ConstUsize, ConstInteger}; use crate::level::ILevel; use crate::level_block::HiBlock; pub trait TypeVisitor { type Out; fn visit(self, _: PhantomData) -> Self::Out where L: ILevel, L::Block: HiBlock; } pub trait Visitor { type Out; fn visit(self, i: I, level: &L) -> Self::Out where L: ILevel, L::Block: HiBlock; } pub trait MutVisitor { type Out; fn visit(self, i: I, level: &mut L) -> Self::Out where L: ILevel, L::Block: HiBlock; } pub trait FoldVisitor { type Acc; fn visit(&mut self, i: I, level: &L, acc: Self::Acc) -> ControlFlow where L: ILevel, L::Block: HiBlock; } pub trait FoldMutVisitor { type Acc; fn visit(&mut self, i: I, level: &mut L, acc: Self::Acc) -> ControlFlow where L: ILevel, L::Block: HiBlock; } pub trait SparseTreeLevels: Default { type LevelCount: ConstInteger; type Mask: BitBlock; fn visit_type>(i: I, visitor: V) -> V::Out; fn visit>(&self, i: I, visitor: V) -> V::Out; fn visit_mut>(&mut self, i: I, visitor: V) -> V::Out; // TODO: remove all folds. We can use const_loop! now with visit/visit_type ? #[inline] fn fold(&self, acc: Acc, visitor: impl FoldVisitor) -> Acc{ self.fold_n(Self::LevelCount::DEFAULT, acc, visitor) } fn fold_mut(&mut self, acc: Acc, visitor: impl FoldMutVisitor) -> Acc; fn fold_rev_mut(&mut self, acc: Acc, visitor: impl FoldMutVisitor) -> Acc; /// fold first `n` tuple elements. fn fold_n(&self, n: impl ConstInteger, acc: Acc, visitor: impl FoldVisitor) -> Acc; } macro_rules! sparse_array_levels_impl { ($n:literal: [$($i:tt,)+] [$($rev_i:tt,)+]; $first_t:tt, $($t:tt,)* ) => { impl<$first_t, $($t,)*> SparseTreeLevels for ($first_t, $($t,)*) where $first_t: ILevel, $first_t::Block: HiBlock, $( $t: ILevel, $t::Block: HiBlock::Mask>, )* { type LevelCount = ConstUsize<$n>; type Mask = <$first_t::Block as HiBlock>::Mask; #[inline(always)] fn visit_type>(i: I, mut visitor: V) -> V::Out { let mut uninit: MaybeUninit = MaybeUninit::uninit(); let ptr = uninit.as_mut_ptr(); fn type_of(_: *mut T) -> PhantomData { PhantomData } match i.value() { $( $i => { let p = unsafe { std::ptr::addr_of_mut!((*ptr).$i) }; visitor.visit(type_of(p)) }, )+ _ => unreachable!() } } #[inline(always)] fn visit>(&self, i: I, mut visitor: V) -> V::Out { match i.value() { $( $i => visitor.visit(i, &self.$i), )+ _ => unreachable!() } } #[inline(always)] fn visit_mut>(&mut self, i: I, mut visitor: V) -> V::Out { match i.value() { $( $i => visitor.visit(i, &mut self.$i), )+ _ => unreachable!() } } #[inline(always)] fn fold_mut(&mut self, mut acc: Acc, mut visitor: impl FoldMutVisitor) -> Acc { $( match visitor.visit(ConstUsize::<$i>, &mut self.$i, acc) { ControlFlow::Break(v) => return v, ControlFlow::Continue(v) => acc = v, } )+ acc } #[inline(always)] fn fold_rev_mut(&mut self, mut acc: Acc, mut visitor: impl FoldMutVisitor) -> Acc { $( match visitor.visit(ConstUsize::<$rev_i>, &mut self.$rev_i, acc) { ControlFlow::Break(v) => return v, ControlFlow::Continue(v) => acc = v, } )+ acc } #[inline] fn fold_n(&self, n: impl ConstInteger, mut acc: Acc, mut visitor: impl FoldVisitor) -> Acc { $( /*const*/ if $i == n.value() { return acc; } match visitor.visit(ConstUsize::<$i>, &self.$i, acc) { ControlFlow::Break(v) => return v, ControlFlow::Continue(v) => acc = v, } )+ acc } } }; } sparse_array_levels_impl!(1: [0,] [0,]; L0,); sparse_array_levels_impl!(2: [0,1,] [1,0,]; L0,L1,); sparse_array_levels_impl!(3: [0,1,2,] [2,1,0,]; L0,L1,L2,); sparse_array_levels_impl!(4: [0,1,2,3,] [3,2,1,0,]; L0,L1,L2,L3,); sparse_array_levels_impl!(5: [0,1,2,3,4,] [4,3,2,1,0,]; L0,L1,L2,L3,L4,); sparse_array_levels_impl!(6: [0,1,2,3,4,5,] [5,4,3,2,1,0,]; L0,L1,L2,L3,L4,L5,); sparse_array_levels_impl!(7: [0,1,2,3,4,5,6,] [6,5,4,3,2,1,0,]; L0,L1,L2,L3,L4,L5,L6,); sparse_array_levels_impl!(8: [0,1,2,3,4,5,6,7,] [7,6,5,4,3,2,1,0,]; L0,L1,L2,L3,L4,L5,L6,L7,);