diff options
Diffstat (limited to 'src/System.Private.CoreLib/shared/System/Text/ValueStringBuilder.cs')
-rw-r--r-- | src/System.Private.CoreLib/shared/System/Text/ValueStringBuilder.cs | 60 |
1 files changed, 55 insertions, 5 deletions
diff --git a/src/System.Private.CoreLib/shared/System/Text/ValueStringBuilder.cs b/src/System.Private.CoreLib/shared/System/Text/ValueStringBuilder.cs index 18d564867..74b5dacf9 100644 --- a/src/System.Private.CoreLib/shared/System/Text/ValueStringBuilder.cs +++ b/src/System.Private.CoreLib/shared/System/Text/ValueStringBuilder.cs @@ -9,7 +9,7 @@ using System.Runtime.InteropServices; namespace System.Text { - internal ref struct ValueStringBuilder + internal ref partial struct ValueStringBuilder { private char[] _arrayToReturnToPool; private Span<char> _chars; @@ -22,11 +22,19 @@ namespace System.Text _pos = 0; } + public ValueStringBuilder(int initialCapacity) + { + _arrayToReturnToPool = ArrayPool<char>.Shared.Rent(initialCapacity); + _chars = _arrayToReturnToPool; + _pos = 0; + } + public int Length { get => _pos; set { + Debug.Assert(value >= 0); Debug.Assert(value <= _chars.Length); _pos = value; } @@ -40,7 +48,30 @@ namespace System.Text Grow(capacity - _chars.Length); } - public ref char GetPinnableReference() => ref MemoryMarshal.GetReference(_chars); + /// <summary> + /// Get a pinnable reference to the builder. + /// Does not ensure there is a null char after <see cref="Length"/> + /// This overload is pattern matched in the C# 7.3+ compiler so you can omit + /// the explicit method call, and write eg "fixed (char* c = builder)" + /// </summary> + public ref char GetPinnableReference() + { + return ref MemoryMarshal.GetReference(_chars); + } + + /// <summary> + /// Get a pinnable reference to the builder. + /// </summary> + /// <param name="terminate">Ensures that the builder has a null char after <see cref="Length"/></param> + public ref char GetPinnableReference(bool terminate) + { + if (terminate) + { + EnsureCapacity(Length + 1); + _chars[Length] = '\0'; + } + return ref MemoryMarshal.GetReference(_chars); + } public ref char this[int index] { @@ -53,12 +84,31 @@ namespace System.Text public override string ToString() { - var s = new string(_chars.Slice(0, _pos)); + var s = _chars.Slice(0, _pos).ToString(); Dispose(); return s; } + /// <summary>Returns the underlying storage of the builder.</summary> + public Span<char> RawChars => _chars; + + /// <summary> + /// Returns a span around the contents of the builder. + /// </summary> + /// <param name="terminate">Ensures that the builder has a null char after <see cref="Length"/></param> + public ReadOnlySpan<char> AsSpan(bool terminate) + { + if (terminate) + { + EnsureCapacity(Length + 1); + _chars[Length] = '\0'; + } + return _chars.Slice(0, _pos); + } + public ReadOnlySpan<char> AsSpan() => _chars.Slice(0, _pos); + public ReadOnlySpan<char> AsSpan(int start) => _chars.Slice(start, _pos - start); + public ReadOnlySpan<char> AsSpan(int start, int length) => _chars.Slice(start, length); public bool TryCopyTo(Span<char> destination, out int charsWritten) { @@ -93,7 +143,7 @@ namespace System.Text public void Append(char c) { int pos = _pos; - if (pos < _chars.Length) + if ((uint)pos < (uint)_chars.Length) { _chars[pos] = c; _pos = pos + 1; @@ -108,7 +158,7 @@ namespace System.Text public void Append(string s) { int pos = _pos; - if (s.Length == 1 && pos < _chars.Length) // very common case, e.g. appending strings from NumberFormatInfo like separators, percent symbols, etc. + if (s.Length == 1 && (uint)pos < (uint)_chars.Length) // very common case, e.g. appending strings from NumberFormatInfo like separators, percent symbols, etc. { _chars[pos] = s[0]; _pos = pos + 1; |