[repo-assist] perf: XmlDoc.escapeXml fast-path + UniqueNameGenerator ToLowerInvariant dedup#429
Merged
sergey-tihon merged 3 commits intoMay 10, 2026
Conversation
… in UniqueNameGenerator
- XmlDoc.escapeXml: skip all 3 Replace allocations when the input string
contains no XML special characters ('&', '<', '>'). The vast majority of
OpenAPI operation summaries and descriptions are plain English text, so
the IndexOfAny check amortises to near-zero and avoids 2 intermediate
string allocations per call on the hot design-time compilation path.
- UniqueNameGenerator.findUniq: precompute prefix.ToLowerInvariant() once
per MakeUnique call (in MakeUnique itself) rather than re-computing it on
every recursive iteration. This eliminates repeated allocations when two or
more schema names collide and the generator appends a numeric suffix.
All 389 unit tests pass.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
3 tasks
Contributor
There was a problem hiding this comment.
Pull request overview
This PR introduces two design-time performance optimizations in Utils.fs aimed at reducing allocations and repeated string operations during schema/type compilation.
Changes:
- Add an
IndexOfAnyfast-path toXmlDoc.escapeXmlto avoid unnecessary string allocations when no XML special characters are present. - Optimize
UniqueNameGenerator.findUniqby precomputing the lowercased prefix once perMakeUniquecall to avoid repeatedToLowerInvariant()work during collision resolution.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🤖 This PR was created by Repo Assist, an automated AI assistant.
Summary
Two low-risk design-time performance improvements in
Utils.fs:1.
XmlDoc.escapeXml—IndexOfAnyfast-pathBefore: every call to
escapeXmlcalled.Replace()three times, allocating two intermediate strings even when the input contained no XML special characters (&,<,>).After: a single
IndexOfAny(['&'; '<'; '>'])check gates all threeReplacecalls. When the string is plain text (the common case for OpenAPI summaries and descriptions), zero intermediate strings are allocated and the function returns the original string reference unchanged.This function is called once per summary, once per description, once per parameter, and once per return doc during schema compilation. For a schema with 50 operations × 5 parameters on average, that's ~350 calls — previously always allocating, now virtually free for plain-text content.
2.
UniqueNameGenerator.findUniq— precompute lowercase keyBefore:
newName.ToLowerInvariant()was called on every recursive iteration offindUniq, even though only the numeric suffix changes between iterations.After:
prefix.ToLowerInvariant()is computed once inMakeUniqueand passed asprefixLowerto the recursive function. On collision, only the (small) integer suffix is appended to the already-lowercased prefix.Test Status
✅ All 389 unit tests pass after the change.