implement iteration with tags
authoralfadur
Tue, 03 Sep 2019 23:57:06 +0300
changeset 15397 b387a51705ac
parent 15396 7a3d70c364fd
child 15398 0ef770a40e75
implement iteration with tags
rust/hwphysics/src/data.rs
rust/hwphysics/src/physics.rs
--- a/rust/hwphysics/src/data.rs	Sun Sep 01 21:57:01 2019 +0200
+++ b/rust/hwphysics/src/data.rs	Tue Sep 03 23:57:06 2019 +0300
@@ -2,6 +2,7 @@
 use std::{
     any::TypeId,
     fmt::{Debug, Error, Formatter},
+    marker::PhantomData,
     mem::{size_of, MaybeUninit},
     num::NonZeroU16,
     ptr::{copy_nonoverlapping, null_mut, NonNull},
@@ -10,6 +11,19 @@
 
 pub trait TypeTuple: Sized {
     fn get_types(types: &mut Vec<TypeId>);
+}
+
+impl TypeTuple for () {
+    fn get_types(types: &mut Vec<TypeId>) {}
+}
+
+impl<T: 'static> TypeTuple for &T {
+    fn get_types(types: &mut Vec<TypeId>) {
+        types.push(TypeId::of::<T>());
+    }
+}
+
+pub trait TypeIter: TypeTuple {
     unsafe fn iter<F: FnMut(GearId, Self)>(slices: &[*mut u8], count: usize, f: F);
 }
 
@@ -19,7 +33,9 @@
             fn get_types(types: &mut Vec<TypeId>) {
                 $(types.push(TypeId::of::<$t>()));+
             }
+        }
 
+        impl<$($t: 'static),+> TypeIter for ($(&$t),+,) {
             unsafe fn iter<F: FnMut(GearId, Self)>(slices: &[*mut u8], count: usize, mut f: F) {
                 for i in 0..count {
                     f(*(*slices.get_unchecked(0) as *const GearId).add(i),
@@ -32,7 +48,9 @@
             fn get_types(types: &mut Vec<TypeId>) {
                 $(types.push(TypeId::of::<$t>()));+
             }
+        }
 
+        impl<$($t: 'static),+> TypeIter for ($(&mut $t),+,) {
             unsafe fn iter<F: FnMut(GearId, Self)>(slices: &[*mut u8], count: usize, mut f: F) {
                 for i in 0..count {
                     f(*(*slices.get_unchecked(0) as *const GearId).add(i),
@@ -444,32 +462,19 @@
         }
     }
 
-    #[inline]
-    pub fn iter<T: TypeTuple + 'static, F: FnMut(T)>(&mut self, mut f: F) {
-        self.iter_id(|_, x| f(x));
-    }
-
-    pub fn iter_id<T: TypeTuple + 'static, F: FnMut(GearId, T)>(&mut self, mut f: F) {
-        let mut arg_types = Vec::with_capacity(64);
-        T::get_types(&mut arg_types);
-
-        let mut type_indices = vec![-1i8; arg_types.len()];
-        let mut selector = 0u64;
-
-        for (arg_index, type_id) in arg_types.iter().enumerate() {
-            match self.types.iter().position(|t| t == type_id) {
-                Some(i) if selector & (1 << i as u64) != 0 => panic!("Duplicate type"),
-                Some(i) => {
-                    type_indices[arg_index] = i as i8;
-                    selector |= 1 << i as u64;
-                }
-                None => panic!("Unregistered type"),
-            }
-        }
-        let mut slices = vec![null_mut(); arg_types.len() + 1];
+    fn run_impl<T: TypeIter + 'static, F: FnMut(GearId, T)>(
+        &mut self,
+        type_selector: u64,
+        included_tags: u64,
+        type_indices: &[i8],
+        mut f: F,
+    ) {
+        let mut slices = vec![null_mut(); type_indices.len() + 1];
 
         for (block_index, mask) in self.block_masks.iter().enumerate() {
-            if mask.type_mask & selector == selector {
+            if mask.type_mask & type_selector == type_selector
+                && mask.tag_mask & included_tags == included_tags
+            {
                 let block = &mut self.blocks[block_index];
                 slices[0] = block.data.as_mut_ptr();
 
@@ -485,6 +490,73 @@
             }
         }
     }
+
+    pub fn iter<T: TypeIter + 'static>(&mut self) -> DataIterator<T> {
+        let mut arg_types = Vec::with_capacity(64);
+        T::get_types(&mut arg_types);
+        let mut type_indices = vec![-1i8; arg_types.len()];
+        let mut selector = 0u64;
+
+        for (arg_index, type_id) in arg_types.iter().enumerate() {
+            match self.types.iter().position(|t| t == type_id) {
+                Some(i) if selector & (1 << i as u64) != 0 => panic!("Duplicate type"),
+                Some(i) => {
+                    type_indices[arg_index] = i as i8;
+                    selector |= 1 << i as u64;
+                }
+                None => panic!("Unregistered type"),
+            }
+        }
+        DataIterator::new(self, selector, type_indices)
+    }
+}
+
+pub struct DataIterator<'a, T> {
+    data: &'a mut GearDataManager,
+    types: u64,
+    type_indices: Vec<i8>,
+    tags: u64,
+    phantom_types: PhantomData<T>,
+}
+
+impl<'a, T: TypeIter + 'static> DataIterator<'a, T> {
+    fn new(
+        data: &'a mut GearDataManager,
+        types: u64,
+        type_indices: Vec<i8>,
+    ) -> DataIterator<'a, T> {
+        Self {
+            data,
+            types,
+            type_indices,
+            tags: 0,
+            phantom_types: PhantomData,
+        }
+    }
+
+    pub fn with_tags<U: TypeTuple + 'static>(self) -> Self {
+        let mut tag_types = Vec::with_capacity(64);
+        U::get_types(&mut tag_types);
+        let mut tags = 0;
+
+        for (i, tag) in self.data.tags.iter().enumerate() {
+            if tag_types.contains(tag) {
+                tags |= 1 << i as u64;
+            }
+        }
+        Self { tags, ..self }
+    }
+
+    #[inline]
+    pub fn run<F: FnMut(T)>(&mut self, mut f: F) {
+        self.run_id(|_, x| f(x))
+    }
+
+    #[inline]
+    pub fn run_id<F: FnMut(GearId, T)>(&mut self, f: F) {
+        self.data
+            .run_impl(self.types, self.tags, &self.type_indices, f);
+    }
 }
 
 #[cfg(test)]
