gioser

tawasuyu/taffy

A high performance rust-powered UI layout library

HTML 231Rust 10TOML 3CSS 1348 Definiciones

Specialize cache for perform_layout and run_mode steps (#579)

70b35712a2e79b6fdfef4cff4392ca94287cd0b1 · por Nico Burns · (hace 2 años) · padre 1876f72be · ver el árbol en este commit

Delta semántico · 10

src/tree/cache.rs

tests/caching.rs

2 archivos · +59 −37

diff --git a/src/tree/cache.rs b/src/tree/cache.rs
index 2cda0d415..3909a908a 100644
--- a/src/tree/cache.rs
+++ b/src/tree/cache.rs
@@ -8,28 +8,27 @@ const CACHE_SIZE: usize = 9;
 
 /// Cached intermediate layout results
 #[derive(Debug, Clone, Copy)]
-pub(crate) struct CacheEntry {
+pub(crate) struct CacheEntry<T> {
     /// The initial cached size of the node itself
     known_dimensions: Size<Option<f32>>,
     /// The initial cached size of the parent's node
     available_space: Size<AvailableSpace>,
-    /// Whether or not layout should be recomputed
-    run_mode: RunMode,
-
     /// The cached size and baselines of the item
-    cached_size_and_baselines: LayoutOutput,
+    content: T,
 }
 
 /// A cache for caching the results of a sizing a Grid Item or Flexbox Item
 pub struct Cache {
-    /// An array of entries in the cache
-    entries: [Option<CacheEntry>; CACHE_SIZE],
+    /// The cache entry for the node's final layout
+    final_layout_entry: Option<CacheEntry<LayoutOutput>>,
+    /// The cache entries for the node's preliminary size measurements
+    measure_entries: [Option<CacheEntry<Size<f32>>>; CACHE_SIZE],
 }
 
 impl Cache {
     /// Create a new empty cache
     pub const fn new() -> Self {
-        Self { entries: [None; CACHE_SIZE] }
+        Self { final_layout_entry: None, measure_entries: [None; CACHE_SIZE] }
     }
 
     /// Return the cache slot to cache the current computed result in
@@ -79,7 +78,7 @@ impl Cache {
 
         // Slot 3: height but not width known_dimension was set and the other dimension was either a MaxContent or Definite available space constraint
         // Slot 4: height but not width known_dimension was set and the other dimension was a MinContent constraint
-        if !has_known_width && has_known_height {
+        if has_known_height && !has_known_width {
             return 3 + (available_space.width == MinContent) as usize;
         }
 
@@ -104,28 +103,42 @@ impl Cache {
         available_space: Size<AvailableSpace>,
         run_mode: RunMode,
     ) -> Option<LayoutOutput> {
-        for entry in self.entries.iter().flatten() {
-            // Cached ComputeSize results are not valid if we are running in PerformLayout mode
-            if entry.run_mode == RunMode::ComputeSize && run_mode == RunMode::PerformLayout {
-                return None;
-            }
-
-            let cached_size = entry.cached_size_and_baselines.size;
-
-            if (known_dimensions.width == entry.known_dimensions.width
-                || known_dimensions.width == Some(cached_size.width))
-                && (known_dimensions.height == entry.known_dimensions.height
-                    || known_dimensions.height == Some(cached_size.height))
-                && (known_dimensions.width.is_some()
-                    || entry.available_space.width.is_roughly_equal(available_space.width))
-                && (known_dimensions.height.is_some()
-                    || entry.available_space.height.is_roughly_equal(available_space.height))
-            {
-                return Some(entry.cached_size_and_baselines);
+        match run_mode {
+            RunMode::PerformLayout => self
+                .final_layout_entry
+                .filter(|entry| {
+                    let cached_size = entry.content.size;
+                    (known_dimensions.width == entry.known_dimensions.width
+                        || known_dimensions.width == Some(cached_size.width))
+                        && (known_dimensions.height == entry.known_dimensions.height
+                            || known_dimensions.height == Some(cached_size.height))
+                        && (known_dimensions.width.is_some()
+                            || entry.available_space.width.is_roughly_equal(available_space.width))
+                        && (known_dimensions.height.is_some()
+                            || entry.available_space.height.is_roughly_equal(available_space.height))
+                })
+                .map(|e| e.content),
+            RunMode::ComputeSize => {
+                for entry in self.measure_entries.iter().flatten() {
+                    let cached_size = entry.content;
+
+                    if (known_dimensions.width == entry.known_dimensions.width
+                        || known_dimensions.width == Some(cached_size.width))
+                        && (known_dimensions.height == entry.known_dimensions.height
+                            || known_dimensions.height == Some(cached_size.height))
+                        && (known_dimensions.width.is_some()
+                            || entry.available_space.width.is_roughly_equal(available_space.width))
+                        && (known_dimensions.height.is_some()
+                            || entry.available_space.height.is_roughly_equal(available_space.height))
+                    {
+                        return Some(LayoutOutput::from(cached_size));
+                    }
+                }
+
+                None
             }
+            RunMode::PerformHiddenLayout => None,
         }
-
-        None
     }
 
     /// Store a computed size in the cache
@@ -134,20 +147,29 @@ impl Cache {
         known_dimensions: Size<Option<f32>>,
         available_space: Size<AvailableSpace>,
         run_mode: RunMode,
-        cached_size_and_baselines: LayoutOutput,
+        layout_output: LayoutOutput,
     ) {
-        let cache_slot = Self::compute_cache_slot(known_dimensions, available_space);
-        self.entries[cache_slot] =
-            Some(CacheEntry { known_dimensions, available_space, run_mode, cached_size_and_baselines });
+        match run_mode {
+            RunMode::PerformLayout => {
+                self.final_layout_entry = Some(CacheEntry { known_dimensions, available_space, content: layout_output })
+            }
+            RunMode::ComputeSize => {
+                let cache_slot = Self::compute_cache_slot(known_dimensions, available_space);
+                self.measure_entries[cache_slot] =
+                    Some(CacheEntry { known_dimensions, available_space, content: layout_output.size });
+            }
+            RunMode::PerformHiddenLayout => {}
+        }
     }
 
     /// Clear all cache entries
     pub fn clear(&mut self) {
-        self.entries = [None; CACHE_SIZE];
+        self.final_layout_entry = None;
+        self.measure_entries = [None; CACHE_SIZE];
     }
 
     /// Returns true if all cache entries are None, else false
     pub fn is_empty(&self) -> bool {
-        !self.entries.iter().any(|entry| entry.is_some())
+        self.final_layout_entry.is_none() && !self.measure_entries.iter().any(|entry| entry.is_some())
     }
 }
diff --git a/tests/caching.rs b/tests/caching.rs
index 3aba08159..4275388bb 100644
--- a/tests/caching.rs
+++ b/tests/caching.rs
@@ -34,7 +34,7 @@ mod caching {
 
         taffy.compute_layout_with_measure(node, Size::MAX_CONTENT, count_measure_function).unwrap();
 
-        assert_eq!(taffy.get_node_context_mut(leaf).unwrap().count, 3);
+        assert_eq!(taffy.get_node_context_mut(leaf).unwrap().count, 8);
     }
 
     #[test]
@@ -51,6 +51,6 @@ mod caching {
         }
 
         taffy.compute_layout_with_measure(node, Size::MAX_CONTENT, count_measure_function).unwrap();
-        assert_eq!(taffy.get_node_context_mut(leaf).unwrap().count, 3);
+        assert_eq!(taffy.get_node_context_mut(leaf).unwrap().count, 8);
     }
 }