<PackageReference Include="System.Drawing.Common" Version="10.0.0-rc.1.25451.107" />

ValueStringBuilder

String builder struct that allows using stack space for small strings.
using System.Buffers; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace System.Text { [CompilerFeatureRequired("RefStructs")] [InterpolatedStringHandler] internal ref struct ValueStringBuilder { private const int GuessedLengthPerHole = 11; private const int MinimumArrayPoolLength = 256; [Nullable(2)] private char[] _arrayToReturnToPool; private Span<char> _chars; private int _pos; public int Length { [IsReadOnly] get { return _pos; } set { _pos = value; } } public int Capacity { [IsReadOnly] get { return _chars.Length; } } public ref char this[int index] { get { return ref _chars[index]; } } public Span<char> RawChars { [IsReadOnly] get { return _chars; } } public ValueStringBuilder(int literalLength, int formattedCount) { _arrayToReturnToPool = null; _chars = ArrayPool<char>.Shared.Rent(Math.Min(256, literalLength + 11 * formattedCount)); _pos = 0; } public ValueStringBuilder(Span<char> initialBuffer) { _arrayToReturnToPool = null; _chars = initialBuffer; _pos = 0; } public ValueStringBuilder(int initialCapacity) { _arrayToReturnToPool = ArrayPool<char>.Shared.Rent(initialCapacity); _chars = _arrayToReturnToPool; _pos = 0; } public void EnsureCapacity(int capacity) { if ((uint)capacity > (uint)_chars.Length) Grow(capacity - _pos); } [IsReadOnly] public ref char GetPinnableReference() { return ref MemoryMarshal.GetReference(_chars); } public ref char GetPinnableReference(bool terminate) { if (terminate) { EnsureCapacity(Length + 1); _chars[Length] = ''; } return ref MemoryMarshal.GetReference(_chars); } [IsReadOnly] [NullableContext(1)] public override string ToString() { Span<char> chars = _chars; return chars.Slice(0, _pos).ToString(); } [NullableContext(1)] public string ToStringAndClear() { string result = ToString(); Dispose(); return result; } public ReadOnlySpan<char> AsSpan(bool terminate) { if (terminate) { EnsureCapacity(Length + 1); _chars[Length] = ''; } return _chars.Slice(0, _pos); } [IsReadOnly] public ReadOnlySpan<char> AsSpan() { Span<char> chars = _chars; return chars.Slice(0, _pos); } [IsReadOnly] public ReadOnlySpan<char> AsSpan(int start) { Span<char> chars = _chars; return chars.Slice(start, _pos - start); } [IsReadOnly] public ReadOnlySpan<char> AsSpan(int start, int length) { return _chars.Slice(start, length); } public bool TryCopyTo(Span<char> destination, out int charsWritten) { if (_chars.Slice(0, _pos).TryCopyTo(destination)) { charsWritten = _pos; Dispose(); return true; } charsWritten = 0; Dispose(); return false; } public void Insert(int index, char value, int count) { if (_pos > _chars.Length - count) Grow(count); int length = _pos - index; Span<char> span = _chars.Slice(index, length); ref Span<char> chars = ref _chars; int num = index + count; span.CopyTo(chars.Slice(num, chars.Length - num)); span = _chars.Slice(index, count); span.Fill(value); _pos += count; } [NullableContext(2)] public void Insert(int index, string s) { if (s != null) { int length = s.Length; if (_pos > _chars.Length - length) Grow(length); int length2 = _pos - index; Span<char> span = _chars.Slice(index, length2); ref Span<char> chars = ref _chars; int num = index + length; span.CopyTo(chars.Slice(num, chars.Length - num)); ref Span<char> chars2 = ref _chars; s.CopyTo(chars2.Slice(index, chars2.Length - index)); _pos += length; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Append(char c) { int pos = _pos; if ((uint)pos < (uint)_chars.Length) { _chars[pos] = c; _pos = pos + 1; } else GrowAndAppend(c); } [MethodImpl(MethodImplOptions.AggressiveInlining)] [NullableContext(2)] public void AppendLiteral(string s) { if (s != null) { int pos = _pos; if (s.Length == 1 && (uint)pos < (uint)_chars.Length) { _chars[pos] = s[0]; _pos = pos + 1; } else AppendSlow(s); } } [NullableContext(1)] private void AppendSlow(string s) { int pos = _pos; if (pos > _chars.Length - s.Length) Grow(s.Length); ref Span<char> chars = ref _chars; int num = pos; s.CopyTo(chars.Slice(num, chars.Length - num)); _pos += s.Length; } [NullableContext(1)] public void AppendFormatted<[Nullable(0)] TFormattable>(TFormattable value) where TFormattable : ISpanFormattable { int charsWritten = default(int); while (true) { object obj = value; ref Span<char> chars = ref _chars; int pos = _pos; if (((ISpanFormattable)obj).TryFormat(chars.Slice(pos, chars.Length - pos), out charsWritten, default(ReadOnlySpan<char>), (IFormatProvider)null)) break; Grow(1); } _pos += charsWritten; } [NullableContext(2)] public void AppendFormatted(string value) { Append(value.AsSpan()); } [NullableContext(2)] public void AppendFormatted(object value) { AppendLiteral(value?.ToString()); } public void Append(char c, int count) { if (_pos > _chars.Length - count) Grow(count); Span<char> span = _chars.Slice(_pos, count); for (int i = 0; i < span.Length; i++) { span[i] = c; } _pos += count; } public unsafe void Append(char* value, int length) { if (_pos > _chars.Length - length) Grow(length); Span<char> span = _chars.Slice(_pos, length); for (int i = 0; i < span.Length; i++) { ref char reference = ref span[i]; char* intPtr = value; value = intPtr + 1; reference = *intPtr; } _pos += length; } public void Append(ReadOnlySpan<char> value) { if (_pos > _chars.Length - value.Length) Grow(value.Length); ref Span<char> chars = ref _chars; int pos = _pos; value.CopyTo(chars.Slice(pos, chars.Length - pos)); _pos += value.Length; } [MethodImpl(MethodImplOptions.NoInlining)] private void GrowAndAppend(char c) { Grow(1); Append(c); } [MethodImpl(MethodImplOptions.NoInlining)] private void Grow(int additionalCapacityBeyondPos) { int minimumLength = (int)Math.Max((uint)(_pos + additionalCapacityBeyondPos), Math.Min((uint)(_chars.Length * 2), 2147483591)); char[] array = ArrayPool<char>.Shared.Rent(minimumLength); _chars.Slice(0, _pos).CopyTo(array); char[] arrayToReturnToPool = _arrayToReturnToPool; _chars = (_arrayToReturnToPool = array); if (arrayToReturnToPool != null) ArrayPool<char>.Shared.Return(arrayToReturnToPool, false); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Dispose() { char[] arrayToReturnToPool = _arrayToReturnToPool; this = default(System.Text.ValueStringBuilder); if (arrayToReturnToPool != null) ArrayPool<char>.Shared.Return(arrayToReturnToPool, false); } } }