Code review: Reverse temperature

This commit is contained in:
Martin Haug 2021-06-27 18:57:08 +02:00
parent 6f518c1728
commit e9960b8942
5 changed files with 65 additions and 57 deletions

View File

@ -26,6 +26,11 @@ impl LayoutCache {
self.frames.clear(); self.frames.clear();
} }
/// Amount of items in the cache.
pub fn len(&self) -> usize {
self.frames.iter().map(|(_, e)| e.len()).sum()
}
/// Retains all elements for which the closure on the level returns `true`. /// Retains all elements for which the closure on the level returns `true`.
pub fn retain<F>(&mut self, mut f: F) pub fn retain<F>(&mut self, mut f: F)
where where
@ -41,9 +46,10 @@ impl LayoutCache {
self.age += 1; self.age += 1;
for entry in self.frames.iter_mut().flat_map(|(_, x)| x.iter_mut()) { for entry in self.frames.iter_mut().flat_map(|(_, x)| x.iter_mut()) {
for i in 0 .. (entry.temperature.len() - 1) { for i in 0 .. (entry.temperature.len() - 1) {
entry.temperature[i] = entry.temperature[i + 1]; entry.temperature[i + 1] = entry.temperature[i];
} }
*entry.temperature.last_mut().unwrap() = 0; entry.temperature[0] = 0;
entry.age += 1;
} }
} }
@ -99,12 +105,11 @@ pub struct FramesEntry {
pub frames: Vec<Constrained<Rc<Frame>>>, pub frames: Vec<Constrained<Rc<Frame>>>,
/// How nested the frame was in the context is was originally appearing in. /// How nested the frame was in the context is was originally appearing in.
pub level: usize, pub level: usize,
/// How much the element was accessed during the last five compilations, the
/// most recent one being the last element. `None` variants indicate that
/// the element is younger than five compilations.
temperature: [usize; 5],
/// For how long the element already exists. /// For how long the element already exists.
age: usize, age: usize,
/// How much the element was accessed during the last five compilations, the
/// most recent one being the first element.
temperature: [usize; 5],
} }
impl FramesEntry { impl FramesEntry {
@ -113,8 +118,8 @@ impl FramesEntry {
Self { Self {
frames, frames,
level, level,
temperature: [0; 5],
age: 1, age: 1,
temperature: [0; 5],
} }
} }
@ -126,7 +131,7 @@ impl FramesEntry {
} }
} }
self.temperature[4] = self.temperature[4] + 1; self.temperature[0] += 1;
Some(self.frames.clone()) Some(self.frames.clone())
} }
@ -141,16 +146,11 @@ impl FramesEntry {
/// been used. /// been used.
pub fn cooldown(&self) -> usize { pub fn cooldown(&self) -> usize {
let mut cycle = 0; let mut cycle = 0;
for (i, &temp) in self.temperature.iter().enumerate().rev() { for &temp in &self.temperature[.. self.age] {
if self.age > i { if temp > 0 {
if temp > 0 {
return self.temperature.len() - 1 - i;
}
} else {
return cycle; return cycle;
} }
cycle += 1;
cycle += 1
} }
cycle cycle
@ -158,7 +158,7 @@ impl FramesEntry {
/// Whether this element was used in the last compilation cycle. /// Whether this element was used in the last compilation cycle.
pub fn hit(&self) -> bool { pub fn hit(&self) -> bool {
self.temperature.last().unwrap() != &0 self.temperature[0] != 0
} }
} }
@ -213,10 +213,10 @@ impl Constraints {
let base = regions.base.to_spec(); let base = regions.base.to_spec();
let current = regions.current.to_spec(); 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.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)))
} }
/// Changes all constraints by adding the `size` to them if they are `Some`. /// Changes all constraints by adding the `size` to them if they are `Some`.
@ -235,18 +235,13 @@ impl Constraints {
} }
} }
self.exact = override_if_some(self.exact, regions.current.to_spec()); let current = regions.current.to_spec();
self.base = override_if_some(self.base, regions.base.to_spec()); let base = regions.base.to_spec();
}
}
fn override_if_some( self.exact.horizontal.set_if_some(current.horizontal);
one: Spec<Option<Length>>, self.exact.vertical.set_if_some(current.vertical);
other: Spec<Length>, self.base.horizontal.set_if_some(base.horizontal);
) -> Spec<Option<Length>> { self.base.vertical.set_if_some(base.vertical);
Spec {
vertical: one.vertical.map(|_| other.vertical),
horizontal: one.horizontal.map(|_| other.horizontal),
} }
} }
@ -272,9 +267,13 @@ pub trait OptionExt {
// Sets `other` as the value if the Option is `None` or if it contains a // Sets `other` as the value if the Option is `None` or if it contains a
// value larger than `other`. // value larger than `other`.
fn set_min(&mut self, other: Length); fn set_min(&mut self, other: Length);
// Sets `other` as the value if the Option is `None` or if it contains a // Sets `other` as the value if the Option is `None` or if it contains a
// value smaller than `other`. // value smaller than `other`.
fn set_max(&mut self, other: Length); fn set_max(&mut self, other: Length);
/// Sets `other` as the value if the Option is `Some`.
fn set_if_some(&mut self, other: Length);
} }
impl OptionExt for Option<Length> { impl OptionExt for Option<Length> {
@ -291,4 +290,10 @@ impl OptionExt for Option<Length> {
None => *self = Some(other), None => *self = Some(other),
} }
} }
fn set_if_some(&mut self, other: Length) {
if self.is_some() {
*self = Some(other);
}
}
} }

