fix component removal
authoralfadur
Sun, 26 Mar 2023 06:06:14 +0300
changeset 15942 bcd43b90401a
parent 15941 8035f7452b48
child 15943 feb7a76915d2
fix component removal
rust/hwphysics/src/data.rs
--- a/rust/hwphysics/src/data.rs	Sun Mar 26 03:53:49 2023 +0300
+++ b/rust/hwphysics/src/data.rs	Sun Mar 26 06:06:14 2023 +0300
@@ -224,6 +224,11 @@
     }
 
     #[inline]
+    fn without_type(&self, type_bit: u64) -> Self {
+        Self::new(self.type_mask & !type_bit, self.tag_mask)
+    }
+
+    #[inline]
     fn with_tag(&self, tag_bit: u64) -> Self {
         Self::new(self.type_mask, self.tag_mask | tag_bit)
     }
@@ -273,7 +278,7 @@
         debug_assert!(src_block_index != dest_block_index);
         let src_mask = self.block_masks[src_block_index as usize];
         let dest_mask = self.block_masks[dest_block_index as usize];
-        debug_assert!(src_mask.type_mask & dest_mask.type_mask == src_mask.type_mask);
+        debug_assert!(src_mask.type_mask & dest_mask.type_mask != 0);
 
         let src_block = &self.blocks[src_block_index as usize];
         let dest_block = &self.blocks[dest_block_index as usize];
@@ -288,13 +293,17 @@
 
             let size = self.element_sizes[i];
             let src_ptr = src_block.component_blocks[i].unwrap().as_ptr();
