Skip to content

perf(formatter): use flat storage for BestFitting variants#18085

Closed
Boshen wants to merge 1 commit intomainfrom
feat/formatter-best-fitting-flat-storage
Closed

perf(formatter): use flat storage for BestFitting variants#18085
Boshen wants to merge 1 commit intomainfrom
feat/formatter-best-fitting-flat-storage

Conversation

@Boshen
Copy link
Member

@Boshen Boshen commented Jan 16, 2026

Summary

Port of astral-sh/ruff#7411 to oxc_formatter.

This optimizes memory allocation for BestFitting elements by using a flat storage structure with marker tags instead of nested allocations.

Key Changes

  1. New Tags (tag.rs):

    • Added StartBestFittingEntry and EndBestFittingEntry to the Tag enum
    • Added BestFittingEntry to TagKind enum
  2. Flat Storage Structure (format_element/mod.rs):

    • Changed BestFittingElement from storing &'a [&'a [FormatElement<'a>]] (nested slices) to &'a [FormatElement<'a>] (flat slice)
    • Variants are now delimited by StartBestFittingEntry/EndBestFittingEntry tags
    • Added BestFittingVariantsIter iterator to parse variants from the flat structure
  3. Builder Update (builders.rs):

    • Updated BestFitting::fmt to write all variants to a single buffer with entry tags
  4. Printer Updates (printer/mod.rs):

    • Added print_best_fitting_entry function to handle the new entry tags
    • Updated print_best_fitting to use the iterator and call the new entry printer
    • Updated tag handling throughout the printer for the new tags
  5. Document Display (document.rs):

    • Updated to handle StartBestFittingEntry/EndBestFittingEntry tags
  6. Direct API Usage (arguments.rs):

    • Updated the call site that directly constructs BestFittingElement to use the new flat structure

Benefits

  • Reduces memory allocations by avoiding per-variant heap allocations
  • All variant content is stored in a single contiguous buffer

Test plan

  • All 144 formatter tests pass
  • Prettier conformance unchanged (97.77% JS, 96.37% TS)
  • Clippy clean

🤖 Generated with Claude Code

Port of astral-sh/ruff#7411 to oxc_formatter.

This optimizes memory allocation for `BestFitting` elements by using a flat
storage structure with marker tags instead of nested allocations.

Key changes:
- Add `StartBestFittingEntry`/`EndBestFittingEntry` tags to delimit variants
- Change `BestFittingElement` from `&[&[FormatElement]]` to `&[FormatElement]`
- Add `BestFittingVariantsIter` iterator to parse variants from flat structure
- Update printer to handle the new structure

Benefits:
- Reduces memory allocations by avoiding per-variant heap allocations
- All variant content stored in a single contiguous buffer

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings January 16, 2026 14:24
@Boshen Boshen requested a review from Dunqing as a code owner January 16, 2026 14:24
@github-actions github-actions bot added A-formatter Area - Formatter C-performance Category - Solution not expected to change functional behavior, only performance labels Jan 16, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR optimizes memory allocation for BestFitting elements by replacing nested slice allocations with a flat storage structure using delimiter tags. This is a performance optimization that reduces per-variant heap allocations while maintaining the same functionality.

Changes:

  • Added StartBestFittingEntry and EndBestFittingEntry tags to delimit variants in flat storage
  • Refactored BestFittingElement to store variants in a single flat slice with delimiter tags instead of nested slices
  • Added BestFittingVariantsIter to parse variants from the flat structure
  • Updated all consumers (printer, document display, builders, and call arguments) to work with the new flat structure

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
crates/oxc_formatter/src/formatter/format_element/tag.rs Added new StartBestFittingEntry and EndBestFittingEntry tags and BestFittingEntry tag kind
crates/oxc_formatter/src/formatter/format_element/mod.rs Changed BestFittingElement storage from nested slices to flat slice with delimiter tags, added iterator
crates/oxc_formatter/src/formatter/builders.rs Updated BestFitting::fmt to write all variants to single buffer with tags, removed ArenaVec usage
crates/oxc_formatter/src/formatter/printer/mod.rs Added print_best_fitting_entry function, updated best fitting logic to use iterator and new tags
crates/oxc_formatter/src/formatter/format_element/document.rs Updated display logic to handle new BestFittingEntry tags
crates/oxc_formatter/src/print/call_like_expression/arguments.rs Updated direct BestFittingElement construction to use flat storage with new tags

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +381 to +383
if let Some(most_expanded) = variants.last() {
queue.extend_back(most_expanded);
}
Copy link

Copilot AI Jan 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The use of variants.last() wrapped in if let Some(...) at lines 381-382 suggests uncertainty about whether variants is non-empty. However, the safety invariants guarantee at least 2 variants exist. If the invariants hold, this check is unnecessary and variants.last().unwrap() would be clearer. If there's concern about the invariants not holding, a more explicit assertion or unwrap with a meaningful message would be better than silently doing nothing when variants.last() returns None.

Suggested change
if let Some(most_expanded) = variants.last() {
queue.extend_back(most_expanded);
}
let most_expanded = variants
.last()
.expect("BestFittingElement should have at least one variant");
queue.extend_back(most_expanded);

Copilot uses AI. Check for mistakes.
Comment on lines +401 to +405
// Find the StartBestFittingEntry tag
let start_index = self.elements.iter().position(|element| {
matches!(element, FormatElement::Tag(Tag::StartBestFittingEntry))
})?;

Copy link

Copilot AI Jan 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The iterator searches for the first StartBestFittingEntry using position(), but based on the construction logic in arguments.rs and builders.rs, the flat buffer should always start with StartBestFittingEntry at position 0. Consider checking if the first element is StartBestFittingEntry and returning early if not, rather than searching through the slice. This would make the common case faster and catch malformed data earlier.

Suggested change
// Find the StartBestFittingEntry tag
let start_index = self.elements.iter().position(|element| {
matches!(element, FormatElement::Tag(Tag::StartBestFittingEntry))
})?;
// The flat buffer is expected to start with StartBestFittingEntry at position 0.
// If it does not, treat the data as malformed and terminate the iteration.
if !matches!(
self.elements[0],
FormatElement::Tag(Tag::StartBestFittingEntry)
) {
// Clear remaining elements so subsequent calls also return None.
self.elements = &[];
return None;
}
let start_index = 0;

Copilot uses AI. Check for mistakes.
@codspeed-hq
Copy link

codspeed-hq bot commented Jan 16, 2026

Merging this PR will not alter performance

✅ 38 untouched benchmarks
⏩ 7 skipped benchmarks1


Comparing feat/formatter-best-fitting-flat-storage (ac274d6) with main (9135b0b)

Open in CodSpeed

Footnotes

  1. 7 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@Boshen Boshen marked this pull request as draft January 16, 2026 14:41
@Boshen Boshen closed this Jan 17, 2026
@Boshen Boshen deleted the feat/formatter-best-fitting-flat-storage branch February 3, 2026 08:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-formatter Area - Formatter C-performance Category - Solution not expected to change functional behavior, only performance

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants