Take advantage of the Span<T> namespace changes#8477
Take advantage of the Span<T> namespace changes#8477andrewlock wants to merge 9 commits intoandrew/update-vendors-8from
Span<T> namespace changes#8477Conversation
Remove the outer #if NETCOREAPP guard from ValueStringBuilder. Now that Span<T> is in the System namespace for vendored types, the ref struct compiles on .NET Framework too. All dependencies (ArrayPool, MemoryMarshal, MemoryExtensions) are available via vendored global usings. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove #if NETCOREAPP around Span<byte>/ReadOnlySpan<byte> overloads of GenerateHash, GenerateV1Hash, and GenerateV1AHash. Delegate the byte[] private methods to the ReadOnlySpan<byte> versions to remove code duplication. The string-accepting methods keep their #if gate as they depend on Encoding.GetBytes(string, Span<byte>). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove #if NETCOREAPP3_1_OR_GREATER around all eight Span<byte> overloads (WriteVarLong, WriteVarLongZigZag, WriteVarInt, WriteVarIntZigZag, ReadVarLong, ReadVarLongZigZag, ReadVarInt, ReadVarIntZigZag). These only index into the span and need no .NET Core-specific BCL methods. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace the two-step byte[] allocation path on .NET Framework with a single stackalloc byte[16] + BinaryPrimitives.WriteUInt64LittleEndian on all TFMs. BinaryPrimitives and FnvHash64 Span overloads are now available everywhere via vendored global usings. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace the byte[]-allocating Guid.ToByteArray() path with stackalloc Guid[2] + MemoryMarshal.Cast<Guid, ulong> on all TFMs. MemoryMarshal is available via vendored global using on .NET Framework. Removes unused _buffer field and GetBuffer helper. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use stackalloc byte[16] for MD5 hash and stackalloc char[36] for hex formatting on all TFMs, avoiding two intermediate array allocations. Now uses the unified Md5Helper.ComputeMd5Hash(string, Span<byte>) signature. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace ArrayPool<char> rent/return for 2-char hex buffer with stackalloc char[2] on all TFMs. The chars are written by HexString.ToHexChars and appended to a StringBuilder, so no ToString/ToArray overhead. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The conditional using for System.Buffers is already handled by GlobalUsings.cs which imports the correct namespace (BCL or vendored) based on the TFM. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace StringBuilderCache fallback with ValueStringBuilder and stackalloc on all TFMs. AppendAsLowerInvariant lowercases each segment inline, avoiding the extra string allocation from the previous .ToLowerInvariant() call on the final result. Add a string? overload to ValueStringBuilder.AppendAsLowerInvariant to avoid needing explicit .AsSpan() at each call site. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6b128fd to
49790cb
Compare
BenchmarksBenchmark execution time: 2026-04-17 16:13:00 Comparing candidate commit 49790cb in PR branch Found 0 performance improvements and 0 performance regressions! Performance is the same for 27 metrics, 0 unstable metrics, 87 known flaky benchmarks.
|
Summary of changes
Remove some branching code that's no longer required after #8476 moved
Span<T>toSystemnamespaceReason for change
This sort of stuff is the reason we made that change, to reduce maintenance.
Implementation details
Set 🤖 looking for possible cases, so it's not exhaustive, but gives a taster. I think most of these make sense. It's nothing outstanding but it's the little things.
Test coverage
Just a refactoring, so covered by existing tests.
Other details
By definition, we don't expect to see performance improvements for this, other than potentially some reduced allocation in .NET Framework. The primary benefits are devx