/
aprogrammer
/
reverse-proxy-ms-yarp
Обзор
Документация
Войти
/
aprogrammer
/
reverse-proxy-ms-yarp
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/ReverseProxy/Utilities/ValueStringBuilder.cs
159 строк
4 KB
Miha Zupan
Use SearchValues in `RequestUtilities.EncodePath` (#2267)
03 окт 2023, 20:52
Не верифицирован
03 окт 2023, 20:52
26fc382
Код
Авторство
О чём код?
// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using System; using System.Buffers; using System.Diagnostics; using System.Globalization; using System.Runtime.CompilerServices; namespace Yarp.ReverseProxy.Utilities; // Adapted from https://github.com/dotnet/runtime/blob/82fee2692b3954ba8903fa4764f1f4e36a26341a/src/libraries/Common/src/System/Text/ValueStringBuilder.cs internal ref partial struct ValueStringBuilder { public const int StackallocThreshold = 512; private char[]? _arrayToReturnToPool; private Span<char> _chars; private int _pos; public ValueStringBuilder(Span<char> initialBuffer) { _arrayToReturnToPool = null; _chars = initialBuffer; _pos = 0; } public int Length { get => _pos; set { Debug.Assert(value >= 0); Debug.Assert(value <= _chars.Length); _pos = value; } } public override string ToString() { var s = _chars.Slice(0, _pos).ToString(); Dispose(); return s; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Append(char c) { var pos = _pos; var chars = _chars; 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 is null) { return; } var pos = _pos; if (pos > _chars.Length - s.Length) { Grow(s.Length); } s.CopyTo(_chars.Slice(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.Slice(_pos)); _pos += value.Length; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Append(int i) { var pos = _pos; if (i.TryFormat(_chars.Slice(pos), out var charsWritten, default, null)) { _pos = pos + charsWritten; } else { Append(i.ToString(CultureInfo.InvariantCulture)); } } [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."); const uint ArrayMaxLength = 0x7FFFFFC7; // same as Array.MaxLength // Increase to at least the required size (_pos + additionalCapacityBeyondPos), but try // to double the size if possible, bounding the doubling to not go beyond the max array length. var newCapacity = (int)Math.Max( (uint)(_pos + additionalCapacityBeyondPos), Math.Min((uint)_chars.Length * 2, ArrayMaxLength)); // Make sure to let Rent throw an exception if the caller has a bug and the desired capacity is negative. // This could also go negative if the actual required length wraps around. var poolArray = ArrayPool<char>.Shared.Rent(newCapacity); _chars.Slice(0, _pos).CopyTo(poolArray); var toReturn = _arrayToReturnToPool; _chars = _arrayToReturnToPool = poolArray; if (toReturn is not null) { ArrayPool<char>.Shared.Return(toReturn); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Dispose() { var toReturn = _arrayToReturnToPool; this = default; // for safety, to avoid using pooled array if this instance is erroneously appended to again if (toReturn is not null) { ArrayPool<char>.Shared.Return(toReturn); } } }