Skip to content

Add segmented buffering and sequence reads to ArrayPoolBufferWriter<T> - #1216

Open
paulomorgado wants to merge 1 commit into
CommunityToolkit:mainfrom
paulomorgado:feature/segmented-arraypoolbufferwriter
Open

paulomorgado wants to merge 1 commit into
CommunityToolkit:mainfrom
paulomorgado:feature/segmented-arraypoolbufferwriter

Conversation

@paulomorgado

Copy link
Copy Markdown
Contributor

Closes #1214

Linked issue: Add segmented buffering and sequence reads to ArrayPoolBufferWriter<T>

ArrayPoolBufferWriter<T> now retains completed pooled arrays as segments rather than copying the entire written prefix each time it grows. The new GetReadOnlySequence() exposes written data without copying its contents, benefiting repeated writes when consumers can accept a sequence.

Design choices: Buffers grow geometrically up to 1 MiB, while larger requested segments are rounded to a power of two. The writer rents the next buffer before changing ownership so a failed rent leaves existing data intact. WrittenMemory, WrittenSpan, IMemoryOwner<T>.Memory, and DangerousGetArray() continue to provide a contiguous view by consolidating on demand. Clear() and Dispose() return retained buffers to the pool; character ToString() and debugger inspection avoid incidental consolidation. Counts and writable views are limited to int.MaxValue elements.

PR Checklist

  • Created a feature/dev branch in your fork (vs. submitting directly from a commit on main)
  • Based off latest main branch of toolkit
  • PR doesn't include merge commits (always rebase on top of our main, if needed)
  • Tested code with current supported SDKs
  • New component — N/A: this enhances an existing type
    • Pull Request has been submitted to the documentation repository instructions. Link: N/A (no new component)
    • Added description of major feature to project description for NuGet package (4000 total character limit, so don't push entire description over that) — N/A (no new component)
  • Tests for the changes have been added (for bug fixes / features) (if applicable)
  • Header has been added to all new source files (run build/UpdateHeaders.bat) — N/A: no new source files
  • Contains NO breaking changes
  • Every new API (including internal ones) has full XML docs
  • Code follows all style conventions (changed code only; pre-existing formatter findings excluded)

Potential behavioral breaking change: Capacity

There are no removed public APIs or changed signatures, but Capacity no longer describes the length of one contiguous underlying array. After growth, it reports the completed written count plus the capacity of the active segment, capped at int.MaxValue; unwritten tails of completed segments are not counted. FreeCapacity is the writable portion of the active segment, so Capacity - WrittenCount == FreeCapacity. Callers that rely on specific capacity values or assume Capacity guarantees one contiguous buffer may need to use GetSpan(sizeHint) for writes or a contiguous-view API for reads. Writes exceeding the supported int.MaxValue total length are rejected.

Other information

Like WrittenSpan and WrittenMemory, GetReadOnlySequence() is a non-owning view into pooled buffers, not a persistent snapshot. The additional interaction to note is that merely requesting a contiguous view after a segmented sequence can consolidate the writer and return the arrays underlying that sequence to the pool, invalidating it without another write.

Automatic compaction of completed buffers was considered, but merging them would copy already-written data even for callers that only consume GetReadOnlySequence(). Keeping the segments intact avoids that unnecessary cost; data is copied only when a contiguous view is requested.

Retain completed pooled arrays instead of copying data on every growth,
and expose written data through GetReadOnlySequence(). Grow segments
geometrically and consolidate only when a contiguous view is requested.

Keep capacity and write counts within supported limits, avoid
consolidation during char formatting and debugger inspection, and add
tests for buffer ownership, failure recovery, and boundary conditions.

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.

Add segmented buffering and sequence reads to ArrayPoolBufferWriter<T>

1 participant