View File

@ -15,10 +15,11 @@ impl Layout for PadNode {
ctx: &mut LayoutContext, ctx: &mut LayoutContext,
regions: &Regions, regions: &Regions,
) -> Vec<Constrained<Rc<Frame>>> { ) -> Vec<Constrained<Rc<Frame>>> {
let mut original = regions.clone(); let mut regions = regions.clone();
let mut regions = regions.map(|size| size - self.padding.resolve(size).size()); let mut frames = self.child.layout(
ctx,
let mut frames = self.child.layout(ctx, &regions); &regions.map(|size| size - self.padding.resolve(size).size()),
);
for frame in &mut frames { for frame in &mut frames {
let padded = solve(self.padding, frame.size); let padded = solve(self.padding, frame.size);
@ -29,19 +30,19 @@ impl Layout for PadNode {
let prev = std::mem::take(&mut frame.item); let prev = std::mem::take(&mut frame.item);
new.push_frame(origin, prev); new.push_frame(origin, prev);
frame.constraints.mutate(padding.size(), &original); frame.constraints.mutate(padding.size(), &regions);
if self.padding.left.is_relative() || self.padding.right.is_relative() { if self.padding.left.is_relative() || self.padding.right.is_relative() {
frame.constraints.base.horizontal = Some(original.base.width); frame.constraints.base.horizontal = Some(regions.base.width);
} }
if self.padding.top.is_relative() || self.padding.bottom.is_relative() { if self.padding.top.is_relative() || self.padding.bottom.is_relative() {
frame.constraints.base.vertical = Some(original.base.height); frame.constraints.base.vertical = Some(regions.base.height);
} }
regions.next(); regions.next();
original.next();
*Rc::make_mut(&mut frame.item) = new; *Rc::make_mut(&mut frame.item) = new;
} }
frames frames
} }
} }

View File

@ -217,9 +217,11 @@ impl<'a> ParLayouter<'a> {
// Again, the line must not fit. It would if the space taken up // Again, the line must not fit. It would if the space taken up
// plus the line height would fit, therefore the constraint // plus the line height would fit, therefore the constraint
// below. // below.
stack.constraints.max.vertical.set_min( stack
stack.full.height - stack.regions.current.height + line.size.height, .constraints
); .max
.vertical
.set_min(stack.size.height + line.size.height);
stack.finish_region(ctx); stack.finish_region(ctx);
} }
@ -230,9 +232,11 @@ impl<'a> ParLayouter<'a> {
break; break;
} }
stack.constraints.max.vertical.set_min( stack
stack.full.height - stack.regions.current.height + line.size.height, .constraints
); .max
.vertical
.set_min(stack.size.height + line.size.height);
stack.finish_region(ctx); stack.finish_region(ctx);
} }
// If the line does not fit horizontally or we have a mandatory // If the line does not fit horizontally or we have a mandatory

