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

View File

@ -86,7 +86,7 @@ impl Layout for LayoutNode {
return self.node.layout(ctx, regions); return self.node.layout(ctx, regions);
#[cfg(feature = "layout-cache")] #[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; ctx.level += 1;
let frames = self.node.layout(ctx, regions); let frames = self.node.layout(ctx, regions);
ctx.level -= 1; ctx.level -= 1;

View File

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