You've already forked linux-packaging-mono
Imported Upstream version 6.6.0.103
Former-commit-id: ed8637df0061cb6f128ae1d26d26db7734e0fa0d
This commit is contained in:
parent
53ae335b9c
commit
9b1ef54dc9
185
mcs/class/corlib/corefx/ArrayBufferWriter.cs
Normal file
185
mcs/class/corlib/corefx/ArrayBufferWriter.cs
Normal file
@ -0,0 +1,185 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace System.Buffers
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a heap-based, array-backed output sink into which <typeparam name="T"/> data can be written.
|
||||
/// </summary>
|
||||
public sealed class ArrayBufferWriter<T> : IBufferWriter<T>
|
||||
{
|
||||
private T[] _buffer;
|
||||
private int _index;
|
||||
|
||||
private const int DefaultInitialBufferSize = 256;
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of an <see cref="ArrayBufferWriter{T}"/>, in which data can be written to,
|
||||
/// with the default initial capacity.
|
||||
/// </summary>
|
||||
public ArrayBufferWriter()
|
||||
{
|
||||
_buffer = Array.Empty<T>();
|
||||
_index = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of an <see cref="ArrayBufferWriter{T}"/>, in which data can be written to,
|
||||
/// with an initial capacity specified.
|
||||
/// </summary>
|
||||
/// <param name="initialCapacity">The minimum capacity with which to initialize the underlying buffer.</param>
|
||||
/// <exception cref="ArgumentException">
|
||||
/// Thrown when <paramref name="initialCapacity"/> is not positive (i.e. less than or equal to 0).
|
||||
/// </exception>
|
||||
public ArrayBufferWriter(int initialCapacity)
|
||||
{
|
||||
if (initialCapacity <= 0)
|
||||
throw new ArgumentException(nameof(initialCapacity));
|
||||
|
||||
_buffer = new T[initialCapacity];
|
||||
_index = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the data written to the underlying buffer so far, as a <see cref="ReadOnlyMemory{T}"/>.
|
||||
/// </summary>
|
||||
public ReadOnlyMemory<T> WrittenMemory => _buffer.AsMemory(0, _index);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the data written to the underlying buffer so far, as a <see cref="ReadOnlySpan{T}"/>.
|
||||
/// </summary>
|
||||
public ReadOnlySpan<T> WrittenSpan => _buffer.AsSpan(0, _index);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the amount of data written to the underlying buffer so far.
|
||||
/// </summary>
|
||||
public int WrittenCount => _index;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the total amount of space within the underlying buffer.
|
||||
/// </summary>
|
||||
public int Capacity => _buffer.Length;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the amount of space available that can still be written into without forcing the underlying buffer to grow.
|
||||
/// </summary>
|
||||
public int FreeCapacity => _buffer.Length - _index;
|
||||
|
||||
/// <summary>
|
||||
/// Clears the data written to the underlying buffer.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// You must clear the <see cref="ArrayBufferWriter{T}"/> before trying to re-use it.
|
||||
/// </remarks>
|
||||
public void Clear()
|
||||
{
|
||||
Debug.Assert(_buffer.Length >= _index);
|
||||
_buffer.AsSpan(0, _index).Clear();
|
||||
_index = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Notifies <see cref="IBufferWriter{T}"/> that <paramref name="count"/> amount of data was written to the output <see cref="Span{T}"/>/<see cref="Memory{T}"/>
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentException">
|
||||
/// Thrown when <paramref name="count"/> is negative.
|
||||
/// </exception>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// Thrown when attempting to advance past the end of the underlying buffer.
|
||||
/// </exception>
|
||||
/// <remarks>
|
||||
/// You must request a new buffer after calling Advance to continue writing more data and cannot write to a previously acquired buffer.
|
||||
/// </remarks>
|
||||
public void Advance(int count)
|
||||
{
|
||||
if (count < 0)
|
||||
throw new ArgumentException(nameof(count));
|
||||
|
||||
if (_index > _buffer.Length - count)
|
||||
ThrowInvalidOperationException_AdvancedTooFar(_buffer.Length);
|
||||
|
||||
_index += count;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a <see cref="Memory{T}"/> to write to that is at least the requested length (specified by <paramref name="sizeHint"/>).
|
||||
/// If no <paramref name="sizeHint"/> is provided (or it's equal to <code>0</code>), some non-empty buffer is returned.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentException">
|
||||
/// Thrown when <paramref name="sizeHint"/> is negative.
|
||||
/// </exception>
|
||||
/// <remarks>
|
||||
/// This will never return an empty <see cref="Memory{T}"/>.
|
||||
/// </remarks>
|
||||
/// <remarks>
|
||||
/// There is no guarantee that successive calls will return the same buffer or the same-sized buffer.
|
||||
/// </remarks>
|
||||
/// <remarks>
|
||||
/// You must request a new buffer after calling Advance to continue writing more data and cannot write to a previously acquired buffer.
|
||||
/// </remarks>
|
||||
public Memory<T> GetMemory(int sizeHint = 0)
|
||||
{
|
||||
CheckAndResizeBuffer(sizeHint);
|
||||
Debug.Assert(_buffer.Length > _index);
|
||||
return _buffer.AsMemory(_index);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a <see cref="Span{T}"/> to write to that is at least the requested length (specified by <paramref name="sizeHint"/>).
|
||||
/// If no <paramref name="sizeHint"/> is provided (or it's equal to <code>0</code>), some non-empty buffer is returned.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentException">
|
||||
/// Thrown when <paramref name="sizeHint"/> is negative.
|
||||
/// </exception>
|
||||
/// <remarks>
|
||||
/// This will never return an empty <see cref="Span{T}"/>.
|
||||
/// </remarks>
|
||||
/// <remarks>
|
||||
/// There is no guarantee that successive calls will return the same buffer or the same-sized buffer.
|
||||
/// </remarks>
|
||||
/// <remarks>
|
||||
/// You must request a new buffer after calling Advance to continue writing more data and cannot write to a previously acquired buffer.
|
||||
/// </remarks>
|
||||
public Span<T> GetSpan(int sizeHint = 0)
|
||||
{
|
||||
CheckAndResizeBuffer(sizeHint);
|
||||
Debug.Assert(_buffer.Length > _index);
|
||||
return _buffer.AsSpan(_index);
|
||||
}
|
||||
|
||||
private void CheckAndResizeBuffer(int sizeHint)
|
||||
{
|
||||
if (sizeHint < 0)
|
||||
throw new ArgumentException(nameof(sizeHint));
|
||||
|
||||
if (sizeHint == 0)
|
||||
{
|
||||
sizeHint = 1;
|
||||
}
|
||||
|
||||
if (sizeHint > FreeCapacity)
|
||||
{
|
||||
int growBy = Math.Max(sizeHint, _buffer.Length);
|
||||
|
||||
if (_buffer.Length == 0)
|
||||
{
|
||||
growBy = Math.Max(growBy, DefaultInitialBufferSize);
|
||||
}
|
||||
|
||||
int newSize = checked(_buffer.Length + growBy);
|
||||
|
||||
Array.Resize(ref _buffer, newSize);
|
||||
}
|
||||
|
||||
Debug.Assert(FreeCapacity > 0 && FreeCapacity >= sizeHint);
|
||||
}
|
||||
|
||||
private static void ThrowInvalidOperationException_AdvancedTooFar(int capacity)
|
||||
{
|
||||
throw new InvalidOperationException(SR.Format(SR.BufferWriterAdvancedTooFar, capacity));
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user