perf: Reduce best fitting allocations (#7411)

This commit is contained in:
Micha Reiser 2023-09-18 21:49:44 +02:00 committed by GitHub
parent 2421805033
commit 3336d23f48
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 173 additions and 83 deletions

View file

@ -288,7 +288,9 @@ impl<'a> Printer<'a> {
stack.push(TagKind::FitsExpanded, args);
}
FormatElement::Tag(tag @ (StartLabelled(_) | StartEntry)) => {
FormatElement::Tag(
tag @ (StartLabelled(_) | StartEntry | StartBestFittingEntry { .. }),
) => {
stack.push(tag.kind(), args);
}
@ -305,6 +307,7 @@ impl<'a> Printer<'a> {
| EndFitsExpanded
| EndVerbatim
| EndLineSuffix
| EndBestFittingEntry
| EndFill),
) => {
stack.pop(tag.kind())?;
@ -495,47 +498,64 @@ impl<'a> Printer<'a> {
if args.mode().is_flat() && self.state.measured_group_fits {
queue.extend_back(variants.most_flat());
self.print_entry(queue, stack, args)
self.print_entry(queue, stack, args, TagKind::BestFittingEntry)
} else {
self.state.measured_group_fits = true;
let normal_variants = &variants[..variants.len() - 1];
let mut variants_iter = variants.into_iter();
let mut current = variants_iter.next().unwrap();
for variant in normal_variants {
for next in variants_iter {
// Test if this variant fits and if so, use it. Otherwise try the next
// variant.
// Try to fit only the first variant on a single line
if !matches!(variant.first(), Some(&FormatElement::Tag(Tag::StartEntry))) {
return invalid_start_tag(TagKind::Entry, variant.first());
if !matches!(
current.first(),
Some(&FormatElement::Tag(Tag::StartBestFittingEntry))
) {
return invalid_start_tag(TagKind::BestFittingEntry, current.first());
}
// Skip the first element because we want to override the args for the entry and the
// args must be popped from the stack as soon as it sees the matching end entry.
let content = &variant[1..];
let content = &current[1..];
let entry_args = args
.with_print_mode(PrintMode::Flat)
.with_measure_mode(MeasureMode::from(mode));
queue.extend_back(content);
stack.push(TagKind::Entry, entry_args);
stack.push(TagKind::BestFittingEntry, entry_args);
let variant_fits = self.fits(queue, stack)?;
stack.pop(TagKind::Entry)?;
stack.pop(TagKind::BestFittingEntry)?;
// Remove the content slice because printing needs the variant WITH the start entry
let popped_slice = queue.pop_slice();
debug_assert_eq!(popped_slice, Some(content));
if variant_fits {
queue.extend_back(variant);
return self.print_entry(queue, stack, args.with_print_mode(PrintMode::Flat));
queue.extend_back(current);
return self.print_entry(
queue,
stack,
args.with_print_mode(PrintMode::Flat),
TagKind::BestFittingEntry,
);
}
current = next;
}
// At this stage current is the most expanded.
// No variant fits, take the last (most expanded) as fallback
let most_expanded = variants.most_expanded();
queue.extend_back(most_expanded);
self.print_entry(queue, stack, args.with_print_mode(PrintMode::Expanded))
queue.extend_back(current);
self.print_entry(
queue,
stack,
args.with_print_mode(PrintMode::Expanded),
TagKind::BestFittingEntry,
)
}
}
@ -686,7 +706,7 @@ impl<'a> Printer<'a> {
stack: &mut PrintCallStack,
args: PrintElementArgs,
) -> PrintResult<()> {
self.print_entry(queue, stack, args)
self.print_entry(queue, stack, args, TagKind::Entry)
}
/// Semantic alias for [`Self::print_entry`] for fill separators.
@ -696,7 +716,7 @@ impl<'a> Printer<'a> {
stack: &mut PrintCallStack,
args: PrintElementArgs,
) -> PrintResult<()> {
self.print_entry(queue, stack, args)
self.print_entry(queue, stack, args, TagKind::Entry)
}
/// Fully print an element (print the element itself and all its descendants)
@ -708,32 +728,31 @@ impl<'a> Printer<'a> {
queue: &mut PrintQueue<'a>,
stack: &mut PrintCallStack,
args: PrintElementArgs,
kind: TagKind,
) -> PrintResult<()> {
let start_entry = queue.top();
if !matches!(start_entry, Some(&FormatElement::Tag(Tag::StartEntry))) {
return invalid_start_tag(TagKind::Entry, start_entry);
if queue
.pop()
.is_some_and(|start| start.tag_kind() == Some(kind))
{
stack.push(kind, args);
} else {
return invalid_start_tag(kind, start_entry);
}
let mut depth = 0;
let mut depth = 1u32;
while let Some(element) = queue.pop() {
match element {
FormatElement::Tag(Tag::StartEntry) => {
// Handle the start of the first element by pushing the args on the stack.
if depth == 0 {
depth = 1;
stack.push(TagKind::Entry, args);
continue;
}
FormatElement::Tag(Tag::StartEntry | Tag::StartBestFittingEntry) => {
depth += 1;
}
FormatElement::Tag(Tag::EndEntry) => {
FormatElement::Tag(end_tag @ (Tag::EndEntry | Tag::EndBestFittingEntry)) => {
depth -= 1;
// Reached the end entry, pop the entry from the stack and return.
if depth == 0 {
stack.pop(TagKind::Entry)?;
stack.pop(end_tag.kind())?;
return Ok(());
}
}
@ -745,7 +764,7 @@ impl<'a> Printer<'a> {
self.print_element(stack, queue, element)?;
}
invalid_end_tag(TagKind::Entry, stack.top_kind())
invalid_end_tag(kind, stack.top_kind())
}
fn print_char(&mut self, char: char) {
@ -1148,11 +1167,14 @@ impl<'a, 'print> FitsMeasurer<'a, 'print> {
PrintMode::Expanded => (variants.most_expanded(), args),
};
if !matches!(slice.first(), Some(FormatElement::Tag(Tag::StartEntry))) {
return invalid_start_tag(TagKind::Entry, slice.first());
if !matches!(
slice.first(),
Some(FormatElement::Tag(Tag::StartBestFittingEntry))
) {
return invalid_start_tag(TagKind::BestFittingEntry, slice.first());
}
self.stack.push(TagKind::Entry, args);
self.stack.push(TagKind::BestFittingEntry, args);
self.queue.extend_back(&slice[1..]);
}
@ -1277,7 +1299,11 @@ impl<'a, 'print> FitsMeasurer<'a, 'print> {
}
FormatElement::Tag(
tag @ (StartFill | StartVerbatim(_) | StartLabelled(_) | StartEntry),
tag @ (StartFill
| StartVerbatim(_)
| StartLabelled(_)
| StartEntry
| StartBestFittingEntry { .. }),
) => {
self.stack.push(tag.kind(), args);
}
@ -1294,6 +1320,7 @@ impl<'a, 'print> FitsMeasurer<'a, 'print> {
| EndAlign
| EndDedent
| EndIndent
| EndBestFittingEntry
| EndFitsExpanded),
) => {
self.stack.pop(tag.kind())?;