diff options
| author | Martin Haug <mhaug@live.de> | 2021-06-27 12:28:40 +0200 |
|---|---|---|
| committer | Martin Haug <mhaug@live.de> | 2021-06-27 12:31:27 +0200 |
| commit | 6b6cdae7ce95681d6a1194be70b375494166a8c6 (patch) | |
| tree | 2fe370798919ee0d1d411c6cacc5518a76094ecd /src/layout/incremental.rs | |
| parent | f64c772b6d969fa3aa1a7391a3d8118b21430434 (diff) | |
Testing for incremental
Also, constraint bugfixes.
Diffstat (limited to 'src/layout/incremental.rs')
| -rw-r--r-- | src/layout/incremental.rs | 155 |
1 files changed, 145 insertions, 10 deletions
diff --git a/src/layout/incremental.rs b/src/layout/incremental.rs index a5c3cea3..e1d1ffba 100644 --- a/src/layout/incremental.rs +++ b/src/layout/incremental.rs @@ -7,13 +7,15 @@ use super::*; pub struct LayoutCache { /// Maps from node hashes to the resulting frames and regions in which the /// frames are valid. - pub frames: HashMap<u64, FramesEntry>, + pub frames: HashMap<u64, Vec<FramesEntry>>, + /// In how many compilations this cache has been used. + age: usize, } impl LayoutCache { /// Create a new, empty layout cache. pub fn new() -> Self { - Self { frames: HashMap::new() } + Self { frames: HashMap::new(), age: 0 } } /// Clear the cache. @@ -26,12 +28,68 @@ impl LayoutCache { where F: FnMut(usize) -> bool, { - self.frames.retain(|_, entry| f(entry.level)); + for (_, hash_ident) in self.frames.iter_mut() { + hash_ident.retain(|entry| f(entry.level)); + } } /// Amount of items in the cache. pub fn len(&self) -> usize { - self.frames.len() + self.frames.iter().map(|(_, e)| e.len()).sum() + } + + /// Prepare the cache for the next round of compilation + pub fn turnaround(&mut self) { + self.age += 1; + for entry in self.frames.iter_mut().flat_map(|(_, x)| x.iter_mut()) { + for i in 0 .. (entry.temperature.len() - 1) { + entry.temperature[i] = entry.temperature[i + 1]; + } + *entry.temperature.last_mut().unwrap() = Some(0); + } + } + + /// What is the deepest level in the cache? + pub fn levels(&self) -> usize { + self.frames + .iter() + .flat_map(|(_, x)| x) + .map(|entry| entry.level + 1) + .max() + .unwrap_or(0) + } + + /// Fetches the appropriate entry from the cache if there is any. + pub fn get( + &mut self, + hash: u64, + regions: Regions, + ) -> Option<Vec<Constrained<Rc<Frame>>>> { + self.frames.get_mut(&hash).and_then(|frames| { + for frame in frames { + let res = frame.check(regions.clone()); + if res.is_some() { + return res; + } + } + + None + }) + } + + /// Inserts a new frame set into the cache. + pub fn insert( + &mut self, + hash: u64, + frames: Vec<Constrained<Rc<Frame>>>, + level: usize, + ) { + let entry = FramesEntry::new(frames, level); + if let Some(variants) = self.frames.get_mut(&hash) { + variants.push(entry); + } else { + self.frames.insert(hash, vec![entry]); + } } } @@ -42,19 +100,72 @@ pub struct FramesEntry { pub frames: Vec<Constrained<Rc<Frame>>>, /// How nested the frame was in the context is was originally appearing in. pub level: usize, + /// How much the element was accessed during the last five compilations, the + /// most current one being the last element. `None` variants indicate that + /// the element is younger than five compilations. + temperature: [Option<usize>; 5], } impl FramesEntry { + /// Construct a new instance. + pub fn new(frames: Vec<Constrained<Rc<Frame>>>, level: usize) -> Self { + let mut temperature = [None; 5]; + temperature[4] = Some(0); + Self { frames, level, temperature } + } + /// Checks if the cached [`Frame`] is valid for the given regions. - pub fn check(&self, mut regions: Regions) -> Option<Vec<Constrained<Rc<Frame>>>> { + pub fn check(&mut self, mut regions: Regions) -> Option<Vec<Constrained<Rc<Frame>>>> { for (i, frame) in self.frames.iter().enumerate() { if (i != 0 && !regions.next()) || !frame.constraints.check(®ions) { return None; } } + let tmp = self.temperature.get_mut(4).unwrap(); + *tmp = Some(tmp.map_or(1, |x| x + 1)); + Some(self.frames.clone()) } + + /// Get the amount of compilation cycles this item has remained in the + /// cache. + pub fn age(&self) -> usize { + let mut age = 0; + for &temp in self.temperature.iter().rev() { + if temp.is_none() { + break; + } + age += 1; + } + age + } + + /// Get the amount of consecutive cycles in which this item has not + /// been used. + pub fn cooldown(&self) -> usize { + let mut age = 0; + for (i, &temp) in self.temperature.iter().enumerate().rev() { + match temp { + Some(temp) => { + if temp > 0 { + return self.temperature.len() - 1 - i; + } + } + None => { + return age; + } + } + age += 1 + } + + age + } + + /// Whether this element was used in the last compilation cycle. + pub fn hit(&self) -> bool { + self.temperature.last().unwrap().unwrap_or(0) != 0 + } } #[derive(Debug, Copy, Clone, PartialEq)] @@ -107,15 +218,22 @@ impl Constraints { let base = regions.base.to_spec(); let current = regions.current.to_spec(); - current.eq_by(&self.min, |x, y| y.map_or(true, |y| x >= &y)) + let res = current.eq_by(&self.min, |&x, y| y.map_or(true, |y| x.fits(y))) && current.eq_by(&self.max, |x, y| y.map_or(true, |y| x < &y)) - && current.eq_by(&self.exact, |x, y| y.map_or(true, |y| x == &y)) - && base.eq_by(&self.base, |x, y| y.map_or(true, |y| x == &y)) + && current.eq_by(&self.exact, |&x, y| y.map_or(true, |y| x.approx_eq(y))) + && base.eq_by(&self.base, |&x, y| y.map_or(true, |y| x.approx_eq(y))); + + res } /// Changes all constraints by adding the argument to them if they are set. - pub fn mutate(&mut self, size: Size) { - for x in &mut [self.min, self.max, self.exact, self.base] { + pub fn mutate(&mut self, size: Size, regions: &Regions) { + for x in std::array::IntoIter::new([ + &mut self.min, + &mut self.max, + &mut self.exact, + &mut self.base, + ]) { if let Some(horizontal) = x.horizontal.as_mut() { *horizontal += size.width; } @@ -123,6 +241,23 @@ impl Constraints { *vertical += size.height; } } + + self.exact = zip(self.exact, regions.current.to_spec(), |_, o| o); + self.base = zip(self.base, regions.base.to_spec(), |_, o| o); + } +} + +fn zip<F>( + one: Spec<Option<Length>>, + other: Spec<Length>, + mut f: F, +) -> Spec<Option<Length>> +where + F: FnMut(Length, Length) -> Length, +{ + Spec { + vertical: one.vertical.map(|r| f(r, other.vertical)), + horizontal: one.horizontal.map(|r| f(r, other.horizontal)), } } |
