gpui: Optimize the ordering update in the BoundsTree (#31025)

laizy created

Release Notes:

- N/A

Change summary

crates/gpui/src/bounds_tree.rs | 44 ++++++++++++++++++++++++++++++++++-
1 file changed, 42 insertions(+), 2 deletions(-)

Detailed changes

crates/gpui/src/bounds_tree.rs 🔗

@@ -111,7 +111,7 @@ where
             self.root = Some(new_parent);
         }
 
-        for node_index in self.stack.drain(..) {
+        for node_index in self.stack.drain(..).rev() {
             let Node::Internal {
                 max_order: max_ordering,
                 ..
@@ -119,7 +119,10 @@ where
             else {
                 unreachable!()
             };
-            *max_ordering = cmp::max(*max_ordering, ordering);
+            if *max_ordering >= ordering {
+                break;
+            }
+            *max_ordering = ordering;
         }
 
         ordering
@@ -237,6 +240,7 @@ where
 mod tests {
     use super::*;
     use crate::{Bounds, Point, Size};
+    use rand::{Rng, SeedableRng};
 
     #[test]
     fn test_insert() {
@@ -294,4 +298,40 @@ mod tests {
         assert_eq!(tree.insert(bounds5), 1); // bounds5 does not overlap with any other bounds
         assert_eq!(tree.insert(bounds6), 2); // bounds6 overlaps with bounds4, so it should have a different order
     }
+
+    #[test]
+    fn test_random_iterations() {
+        let max_bounds = 100;
+        for seed in 1..=1000 {
+            // let seed = 44;
+            let mut tree = BoundsTree::default();
+            let mut rng = rand::rngs::StdRng::seed_from_u64(seed as u64);
+            let mut expected_quads: Vec<(Bounds<f32>, u32)> = Vec::new();
+
+            // Insert a random number of random AABBs into the tree.
+            let num_bounds = rng.gen_range(1..=max_bounds);
+            for _ in 0..num_bounds {
+                let min_x: f32 = rng.gen_range(-100.0..100.0);
+                let min_y: f32 = rng.gen_range(-100.0..100.0);
+                let width: f32 = rng.gen_range(0.0..50.0);
+                let height: f32 = rng.gen_range(0.0..50.0);
+                let bounds = Bounds {
+                    origin: Point { x: min_x, y: min_y },
+                    size: Size { width, height },
+                };
+
+                let expected_ordering = expected_quads
+                    .iter()
+                    .filter_map(|quad| quad.0.intersects(&bounds).then_some(quad.1))
+                    .max()
+                    .unwrap_or(0)
+                    + 1;
+                expected_quads.push((bounds, expected_ordering));
+
+                // Insert the AABB into the tree and collect intersections.
+                let actual_ordering = tree.insert(bounds);
+                assert_eq!(actual_ordering, expected_ordering);
+            }
+        }
+    }
 }