2using System.Diagnostics;
4using System.Runtime.InteropServices;
12 internal ref partial struct ValueStringBuilder
15 char[]? _arrayToReturnToPool;
23 public ValueStringBuilder(Span<char> initialBuffer)
25 _arrayToReturnToPool =
null;
26 _chars = initialBuffer;
34 public ValueStringBuilder(
int initialCapacity)
36 _arrayToReturnToPool = ArrayPool<char>.Shared.Rent(initialCapacity);
37 _chars = _arrayToReturnToPool;
49 Debug.Assert(value >= 0);
50 Debug.Assert(value <= _chars.Length);
58 public readonly
int Capacity => _chars.Length;
64 public void EnsureCapacity(
int capacity)
67 Debug.Assert(capacity >= 0);
70 if ((uint)capacity > (uint)_chars.Length)
71 Grow(capacity - _pos);
80 public ref char GetPinnableReference()
82 return ref MemoryMarshal.GetReference(_chars);
89 public ref char GetPinnableReference(
bool terminate)
93 EnsureCapacity(Length + 1);
94 _chars[Length] =
'\0';
97 return ref MemoryMarshal.GetReference(_chars);
105 public ref char this[
int index]
109 Debug.Assert(index < _pos);
110 return ref _chars[index];
118 public override string ToString()
120 var s = _chars.Slice(0, _pos).ToString();
126 public readonly Span<char> RawChars => _chars;
132 public ReadOnlySpan<char> AsSpan(
bool terminate)
136 EnsureCapacity(Length + 1);
137 _chars[Length] =
'\0';
140 return _chars.Slice(0, _pos);
147 public readonly ReadOnlySpan<char> AsSpan() => _chars.Slice(0, _pos);
154 public readonly ReadOnlySpan<char> AsSpan(
int start) => _chars.Slice(start, _pos - start);
162 public readonly ReadOnlySpan<char> AsSpan(
int start,
int length) => _chars.Slice(start, length);
170 public bool TryCopyTo(Span<char> destination, out
int charsWritten)
172 if (_chars.Slice(0, _pos).TryCopyTo(destination))
192 public void Insert(
int index,
char value,
int count)
194 if (_pos > _chars.Length - count)
199 int remaining = _pos - index;
200 _chars.Slice(index, remaining).CopyTo(_chars.Slice(index + count));
201 _chars.Slice(index, count).Fill(value);
210 public void Insert(
int index,
string? s)
215 int count = s.Length;
217 if (_pos > _chars.Length - count)
220 int remaining = _pos - index;
221 _chars.Slice(index, remaining).CopyTo(_chars.Slice(index + count));
226 .CopyTo(_chars.Slice(index));
234 [MethodImpl(MethodImplOptions.AggressiveInlining)]
235 public void Append(
char c)
239 if ((uint)pos < (uint)chars.Length)
254 [MethodImpl(MethodImplOptions.AggressiveInlining)]
255 public void Append(
string? s)
263 if (s.Length == 1 && (uint)pos < (uint)_chars.Length)
278 void AppendSlow(
string s)
281 if (pos > _chars.Length - s.Length)
290 .CopyTo(_chars.Slice(pos));
299 public void Append(
char c,
int count)
301 if (_pos > _chars.Length - count)
304 var dst = _chars.Slice(_pos, count);
305 for (
int i = 0; i < dst.Length; i++)
316 public unsafe
void Append(
char* value,
int length)
319 if (pos > _chars.Length - length)
322 var dst = _chars.Slice(_pos, length);
323 for (
int i = 0; i < dst.Length; i++)
333 public void Append(scoped ReadOnlySpan<char> value)
336 if (pos > _chars.Length - value.Length)
339 value.CopyTo(_chars.Slice(_pos));
340 _pos += value.Length;
348 [MethodImpl(MethodImplOptions.AggressiveInlining)]
349 public Span<char> AppendSpan(
int length)
352 if (origPos > _chars.Length - length)
355 _pos = origPos + length;
356 return _chars.Slice(origPos, length);
363 [MethodImpl(MethodImplOptions.NoInlining)]
364 void GrowAndAppend(
char c)
376 public void Remove(
int startIndex,
int length)
379 throw new ArgumentOutOfRangeException(nameof(startIndex));
381 throw new ArgumentOutOfRangeException(nameof(length));
382 if (length > Length - startIndex)
383 throw new ArgumentOutOfRangeException(nameof(length));
385 if (Length == length && startIndex == 0)
393 var src = _chars.Slice(startIndex + length);
394 var dst = _chars.Slice(startIndex);
408 [MethodImpl(MethodImplOptions.NoInlining)]
409 private void Grow(
int additionalCapacityBeyondPos)
411 Debug.Assert(additionalCapacityBeyondPos > 0);
412 Debug.Assert(_pos > _chars.Length - additionalCapacityBeyondPos,
"Grow called incorrectly, no resize is needed.");
414 const uint ArrayMaxLength = 0x7FFFFFC7;
418 int newCapacity = (int)Math.Max(
419 (uint)(_pos + additionalCapacityBeyondPos),
420 Math.Min((uint)_chars.Length * 2, ArrayMaxLength));
424 var poolArray = ArrayPool<char>.Shared.Rent(newCapacity);
426 _chars.Slice(0, _pos).CopyTo(poolArray);
428 var toReturn = _arrayToReturnToPool;
429 _chars = _arrayToReturnToPool = poolArray;
430 if (toReturn !=
null)
431 ArrayPool<char>.Shared.Return(toReturn);
437 [MethodImpl(MethodImplOptions.AggressiveInlining)]
438 public void Dispose()
440 var toReturn = _arrayToReturnToPool;
442 if (toReturn !=
null)
443 ArrayPool<char>.Shared.Return(toReturn);