View File

@ -88,12 +88,12 @@ impl<'a> StackLayouter<'a> {
Self { Self {
stack, stack,
main, main,
constraints: Constraints::new(expand),
expand, expand,
regions, regions,
full, full,
used: Gen::zero(), used: Gen::zero(),
ruler: Align::Start, ruler: Align::Start,
constraints: Constraints::new(expand),
overflowing: false, overflowing: false,
frames: vec![], frames: vec![],
finished: vec![], finished: vec![],
@ -154,7 +154,7 @@ impl<'a> StackLayouter<'a> {
self.constraints self.constraints
.max .max
.get_mut(self.main) .get_mut(self.main)
.set_min(size.main + self.used.main); .set_min(self.used.main + size.main);
self.finish_region(); self.finish_region();
} }

View File

@ -15,7 +15,7 @@ use walkdir::WalkDir;
use typst::cache::Cache; use typst::cache::Cache;
use typst::color; use typst::color;
use typst::diag::{Diag, DiagSet, Level, Pass}; use typst::diag::{Diag, DiagSet, Level};
use typst::eval::{eval, EvalContext, FuncArgs, FuncValue, Scope, Value}; use typst::eval::{eval, EvalContext, FuncArgs, FuncValue, Scope, Value};
use typst::exec::{exec, State}; use typst::exec::{exec, State};
use typst::geom::{self, Length, Point, Sides, Size}; use typst::geom::{self, Length, Point, Sides, Size};
@ -233,14 +233,12 @@ fn test_part(
&scope, &scope,
); );
let executed = exec(&evaluated.output.template, state.clone()); let executed = exec(&evaluated.output.template, state.clone());
let layouted = layout(loader, cache, &executed.output); let mut layouted = layout(loader, cache, &executed.output);
let mut diags = parsed.diags; let mut diags = parsed.diags;
diags.extend(evaluated.diags); diags.extend(evaluated.diags);
diags.extend(executed.diags); diags.extend(executed.diags);
let mut pass = Pass::new(layouted, diags);
let mut ok = true; let mut ok = true;
for panic in &*panics.borrow() { for panic in &*panics.borrow() {
@ -255,11 +253,11 @@ fn test_part(
ok = false; ok = false;
} }
if pass.diags != ref_diags { if diags != ref_diags {
println!(" Subtest {} does not match expected diagnostics. ❌", i); println!(" Subtest {} does not match expected diagnostics. ❌", i);
ok = false; ok = false;
for diag in &pass.diags { for diag in &diags {
if !ref_diags.contains(diag) { if !ref_diags.contains(diag) {
print!(" Not annotated | "); print!(" Not annotated | ");
print_diag(diag, &map, lines); print_diag(diag, &map, lines);
@ -267,7 +265,7 @@ fn test_part(
} }
for diag in &ref_diags { for diag in &ref_diags {
if !pass.diags.contains(diag) { if !diags.contains(diag) {
print!(" Not emitted | "); print!(" Not emitted | ");
print_diag(diag, &map, lines); print_diag(diag, &map, lines);
} }
@ -302,7 +300,7 @@ fn test_part(
); );
} }
if cached_result != pass.output { if cached_result != layouted {
ok = false; ok = false;
println!( println!(
" Recompilation of subtest {} differs from clean pass ❌", " Recompilation of subtest {} differs from clean pass ❌",
@ -315,10 +313,10 @@ fn test_part(
cache.layout.turnaround(); cache.layout.turnaround();
if !compare_ref { if !compare_ref {
pass.output.clear(); layouted.clear();
} }
(ok, compare_ref, pass.output) (ok, compare_ref, layouted)
} }
fn parse_metadata(src: &str, map: &LineMap) -> (Option<bool>, DiagSet) { fn parse_metadata(src: &str, map: &LineMap) -> (Option<bool>, DiagSet) {