/
aprogrammer
/
yessql
Обзор
Документация
Войти
/
aprogrammer
/
yessql
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/YesSql.Core/Utils/RentedStringBuilder.cs
233 строки
7 KB
Mike Alhayek
Code Cleanup (#507)
09 ноя 2023, 03:32
Не верифицирован
09 ноя 2023, 03:32
dabecfb
Код
Авторство
О чём код?
// Inspired from https://raw.githubusercontent.com/dotnet/runtime/59c592cc8d2778bcc6173baa2b25b13190e42990/src/libraries/Common/src/System/Text/ValueStringBuilder.cs using System; using System.Buffers; using System.Diagnostics; using System.Runtime.CompilerServices; namespace YesSql.Utils { public class RentedStringBuilder : IStringBuilder { private char[] _arrayToReturnToPool; private char[] _chars; private int _pos; public RentedStringBuilder(char[] initialBuffer) { _arrayToReturnToPool = null; _chars = initialBuffer; _pos = 0; } public RentedStringBuilder(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; } } public int Capacity => _chars.Length; public void EnsureCapacity(int capacity) { // This is not expected to be called this with negative capacity Debug.Assert(capacity >= 0); // If the caller has a bug and calls this with negative capacity, make sure to call Grow to throw an exception. if ((uint)capacity > (uint)_chars.Length) Grow(capacity - _pos); } public ref char this[int index] { get { Debug.Assert(index < _pos); return ref _chars[index]; } } public override string ToString() { string s = _chars.AsSpan(0, _pos).ToString(); return s; } public ReadOnlySpan<char> AsSpan() => _chars.AsSpan(0, _pos); public ReadOnlySpan<char> AsSpan(int start) => _chars.AsSpan(start, _pos - start); public ReadOnlySpan<char> AsSpan(int start, int length) => _chars.AsSpan(start, length); public bool TryCopyTo(Span<char> destination, out int charsWritten) { if (_chars.AsSpan(0, _pos).TryCopyTo(destination)) { charsWritten = _pos; Clear(); return true; } else { charsWritten = 0; Clear(); return false; } } public void Insert(int index, char value, int count) { if (_pos > _chars.Length - count) { Grow(count); } var remaining = _pos - index; _chars.AsSpan(index, remaining).CopyTo(_chars.AsSpan(index + count)); _chars.AsSpan(index, count).Fill(value); _pos += count; } public void Insert(int index, string s) { if (s == null) { return; } var count = s.Length; if (_pos > (_chars.Length - count)) { Grow(count); } var remaining = _pos - index; _chars.AsSpan(index, remaining).CopyTo(_chars.AsSpan(index + count)); s.AsSpan().CopyTo(_chars.AsSpan(index)); _pos += count; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Append(char c) { var pos = _pos; if ((uint)pos < (uint)_chars.Length) { _chars[pos] = c; _pos = pos + 1; } else { GrowAndAppend(c); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Append(string s) { if (s == null) { return; } var pos = _pos; 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; } else { AppendSlow(s); } } private void AppendSlow(string s) { var pos = _pos; if (pos > _chars.Length - s.Length) { Grow(s.Length); } s.AsSpan().CopyTo(_chars.AsSpan(pos)); _pos += s.Length; } public void Append(ReadOnlySpan<char> value) { var pos = _pos; if (pos > _chars.Length - value.Length) { Grow(value.Length); } value.CopyTo(_chars.AsSpan(_pos)); _pos += value.Length; } [MethodImpl(MethodImplOptions.NoInlining)] private void GrowAndAppend(char c) { Grow(1); Append(c); } /// <summary> /// Resize the internal buffer either by doubling current buffer size or /// by adding <paramref name="additionalCapacityBeyondPos"/> to /// <see cref="_pos"/> whichever is greater. /// </summary> /// <param name="additionalCapacityBeyondPos"> /// Number of chars requested beyond current position. /// </param> [MethodImpl(MethodImplOptions.NoInlining)] private void Grow(int additionalCapacityBeyondPos) { Debug.Assert(additionalCapacityBeyondPos > 0); Debug.Assert(_pos > _chars.Length - additionalCapacityBeyondPos, "Grow called incorrectly, no resize is needed."); // Make sure to let Rent throw an exception if the caller has a bug and the desired capacity is negative var poolArray = ArrayPool<char>.Shared.Rent((int)Math.Max((uint)(_pos + additionalCapacityBeyondPos), (uint)_chars.Length * 2)); _chars.AsSpan(0, _pos).CopyTo(poolArray); var toReturn = _arrayToReturnToPool; _chars = _arrayToReturnToPool = poolArray; if (toReturn != null) { ArrayPool<char>.Shared.Return(toReturn); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Clear() { _pos = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Dispose() { var toReturn = _arrayToReturnToPool; if (toReturn != null) { ArrayPool<char>.Shared.Return(toReturn); } _pos = 0; _chars = null; } } }