зеркало из https://github.com/dotnet/razor.git
Add MemoryBuilder<T> helper
This commit is contained in:
Родитель
8d9b438270
Коммит
aed8cfaa5c
|
@ -0,0 +1,90 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the MIT license. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Buffers;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Razor;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Temporary builder that uses <see cref="ArrayPool{T}"/> to back a <see cref="Memory{T}"/>.
|
||||||
|
/// </summary>
|
||||||
|
internal ref struct MemoryBuilder<T>
|
||||||
|
{
|
||||||
|
private Memory<T> _memory;
|
||||||
|
private T[]? _arrayFromPool;
|
||||||
|
private int _index;
|
||||||
|
|
||||||
|
public MemoryBuilder(int initialCapacity = 1)
|
||||||
|
{
|
||||||
|
ArgHelper.ThrowIfNegativeOrZero(initialCapacity);
|
||||||
|
_arrayFromPool = ArrayPool<T>.Shared.Rent(initialCapacity);
|
||||||
|
_memory = _arrayFromPool;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
var toReturn = _arrayFromPool;
|
||||||
|
if (toReturn is not null)
|
||||||
|
{
|
||||||
|
_arrayFromPool = null;
|
||||||
|
ArrayPool<T>.Shared.Return(toReturn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly ReadOnlyMemory<T> AsMemory()
|
||||||
|
=> _memory[.._index];
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void Append(T item)
|
||||||
|
{
|
||||||
|
var index = _index;
|
||||||
|
|
||||||
|
var memory = _memory;
|
||||||
|
if ((uint)index < (uint)memory.Length)
|
||||||
|
{
|
||||||
|
memory.Span[index] = item;
|
||||||
|
_index = index + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AppendWithResize(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
|
private void AppendWithResize(T item)
|
||||||
|
{
|
||||||
|
Debug.Assert(_index == _memory.Length);
|
||||||
|
var index = _index;
|
||||||
|
Grow(1);
|
||||||
|
_memory.Span[index] = item;
|
||||||
|
_index = index + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Grow(int additionalCapacityRequired = 1)
|
||||||
|
{
|
||||||
|
const int ArrayMaxLength = 0x7FFFFFC7; // same as Array.MaxLength
|
||||||
|
|
||||||
|
var nextCapacity = Math.Max(_memory.Length != 0 ? _memory.Length * 2 : 4, _memory.Length + additionalCapacityRequired);
|
||||||
|
|
||||||
|
if ((uint)nextCapacity > ArrayMaxLength)
|
||||||
|
{
|
||||||
|
nextCapacity = Math.Max(Math.Max(_memory.Length + 1, ArrayMaxLength), _memory.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
var newArray = ArrayPool<T>.Shared.Rent(nextCapacity);
|
||||||
|
_memory.Span.CopyTo(newArray);
|
||||||
|
|
||||||
|
var toReturn = _arrayFromPool;
|
||||||
|
_memory = newArray;
|
||||||
|
_arrayFromPool = newArray;
|
||||||
|
|
||||||
|
if (toReturn != null)
|
||||||
|
{
|
||||||
|
ArrayPool<T>.Shared.Return(toReturn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Загрузка…
Ссылка в новой задаче