Skip to content

[repo-assist] perf: HtmlParser reuses CurrentTag and Content StringBuilders across tokens - #1789

Draft
github-actions[bot] wants to merge 1 commit into
mainfrom
repo-assist/perf-html-parser-reuse-sb-2026-08-02-c5e1a26b4608f1a3
Draft

[repo-assist] perf: HtmlParser reuses CurrentTag and Content StringBuilders across tokens#1789
github-actions[bot] wants to merge 1 commit into
mainfrom
repo-assist/perf-html-parser-reuse-sb-2026-08-02-c5e1a26b4608f1a3

Conversation

@github-actions

@github-actions github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

🤖 This PR was created by Repo Assist, an automated AI assistant.

Summary

The HTML parser's HtmlState type previously allocated a new { Contents = StringBuilder() } (a new CharList record and a new StringBuilder) on every call to:

  • EmitSelfClosingTag() — reset CurrentTag
  • EmitTag() — reset CurrentTag
  • EmitToAttributeValue() — reset Content
  • Emit() — reset Content

For a typical HTML document with hundreds of elements, this means hundreds of short-lived StringBuilder objects, all discarded immediately after .Clear() would have sufficed.

Fix

Replace x.CurrentTag <- { Contents = StringBuilder() } and x.Content <- { Contents = StringBuilder() } with x.CurrentTag.Clear() and x.Content.Clear() respectively.

The CharList.Clear() method already existed for exactly this purpose (line 90).

Benefit

  • Eliminates 2 heap allocations per HTML element (one CharList record + one StringBuilder) for both CurrentTag and Content resets — roughly 4 allocations per opening/closing tag pair.
  • For a 1000-element HTML page this removes ~4000 short-lived allocations from the parser hot path.
  • No change to observable behaviour.

Trade-offs

None — this is a pure internal refactor. The CharList struct already reuses its StringBuilder safely via .Clear().

Test Status

All 2284 HTML-related tests pass on Linux/net8.0 (FSharp.Data.Core.Tests, HTML filter).

Closes #none (standalone performance improvement)

Generated by 🌈 Repo Assist, see workflow run. Learn more.

Generated by 🌈 Repo Assist, see workflow run. Learn more.
Comment /repo-assist to run again

Add this agentic workflow to your repo

To install this agentic workflow, run

gh aw add githubnext/agentics/workflows/repo-assist.md@42c2ab5b4e4c9273534c39259b2e0df7f20f07e9

…tokens

Instead of allocating a new { Contents = StringBuilder() } on every
EmitTag, EmitSelfClosingTag, EmitToAttributeValue, and Emit call,
reuse the existing CharList by calling .Clear(). This eliminates two
StringBuilder allocations per HTML element (one for CurrentTag, one
for Content) - for a typical HTML document with hundreds of elements
this removes hundreds of short-lived heap objects.

The CharList.Clear() method already existed for this purpose.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants