Better block caching (#5046)

This commit is contained in:
Laurenz 2024-09-27 10:24:59 +02:00 committed by GitHub
parent 839983a0a7
commit 01af4308d3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 93 additions and 17 deletions

View File

@ -4,12 +4,15 @@ use std::hash::Hash;
use bumpalo::boxed::Box as BumpBox; use bumpalo::boxed::Box as BumpBox;
use bumpalo::Bump; use bumpalo::Bump;
use comemo::{Track, Tracked, TrackedMut};
use once_cell::unsync::Lazy; use once_cell::unsync::Lazy;
use crate::diag::{bail, SourceResult}; use crate::diag::{bail, SourceResult};
use crate::engine::Engine; use crate::engine::{Engine, Route, Sink, Traced};
use crate::foundations::{Packed, Resolve, Smart, StyleChain}; use crate::foundations::{Packed, Resolve, Smart, StyleChain};
use crate::introspection::{Locator, SplitLocator, Tag, TagElem}; use crate::introspection::{
Introspector, Locator, LocatorLink, SplitLocator, Tag, TagElem,
};
use crate::layout::{ use crate::layout::{
layout_frame, Abs, AlignElem, Alignment, Axes, BlockElem, ColbreakElem, layout_frame, Abs, AlignElem, Alignment, Axes, BlockElem, ColbreakElem,
FixedAlignment, FlushElem, Fr, Fragment, Frame, PagebreakElem, PlaceElem, FixedAlignment, FlushElem, Fr, Fragment, Frame, PagebreakElem, PlaceElem,
@ -18,6 +21,7 @@ use crate::layout::{
use crate::model::ParElem; use crate::model::ParElem;
use crate::realize::Pair; use crate::realize::Pair;
use crate::text::TextElem; use crate::text::TextElem;
use crate::World;
/// Collects all elements of the flow into prepared children. These are much /// Collects all elements of the flow into prepared children. These are much
/// simpler to handle than the raw elements. /// simpler to handle than the raw elements.
@ -324,13 +328,49 @@ impl SingleChild<'_> {
/// Build the child's frame given the region's base size. /// Build the child's frame given the region's base size.
pub fn layout(&self, engine: &mut Engine, base: Size) -> SourceResult<Frame> { pub fn layout(&self, engine: &mut Engine, base: Size) -> SourceResult<Frame> {
self.cell.get_or_init(base, |base| { self.cell.get_or_init(base, |base| {
self.elem layout_single_impl(
.layout_single(engine, self.locator.relayout(), self.styles, base) engine.world,
.map(|frame| frame.post_processed(self.styles)) engine.introspector,
engine.traced,
TrackedMut::reborrow_mut(&mut engine.sink),
engine.route.track(),
self.elem,
self.locator.track(),
self.styles,
base,
)
}) })
} }
} }
/// The cached, internal implementation of [`SingleChild::layout`].
#[comemo::memoize]
#[allow(clippy::too_many_arguments)]
fn layout_single_impl(
world: Tracked<dyn World + '_>,
introspector: Tracked<Introspector>,
traced: Tracked<Traced>,
sink: TrackedMut<Sink>,
route: Tracked<Route>,
elem: &Packed<BlockElem>,
locator: Tracked<Locator>,
styles: StyleChain,
base: Size,
) -> SourceResult<Frame> {
let link = LocatorLink::new(locator);
let locator = Locator::link(&link);
let mut engine = Engine {
world,
introspector,
traced,
sink,
route: Route::extend(route),
};
elem.layout_single(&mut engine, locator, styles, base)
.map(|frame| frame.post_processed(styles))
}
/// A child that encapsulates a prepared breakable block. /// A child that encapsulates a prepared breakable block.
#[derive(Debug)] #[derive(Debug)]
pub struct MultiChild<'a> { pub struct MultiChild<'a> {
@ -349,7 +389,7 @@ impl<'a> MultiChild<'a> {
engine: &mut Engine, engine: &mut Engine,
regions: Regions, regions: Regions,
) -> SourceResult<(Frame, Option<MultiSpill<'a, 'b>>)> { ) -> SourceResult<(Frame, Option<MultiSpill<'a, 'b>>)> {
let fragment = self.layout_impl(engine, regions)?; let fragment = self.layout_full(engine, regions)?;
// Extract the first frame. // Extract the first frame.
let mut frames = fragment.into_iter(); let mut frames = fragment.into_iter();
@ -371,7 +411,7 @@ impl<'a> MultiChild<'a> {
/// The shared internal implementation of [`Self::layout`] and /// The shared internal implementation of [`Self::layout`] and
/// [`MultiSpill::layout`]. /// [`MultiSpill::layout`].
fn layout_impl( fn layout_full(
&self, &self,
engine: &mut Engine, engine: &mut Engine,
regions: Regions, regions: Regions,
@ -379,18 +419,54 @@ impl<'a> MultiChild<'a> {
self.cell.get_or_init(regions, |mut regions| { self.cell.get_or_init(regions, |mut regions| {
// Vertical expansion is only kept if this block is the only child. // Vertical expansion is only kept if this block is the only child.
regions.expand.y &= self.alone; regions.expand.y &= self.alone;
self.elem layout_multi_impl(
.layout_multiple(engine, self.locator.relayout(), self.styles, regions) engine.world,
.map(|mut fragment| { engine.introspector,
for frame in &mut fragment { engine.traced,
frame.post_process(self.styles); TrackedMut::reborrow_mut(&mut engine.sink),
} engine.route.track(),
fragment self.elem,
}) self.locator.track(),
self.styles,
regions,
)
}) })
} }
} }
/// The cached, internal implementation of [`MultiChild::layout_full`].
#[comemo::memoize]
#[allow(clippy::too_many_arguments)]
fn layout_multi_impl(
world: Tracked<dyn World + '_>,
introspector: Tracked<Introspector>,
traced: Tracked<Traced>,
sink: TrackedMut<Sink>,
route: Tracked<Route>,
elem: &Packed<BlockElem>,
locator: Tracked<Locator>,
styles: StyleChain,
regions: Regions,
) -> SourceResult<Fragment> {
let link = LocatorLink::new(locator);
let locator = Locator::link(&link);
let mut engine = Engine {
world,
introspector,
traced,
sink,
route: Route::extend(route),
};
elem.layout_multiple(&mut engine, locator, styles, regions)
.map(|mut fragment| {
for frame in &mut fragment {
frame.post_process(styles);
}
fragment
})
}
/// The spilled remains of a `MultiChild` that broke across two regions. /// The spilled remains of a `MultiChild` that broke across two regions.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct MultiSpill<'a, 'b> { pub struct MultiSpill<'a, 'b> {
@ -433,7 +509,7 @@ impl MultiSpill<'_, '_> {
// Extract the not-yet-processed frames. // Extract the not-yet-processed frames.
let mut frames = self let mut frames = self
.multi .multi
.layout_impl(engine, pod)? .layout_full(engine, pod)?
.into_iter() .into_iter()
.skip(self.backlog.len()); .skip(self.backlog.len());

View File

@ -97,7 +97,7 @@ pub fn layout_frame(
.map(Fragment::into_frame) .map(Fragment::into_frame)
} }
/// The internal implementation of [`layout_fragment`]. /// The cached, internal implementation of [`layout_fragment`].
#[comemo::memoize] #[comemo::memoize]
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
fn layout_fragment_impl( fn layout_fragment_impl(