No more excessive region cloning

This commit is contained in:
Laurenz 2021-07-26 00:29:37 +02:00
parent 56cbf96fe2
commit 7aa3d2c2d6
4 changed files with 33 additions and 22 deletions

View File

@ -50,11 +50,11 @@ impl LayoutCache {
pub fn get(
&mut self,
hash: u64,
regions: Regions,
regions: &Regions,
) -> Option<Vec<Constrained<Rc<Frame>>>> {
let entries = self.frames.get_mut(&hash)?;
for entry in entries {
if let Some(frames) = entry.check(regions.clone()) {
if let Some(frames) = entry.check(regions) {
return Some(frames);
}
}
@ -136,9 +136,11 @@ impl FramesEntry {
/// Checks if the cached frames are valid in the given regions and returns
/// them if so.
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(&regions) {
pub fn check(&mut self, regions: &Regions) -> Option<Vec<Constrained<Rc<Frame>>>> {
let mut iter = regions.iter();
for frame in &self.frames {
let (current, base) = iter.next()?;
if !frame.constraints.check(current, base, regions.expand) {
return None;
}
}
@ -175,11 +177,13 @@ impl FramesEntry {
}
}
/// Carries an item that only applies to certain regions and the constraints
/// Carries an item that is only valid in certain regions and the constraints
/// that describe these regions.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct Constrained<T> {
/// The item that is only valid if the constraints are fullfilled.
pub item: T,
/// Constraints on regions in which the item is valid.
pub constraints: Constraints,
}
@ -218,16 +222,13 @@ impl Constraints {
}
}
#[cfg(feature = "layout-cache")]
fn check(&self, regions: &Regions) -> bool {
if self.expand != regions.expand {
return false;
}
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.fits(y)))
/// Check whether the constraints are fullfilled in a region with the given
/// properties.
pub fn check(&self, current: Size, base: Size, expand: Spec<bool>) -> bool {
let current = current.to_spec();
let base = base.to_spec();
self.expand == expand
&& 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.approx_eq(y)))
&& base.eq_by(&self.base, |x, y| y.map_or(true, |y| x.approx_eq(y)))

View File

@ -140,14 +140,21 @@ impl Regions {
self.backlog.is_empty() && self.last.map_or(true, |size| self.current == size)
}
/// An iterator that returns pairs of `(current, base)` that are equivalent
/// to what would be produced by calling [`next()`](Self::next) repeatedly
/// until all regions are exhausted.
pub fn iter(&self) -> impl Iterator<Item = (Size, Size)> + '_ {
let first = std::iter::once((self.current, self.base));
let backlog = self.backlog.iter().rev();
let last = self.last.iter().cycle();
first.chain(backlog.chain(last).map(|&s| (s, s)))
}
/// Advance to the next region if there is any.
pub fn next(&mut self) -> bool {
pub fn next(&mut self) {
if let Some(size) = self.backlog.pop().or(self.last) {
self.current = size;
self.base = size;
true
} else {
false
}
}

View File

@ -86,7 +86,7 @@ impl Layout for LayoutNode {
return self.node.layout(ctx, regions);
#[cfg(feature = "layout-cache")]
ctx.layouts.get(self.hash, regions.clone()).unwrap_or_else(|| {
ctx.layouts.get(self.hash, regions).unwrap_or_else(|| {
ctx.level += 1;
let frames = self.node.layout(ctx, regions);
ctx.level -= 1;

View File

@ -16,12 +16,15 @@ use typst::eval::{eval, Scope, Value};
use typst::exec::{exec, State};
use typst::geom::{self, Length, PathElement, Point, Sides, Size};
use typst::image::ImageId;
use typst::layout::{layout, Element, Frame, Geometry, LayoutTree, Paint, Text};
use typst::layout::{layout, Element, Frame, Geometry, Paint, Text};
use typst::loading::{FileId, FsLoader};
use typst::parse::{parse, LineMap, Scanner};
use typst::syntax::{Location, Pos};
use typst::Context;
#[cfg(feature = "layout-cache")]
use typst::layout::LayoutTree;
const TYP_DIR: &str = "./typ";
const REF_DIR: &str = "./ref";
const PNG_DIR: &str = "./png";