diff --git a/src/runtime/ecs.rs b/src/runtime/ecs.rs new file mode 100644 index 0000000000000000000000000000000000000000..90f0a55acb749ebc0015634fe548eeee0c7daa57 --- /dev/null +++ b/src/runtime/ecs.rs @@ -0,0 +1,187 @@ +use crate::common::*; +use crate::runtime::ProtocolS; + +use std::collections::HashMap; + +/// invariant: last element is not zero. +/// => all values out of bounds are implicitly absent. +/// i.e., &[0,1] means {1<<32, 0} while &[0,1] is identical to &[1] and means {1}. + +#[derive(Debug, Default)] +struct BitSet(Vec); +impl BitSet { + #[inline(always)] + fn index_decomposed(index: usize) -> [usize; 2] { + // [chunk_index, chunk_bit] + [index / 32, index % 32] + } + fn set(&mut self, at: usize) { + let [chunk_index, chunk_bit] = Self::index_decomposed(at); + if chunk_index >= self.0.len() { + self.0.resize(chunk_index + 1, 0u32); + } + let chunk = unsafe { + // SAFE! previous line ensures sufficient size + self.0.get_unchecked_mut(chunk_index) + }; + *chunk |= 1 << chunk_bit; + } + fn unset(&mut self, at: usize) { + let [chunk_index, chunk_bit] = Self::index_decomposed(at); + if chunk_index < self.0.len() { + let chunk = unsafe { + // SAFE! previous line ensures sufficient size + self.0.get_unchecked_mut(chunk_index) + }; + *chunk &= !(1 << chunk_bit); + while let Some(0u32) = self.0.iter().copied().last() { + self.0.pop(); + } + } + } +} + +#[derive(Debug, Default)] +struct BitMasks(HashMap<(ChannelId, bool), BitSet>); + +struct BitChunkIter> { + chunk_iter: I, + next_bit_index: usize, + cached: Option, // None <=> iterator is done +} + +impl> BitChunkIter { + fn new(mut chunk_iter: I) -> Self { + let cached = chunk_iter.next(); + Self { chunk_iter, next_bit_index: 0, cached } + } +} +impl> Iterator for BitChunkIter { + type Item = usize; + fn next(&mut self) -> Option { + loop { + println!("LOOP"); + // get cached chunk. If none exists, iterator is done. + let mut chunk = self.cached?; + if chunk == 0 { + // self.next_bit_index jumps to next multiple of 32 + self.next_bit_index = (self.next_bit_index + 32) & !(32 - 1); + self.cached = self.chunk_iter.next(); + continue; + } + // this chunk encodes 1+ Items to yield + // shift the contents of chunk until the least significant bit is 1 + + #[inline(always)] + fn shifty(chunk: &mut u32, shift_by: usize, next_bit_index: &mut usize) { + if *chunk & ((1 << shift_by) - 1) == 0 { + *next_bit_index += shift_by; + *chunk >>= shift_by; + } + println!("{:#032b}", *chunk); + } + shifty(&mut chunk, 16, &mut self.next_bit_index); + shifty(&mut chunk, 08, &mut self.next_bit_index); + shifty(&mut chunk, 04, &mut self.next_bit_index); + shifty(&mut chunk, 02, &mut self.next_bit_index); + shifty(&mut chunk, 01, &mut self.next_bit_index); + // assert(chunk & 1 == 1) + + self.next_bit_index += 1; + self.cached = Some(chunk >> 1); + if chunk > 0 { + return Some(self.next_bit_index - 1); + } + } + } +} + +/// Returns an iterator over chunks of bits where ALL of the given +/// bitsets have 1. +struct AndChunkIter<'a> { + // this value is not overwritten during iteration + // invariant: !sets.is_empty() + sets: &'a [&'a [u32]], + + next_chunk_index: usize, +} +impl<'a> AndChunkIter<'a> { + fn new(sets: &'a [&'a [u32]]) -> Self { + let sets = if sets.is_empty() { &[&[] as &[_]] } else { sets }; + Self { sets, next_chunk_index: 0 } + } +} +impl Iterator for AndChunkIter<'_> { + type Item = u32; + fn next(&mut self) -> Option { + let old_chunk_index = self.next_chunk_index; + self.next_chunk_index += 1; + self.sets.iter().fold(Some(!0u32), move |a, b| { + let a = a?; + let b = *b.get(old_chunk_index)?; + Some(a & b) + }) + } +} + +/// Returns an iterator over chunks for bits in range 0..bits_to_go but skipping +/// indices for which ANY of the given bitsets has a 1 +struct NoneChunkIter<'a> { + // this value is not overwritten during iteration + // invariant: !sets.is_empty() + sets: &'a [&'a [u32]], + next_chunk_index: usize, + bits_to_go: usize, +} +impl<'a> NoneChunkIter<'a> { + /// a set of bitsets. the u32s of each are in ascending order of significant digits + /// i.e., &[0,1] means {1<<32, 0} while &[0,1] is identical to &[1] and means {1}. + fn new(sets: &'a [&'a [u32]], max_bit: usize) -> Self { + let sets = if sets.is_empty() { &[&[] as &[_]] } else { sets }; + Self { sets, next_chunk_index: 0, bits_to_go: max_bit } + } +} +impl Iterator for NoneChunkIter<'_> { + type Item = u32; + fn next(&mut self) -> Option { + let neutral = match self.bits_to_go { + 0 => None, + x @ 1..=31 => Some(!0u32 >> (32 - x)), + _ => Some(!0u32), + }; + self.bits_to_go = self.bits_to_go.saturating_sub(32); + + let old_chunk_index = self.next_chunk_index; + self.next_chunk_index += 1; + + self.sets.iter().fold(neutral, move |a, b| { + let a = a?; + let b = *b.get(old_chunk_index)?; + Some(a & !b) + }) + } +} + +#[test] +fn test_bit_iter() { + static SETS: &[&[u32]] = &[ + // + &[0b101001, 0b101001], + &[0b100001, 0b101001], + ]; + let _ = BitChunkIter::new(AndChunkIter::new(SETS)); + let iter = BitChunkIter::new(NoneChunkIter::new(SETS, 9)); + let indices = iter.collect::>(); + println!("indices {:?}", indices); +} + +enum Entity { + Payload(Payload), + State(ProtocolS), +} + +fn ecs() { + let entities: Vec = Default::default(); + let assignments: HashMap<(ChannelId, bool), BitSet> = Default::default(); + let to_run: BitSet = Default::default(); +}