Skip to content

fix(scanner): do not allocate for every character of a block scalar - #986

Open
beffe123 wants to merge 1 commit into
goccy:masterfrom
beffe123:fix-block-scalar-allocations
Open

beffe123 wants to merge 1 commit into
goccy:masterfrom
beffe123:fix-block-scalar-allocations

Conversation

@beffe123

@beffe123 beffe123 commented Nov 2, 2026

Copy link
Copy Markdown

Before submitting your PR, please confirm the following.

  • Describe the purpose for which you created this PR.
  • Create test code that corresponds to the modification

Purpose

MultiLineState.validateIndentColumn is called for every character of a literal or folded block scalar, and it called
firstLineIndentColumnByOpt(s.opt) each time. For a header without an indentation indicator (|, >, |-, >+, …),
that is strconv.ParseInt(""), which returns a *strconv.NumError: one allocation of 48 bytes per character of the text.

This PR parses the indicator once, in setLiteral and setFolded, and keeps it in MultiLineState.optIndentColumn.
Behaviour does not change.

Unmarshalling a document with a literal block of 2,030 characters into map[string]any (Apple M2, Go 1.26.9, 6 runs):

before after
time 98.8 µs 53.9 µs
memory 123.9 KB 26.3 KB
allocations 2,186 155

We came across it while profiling a CMS that parses a few thousand pages with text blocks on every publish: two thirds of
all bytes allocated were these errors.

Test

TestBlockScalarAllocations (lexer) tokenizes block scalars of 10 and of 10,000 characters and requires about the same
number of allocations. Before the change it was 67 against 20,054, after it 46 against 52. make test (with the YAML test
suite) and golangci-lint run pass.

🤖 Generated with Claude Code

validateIndentColumn runs for every character of a literal or folded
block scalar, and it parsed the header option each time. Without an
indentation indicator (the common "|" or ">"), that is
strconv.ParseInt(""), which returns a *strconv.NumError: one
allocation of 48 bytes per character.

The indicator is now parsed once, when the multi-line state is set up.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 80.66%. Comparing base (edee2f9) to head (9bebe2b).
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@           Coverage Diff           @@
##           master     #986   +/-   ##
=======================================
  Coverage   80.65%   80.66%           
=======================================
  Files          22       22           
  Lines        6845     6847    +2     
=======================================
+ Hits         5521     5523    +2     
  Misses        905      905           
  Partials      419      419           
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants