Skip to content

Split and join text with no markup without the run builder and interleaved copies - #78

Merged
HarryCordewener merged 1 commit into
mainfrom
claude/project-thread-v53z23
Nov 3, 2026
Merged

HarryCordewener merged 1 commit into
mainfrom
claude/project-thread-v53z23

Conversation

@HarryCordewener

@HarryCordewener HarryCordewener commented Nov 3, 2026 •

Copy link
Copy Markdown
Member

Before: splitting a 100-item plain list on spaces took 8.7 µs and 28,336 B, and joining 100 items took 2.7 µs and 8,232 B. Every segment built a run list even with no runs to clip, and Join collected parts and separators into a list, copied it to an array, and copied the parts again in Concat.

After: the same split takes 4.2 µs and 8,752 B (the result array plus one string and one MarkupText per item), and the join takes 1.6 µs and 656 B. Results are the same, runs included.

How: ExtractRange returns a slice with the shared empty run array when the text has no runs. Split counts the delimiters first and fills an exactly sized array. Join with one separator writes the parts and separators straight into the result string and builds runs only if something has them. Concat takes its parts as a span without copying them. Text with runs still goes through the existing run code.

Tests: CsCheck property tests (fixed seed, 5,000 samples each) compare Split, Substring, Concat and Join against copies of the old code on plain and marked input, with empty items, delimiters at both ends, multi-character delimiters and delimiters inside grapheme clusters. An allocation test bounds the plain split and join. All 1,390 tests pass.

The only observable difference: Join(separator, null) now throws ArgumentNullException instead of NullReferenceException.

Patch bump (2.24.3) in CHANGELOG.md. SharpMUSH picks it up with a MarkupStringVersion bump once it is tagged.


Generated by Claude Code

Summary by CodeRabbit

  • Performance Improvements
    • Reduced memory allocations when working with plain text, including substring extraction, splitting, joining, and concatenation.
    • Improved performance when joining collections of text.
  • Behavior
    • Text and markup results remain unchanged across these operations.

…eaved copies

Substring of a run-free text skips the run builder, Split counts its
delimiters to size the result exactly, Join with one separator writes the
parts straight into the result, and Concat no longer copies its parts.
Results are unchanged; property tests compare each against the forms they
replaced on plain and marked text.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DaoLzbDbE9CZBRWWkKM4Es
@coderabbitai

coderabbitai Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review.

Walkthrough

The change updates MarkupText extraction, splitting, concatenation, and joining to reduce allocations. Property-based tests compare text and markup runs with reference implementations, and an allocation test measures plain-text splitting and joining.

Changes

MarkupText text operations

Layer / File(s) Summary
Plain-text extraction and splitting
MarkupString/MarkupText.Operations.cs, MarkupString.Tests/Properties/SplitJoinProperties.cs
ExtractRange skips run clipping when the source has no runs. Split counts delimiter matches, returns the original text when there are none, and sizes the result array to the segment count. Property tests compare split text and runs with reference results.
Span-based concatenation and joining
MarkupString/MarkupText.cs, MarkupString.Tests/Properties/SplitJoinProperties.cs, MarkupString.Tests/AllocationTests.cs, CHANGELOG.md
Concat and Join build text and shifted runs from spans, with fast paths for empty and single-item inputs. Enumerable inputs use arrays or list spans when available and materialize other enumerable types. Tests cover overloads, separator call order, and allocation ranges. The changelog records the unreleased entry.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Merge Risk: Minimal · up to 5c1bb

The change reduces intermediate allocations in text operations. No merge-blocking issue was identified.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 42.86% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documenta… Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title names the main change: plain text with no markup is split and joined without the run builder or interleaved copies. The raw summary confirms this. The changes to MarkupText.Operations.cs (Sp…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Title check

Explanation

The title names the main change: plain text with no markup is split and joined without the run builder or interleaved copies. The raw summary confirms this. The changes to MarkupText.Operations.cs (Split sizing via delimiter count, ExtractRange short-circuit for run-free text) and MarkupText.cs (span-based Join, Concat without parts array) match the title. The added allocation test and property tests cover the same paths. The title is specific and accurate, though it is long at 81 characters.

Full details: Docstring Coverage

Explanation

Docstring coverage is 42.86% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 14 functions across 4 files. (1 skipped: 1 unsupported.)

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

Finishing Touches
Generate docstrings
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Warning

Some tools did not complete. Review the errors below.

ast-grep (0.51.1)

ast-grep could not parse rule config: /ast-grep-rules/ast-grep-essentials/rules/scala/security/scala-jwt-hardcoded-secret-scala.yml

CodeRabbit Verify

  • Run CodeRabbit Verify to test the changes in this pull request.
Recent review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: ASSERTIVE
  • Plan: Essentials
  • Run ID: 9d3c8c40-4464-4218-80cb-fdbfa2209718
Commits

Reviewing files that changed from the base of the PR and between 5265e31 and 5c1bb13.

Files selected for processing: 5
  • CHANGELOG.md
  • MarkupString.Tests/AllocationTests.cs
  • MarkupString.Tests/Properties/SplitJoinProperties.cs
  • MarkupString/MarkupText.Operations.cs
  • MarkupString/MarkupText.cs

Included review availability: This review used your included allowance. 0 included reviews remain after this review. Your included PR review attempts over the past 7 days set your current allowance at 1 review per hour.

@HarryCordewener
HarryCordewener marked this pull request as ready for review November 3, 2026 02:04
@HarryCordewener
HarryCordewener merged commit 87d26f6 into main Nov 3, 2026
7 checks passed
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