-            let dest_ptr = dest_block.component_blocks[i].unwrap().as_ptr();
+            if let Some(dest_ptr) = dest_block.component_blocks[i] {
+                let dest_ptr = dest_ptr.as_ptr();
+                unsafe {
+                    copy_nonoverlapping(
+                        src_ptr.add((src_index * size) as usize),
+                        dest_ptr.add((dest_index * size) as usize),
+                        size as usize,
+                    );
+                }
+            }
             unsafe {
-                copy_nonoverlapping(
-                    src_ptr.add((src_index * size) as usize),
-                    dest_ptr.add((dest_index * size) as usize),
-                    size as usize,
-                );
                 if src_index < src_block.elements_count - 1 {
                     copy_nonoverlapping(
                         src_ptr.add((size * (src_block.elements_count - 1)) as usize),
@@ -310,7 +319,7 @@
         let src_block = &mut self.blocks[src_block_index as usize];
         let gear_id = src_block.gear_ids()[src_index as usize];
 
-        if src_index < src_block.elements_count - 1 {
+        if src_index + 1 < src_block.elements_count {
             let relocated_index = src_block.elements_count as usize - 1;
             let gear_ids = src_block.gear_ids_mut();
             let relocated_id = gear_ids[relocated_index];
@@ -470,16 +479,24 @@
 
     pub fn remove<T: 'static>(&mut self, gear_id: GearId) {
         if let Some(type_index) = self.get_type_index::<T>() {
+            let type_bit = 1 << type_index as u64;
             let entry = self.lookup[gear_id.get() as usize - 1];
+
             if let Some(index) = entry.index {
-                let mut dest_mask = self.block_masks[entry.block_index as usize];
-                dest_mask.type_mask &= !(1 << type_index as u64);
+                let mask = self.block_masks[entry.block_index as usize];
+                let new_mask = mask.without_type(type_bit);
 
-                if dest_mask.type_mask == 0 {
-                    self.remove_from_block(entry.block_index, index.get() - 1);
-                } else {
-                    let dest_block_index = self.ensure_block(dest_mask);
-                    self.move_between_blocks(entry.block_index, index.get() - 1, dest_block_index);
+                if new_mask != mask {
+                    if new_mask.type_mask == 0 {
+                        self.remove_from_block(entry.block_index, index.get() - 1);
+                    } else {
+                        let dest_block_index = self.ensure_block(new_mask);
+                        self.move_between_blocks(
+                            entry.block_index,
+                            index.get() - 1,
+                            dest_block_index,
+                        );
+                    }
                 }
             }
         } else {
@@ -629,7 +646,12 @@
     use super::{super::common::GearId, GearDataManager};
 
     #[derive(Clone)]
-    struct Datum {
+    struct DatumA {
+        value: u32,
+    }
+
+    #[derive(Clone)]
+    struct DatumB {
         value: u32,
     }
 
@@ -639,15 +661,15 @@
     #[test]
     fn direct_access() {
         let mut manager = GearDataManager::new();
-        manager.register::<Datum>();
+        manager.register::<DatumA>();
         for i in 1..=5 {
-            manager.add(GearId::new(i as u16).unwrap(), &Datum { value: i * i });
+            manager.add(GearId::new(i as u16).unwrap(), &DatumA { value: i * i });
         }
 
         for i in 1..=5 {
             assert_eq!(
                 manager
-                    .get::<Datum>(GearId::new(i as u16).unwrap())
+                    .get::<DatumA>(GearId::new(i as u16).unwrap())
                     .unwrap()
                     .value,
                 i * i
@@ -658,46 +680,72 @@
     #[test]
     fn single_component_iteration() {
         let mut manager = GearDataManager::new();
-        manager.register::<Datum>();
+        manager.register::<DatumA>();
+
         for i in 1..=5 {
-            manager.add(GearId::new(i as u16).unwrap(), &Datum { value: i });
+            manager.add(GearId::new(i as u16).unwrap(), &DatumA { value: i });
         }
 
         let mut sum = 0;
-        manager.iter().run(|(d,): (&Datum,)| sum += d.value);
+        manager.iter().run(|(d,): (&DatumA,)| sum += d.value);
         assert_eq!(sum, 15);
 
-        manager.iter().run(|(d,): (&mut Datum,)| d.value += 1);
-        manager.iter().run(|(d,): (&Datum,)| sum += d.value);
+        manager.iter().run(|(d,): (&mut DatumA,)| d.value += 1);
+        manager.iter().run(|(d,): (&DatumA,)| sum += d.value);
         assert_eq!(sum, 35);
     }
 
     #[test]
     fn tagged_component_iteration() {
         let mut manager = GearDataManager::new();
-        manager.register::<Datum>();
+        manager.register::<DatumA>();
         manager.register::<Tag>();
-        for i in 1..=10 {
-            let gear_id = GearId::new(i as u16).unwrap();
-            manager.add(gear_id, &Datum { value: i });
-        }
 
         for i in 1..=10 {
             let gear_id = GearId::new(i as u16).unwrap();
-            if i & 1 == 0 {
-                manager.add_tag::<Tag>(gear_id);
-            }
+            manager.add(gear_id, &DatumA { value: i });
+        }
+
+        for i in (2..=10).step_by(2) {
+            let gear_id = GearId::new(i as u16).unwrap();
+            manager.add_tag::<Tag>(gear_id);
         }
 
         let mut sum = 0;
-        manager.iter().run(|(d,): (&Datum,)| sum += d.value);
+        manager.iter().run(|(d,): (&DatumA,)| sum += d.value);
         assert_eq!(sum, 55);
 
         let mut tag_sum = 0;
         manager
             .iter()
             .with_tags::<&Tag>()
-            .run(|(d,): (&Datum,)| tag_sum += d.value);
+            .run(|(d,): (&DatumA,)| tag_sum += d.value);
         assert_eq!(tag_sum, 30);
     }
+
+    #[test]
+    fn removal() {
+        let mut manager = GearDataManager::new();
+        manager.register::<DatumA>();
+        manager.register::<DatumB>();
+
+        for i in 1..=10 {
+            let gear_id = GearId::new(i as u16).unwrap();
+            manager.add(gear_id, &DatumA { value: i });
+            manager.add(gear_id, &DatumB { value: i });
+        }
+
+        for i in (1..=10).step_by(2) {
+            let gear_id = GearId::new(i as u16).unwrap();
+            manager.remove::<DatumA>(gear_id);
+        }
+
+        let mut sum_a = 0;
+        manager.iter().run(|(d,): (&DatumA,)| sum_a += d.value);
+        assert_eq!(sum_a, 30);
+
+        let mut sum_b = 0;
+        manager.iter().run(|(d,): (&DatumB,)| sum_b += d.value);
+        assert_eq!(sum_b, 55);
+    }
 }