@@ -497,9 +569,7 @@
     }
 
     #[derive(Clone)]
-    struct Tag {
-        nothing: u8,
-    }
+    struct Tag;
 
     #[test]
     fn single_component_iteration() {
@@ -510,16 +580,16 @@
         }
 
         let mut sum = 0;
-        manager.iter(|(d,): (&Datum,)| sum += d.value);
+        manager.iter().run(|(d,): (&Datum,)| sum += d.value);
         assert_eq!(sum, 15);
 
-        manager.iter(|(d,): (&mut Datum,)| d.value += 1);
-        manager.iter(|(d,): (&Datum,)| sum += d.value);
+        manager.iter().run(|(d,): (&mut Datum,)| d.value += 1);
+        manager.iter().run(|(d,): (&Datum,)| sum += d.value);
         assert_eq!(sum, 35);
     }
 
     #[test]
-    fn multiple_component_iteration() {
+    fn tagged_component_iteration() {
         let mut manager = GearDataManager::new();
         manager.register::<Datum>();
         manager.register::<Tag>();
@@ -531,19 +601,19 @@
         for i in 1..=10 {
             let gear_id = GearId::new(i as u16).unwrap();
             if i & 1 == 0 {
-                manager.add(GearId::new(i as u16).unwrap(), &Tag { nothing: 0 });
+                manager.add_tag::<Tag>(gear_id);
             }
         }
 
         let mut sum = 0;
-        manager.iter(|(d,): (&Datum,)| sum += d.value);
+        manager.iter().run(|(d,): (&Datum,)| sum += d.value);
         assert_eq!(sum, 55);
 
-        let mut tag_sum1 = 0;
-        let mut tag_sum2 = 0;
-        manager.iter(|(d, _): (&Datum, &Tag)| tag_sum1 += d.value);
-        manager.iter(|(_, d): (&Tag, &Datum)| tag_sum2 += d.value);
-        assert_eq!(tag_sum1, 30);
-        assert_eq!(tag_sum2, tag_sum1);
+        let mut tag_sum = 0;
+        manager
+            .iter()
+            .with_tags::<&Tag>()
+            .run(|(d,): (&Datum,)| tag_sum += d.value);
+        assert_eq!(tag_sum, 30);
     }
 }
--- a/rust/hwphysics/src/physics.rs	Sun Sep 01 21:57:01 2019 +0200
+++ b/rust/hwphysics/src/physics.rs	Tue Sep 03 23:57:06 2019 +0300
@@ -65,7 +65,7 @@
     pub fn process_single_tick(&mut self, data: &mut GearDataManager) -> &PositionUpdates {
         self.position_updates.clear();
 
-        data.iter_id(
+        data.iter().run_id(
             |gear_id, (pos, vel): (&mut PositionData, &mut VelocityData)| {
                 let old_pos = pos.0;
                 vel.0 -= self.gravity;
@@ -85,7 +85,7 @@
         let fp_step = time_step.to_fixed();
         self.position_updates.clear();
 
-        data.iter_id(
+        data.iter().run_id(
             |gear_id, (pos, vel): (&mut PositionData, &mut VelocityData)| {
                 let old_pos = pos.0;
                 vel.0 -= self.gravity * fp_step;