| File: System\BufferScope.cs | Web Access |
| Project: src\winforms\src\System.Private.Windows.Core\src\Microsoft.Private.Windows.Core.csproj (Microsoft.Private.Windows.Core) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Buffers; namespace System; /// <summary> /// Allows renting a buffer from <see cref="ArrayPool{T}"/> with a using statement. Can be used directly as if it /// were a <see cref="Span{T}"/>. /// </summary> /// <remarks> /// <para> /// Buffers are not cleared and as such their initial contents will be random. /// </para> /// </remarks> internal ref struct BufferScope<T> { private T[]? _array; private Span<T> _span; public BufferScope(int minimumLength) { _array = ArrayPool<T>.Shared.Rent(minimumLength); _span = _array; } /// <summary> /// Create the <see cref="BufferScope{T}"/> with an initial buffer. Useful for creating with an initial stack /// allocated buffer. /// </summary> public BufferScope(Span<T> initialBuffer) { _array = null; _span = initialBuffer; } /// <summary> /// Create the <see cref="BufferScope{T}"/> with an initial buffer. Useful for creating with an initial stack /// allocated buffer. /// </summary> /// <remarks> /// <para> /// <example> /// <para>Creating with a stack allocated buffer:</para> /// <code>using BufferScope<char> buffer = new(stackalloc char[64]);</code> /// </example> /// </para> /// <para> /// Stack allocated buffers should be kept small to avoid overflowing the stack. /// </para> /// </remarks> /// <param name="minimumLength"> /// The required minimum length. If the <paramref name="initialBuffer"/> is not large enough, this will rent from /// the shared <see cref="ArrayPool{T}"/>. /// </param> public BufferScope(Span<T> initialBuffer, int minimumLength) { if (initialBuffer.Length >= minimumLength) { _array = null; _span = initialBuffer; } else { _array = ArrayPool<T>.Shared.Rent(minimumLength); _span = _array; } } /// <summary> /// Ensure that the buffer has enough space for <paramref name="capacity"/> number of elements. /// </summary> /// <remarks> /// <para> /// Consider if creating new <see cref="BufferScope{T}"/> instances is possible and cleaner than using /// this method. /// </para> /// </remarks> /// <param name="copy">True to copy the existing elements when new space is allocated.</param> public unsafe void EnsureCapacity(int capacity, bool copy = false) { if (_span!.Length >= capacity) { return; } T[] newArray = ArrayPool<T>.Shared.Rent(capacity); if (copy) { _span.CopyTo(newArray); } if (_array is not null) { ArrayPool<T>.Shared.Return(_array); } _array = newArray; _span = _array; } public ref T this[int i] => ref _span[i]; public readonly Span<T> this[Range range] => _span[range]; public readonly Span<T> Slice(int start, int length) => _span.Slice(start, length); public readonly ref T GetPinnableReference() => ref MemoryMarshal.GetReference(_span); public readonly int Length => _span.Length; public readonly Span<T> AsSpan() => _span; public static implicit operator Span<T>(BufferScope<T> scope) => scope._span; public static implicit operator ReadOnlySpan<T>(BufferScope<T> scope) => scope._span; public void Dispose() { if (_array is not null) { ArrayPool<T>.Shared.Return(_array); } _array = default; } public override readonly string ToString() => _span.ToString(); }