Update NETStandard2.1 APIs (#17080)
[mono-project.git] / mcs / class / corlib / corefx / ArrayBufferWriter.cs
blob9a6736bf235fa1389a0b5ffb9a6a39e6679f4baa
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
5 using System.Diagnostics;
7 namespace System.Buffers
9 /// <summary>
10 /// Represents a heap-based, array-backed output sink into which <typeparam name="T"/> data can be written.
11 /// </summary>
12 public sealed class ArrayBufferWriter<T> : IBufferWriter<T>
14 private T[] _buffer;
15 private int _index;
17 private const int DefaultInitialBufferSize = 256;
19 /// <summary>
20 /// Creates an instance of an <see cref="ArrayBufferWriter{T}"/>, in which data can be written to,
21 /// with the default initial capacity.
22 /// </summary>
23 public ArrayBufferWriter()
25 _buffer = Array.Empty<T>();
26 _index = 0;
29 /// <summary>
30 /// Creates an instance of an <see cref="ArrayBufferWriter{T}"/>, in which data can be written to,
31 /// with an initial capacity specified.
32 /// </summary>
33 /// <param name="initialCapacity">The minimum capacity with which to initialize the underlying buffer.</param>
34 /// <exception cref="ArgumentException">
35 /// Thrown when <paramref name="initialCapacity"/> is not positive (i.e. less than or equal to 0).
36 /// </exception>
37 public ArrayBufferWriter(int initialCapacity)
39 if (initialCapacity <= 0)
40 throw new ArgumentException(nameof(initialCapacity));
42 _buffer = new T[initialCapacity];
43 _index = 0;
46 /// <summary>
47 /// Returns the data written to the underlying buffer so far, as a <see cref="ReadOnlyMemory{T}"/>.
48 /// </summary>
49 public ReadOnlyMemory<T> WrittenMemory => _buffer.AsMemory(0, _index);
51 /// <summary>
52 /// Returns the data written to the underlying buffer so far, as a <see cref="ReadOnlySpan{T}"/>.
53 /// </summary>
54 public ReadOnlySpan<T> WrittenSpan => _buffer.AsSpan(0, _index);
56 /// <summary>
57 /// Returns the amount of data written to the underlying buffer so far.
58 /// </summary>
59 public int WrittenCount => _index;
61 /// <summary>
62 /// Returns the total amount of space within the underlying buffer.
63 /// </summary>
64 public int Capacity => _buffer.Length;
66 /// <summary>
67 /// Returns the amount of space available that can still be written into without forcing the underlying buffer to grow.
68 /// </summary>
69 public int FreeCapacity => _buffer.Length - _index;
71 /// <summary>
72 /// Clears the data written to the underlying buffer.
73 /// </summary>
74 /// <remarks>
75 /// You must clear the <see cref="ArrayBufferWriter{T}"/> before trying to re-use it.
76 /// </remarks>
77 public void Clear()
79 Debug.Assert(_buffer.Length >= _index);
80 _buffer.AsSpan(0, _index).Clear();
81 _index = 0;
84 /// <summary>
85 /// 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}"/>
86 /// </summary>
87 /// <exception cref="ArgumentException">
88 /// Thrown when <paramref name="count"/> is negative.
89 /// </exception>
90 /// <exception cref="InvalidOperationException">
91 /// Thrown when attempting to advance past the end of the underlying buffer.
92 /// </exception>
93 /// <remarks>
94 /// You must request a new buffer after calling Advance to continue writing more data and cannot write to a previously acquired buffer.
95 /// </remarks>
96 public void Advance(int count)
98 if (count < 0)
99 throw new ArgumentException(nameof(count));
101 if (_index > _buffer.Length - count)
102 ThrowInvalidOperationException_AdvancedTooFar(_buffer.Length);
104 _index += count;
107 /// <summary>
108 /// Returns a <see cref="Memory{T}"/> to write to that is at least the requested length (specified by <paramref name="sizeHint"/>).
109 /// If no <paramref name="sizeHint"/> is provided (or it's equal to <code>0</code>), some non-empty buffer is returned.
110 /// </summary>
111 /// <exception cref="ArgumentException">
112 /// Thrown when <paramref name="sizeHint"/> is negative.
113 /// </exception>
114 /// <remarks>
115 /// This will never return an empty <see cref="Memory{T}"/>.
116 /// </remarks>
117 /// <remarks>
118 /// There is no guarantee that successive calls will return the same buffer or the same-sized buffer.
119 /// </remarks>
120 /// <remarks>
121 /// You must request a new buffer after calling Advance to continue writing more data and cannot write to a previously acquired buffer.
122 /// </remarks>
123 public Memory<T> GetMemory(int sizeHint = 0)
125 CheckAndResizeBuffer(sizeHint);
126 Debug.Assert(_buffer.Length > _index);
127 return _buffer.AsMemory(_index);
130 /// <summary>
131 /// Returns a <see cref="Span{T}"/> to write to that is at least the requested length (specified by <paramref name="sizeHint"/>).
132 /// If no <paramref name="sizeHint"/> is provided (or it's equal to <code>0</code>), some non-empty buffer is returned.
133 /// </summary>
134 /// <exception cref="ArgumentException">
135 /// Thrown when <paramref name="sizeHint"/> is negative.
136 /// </exception>
137 /// <remarks>
138 /// This will never return an empty <see cref="Span{T}"/>.
139 /// </remarks>
140 /// <remarks>
141 /// There is no guarantee that successive calls will return the same buffer or the same-sized buffer.
142 /// </remarks>
143 /// <remarks>
144 /// You must request a new buffer after calling Advance to continue writing more data and cannot write to a previously acquired buffer.
145 /// </remarks>
146 public Span<T> GetSpan(int sizeHint = 0)
148 CheckAndResizeBuffer(sizeHint);
149 Debug.Assert(_buffer.Length > _index);
150 return _buffer.AsSpan(_index);
153 private void CheckAndResizeBuffer(int sizeHint)
155 if (sizeHint < 0)
156 throw new ArgumentException(nameof(sizeHint));
158 if (sizeHint == 0)
160 sizeHint = 1;
163 if (sizeHint > FreeCapacity)
165 int growBy = Math.Max(sizeHint, _buffer.Length);
167 if (_buffer.Length == 0)
169 growBy = Math.Max(growBy, DefaultInitialBufferSize);
172 int newSize = checked(_buffer.Length + growBy);
174 Array.Resize(ref _buffer, newSize);
177 Debug.Assert(FreeCapacity > 0 && FreeCapacity >= sizeHint);
180 private static void ThrowInvalidOperationException_AdvancedTooFar(int capacity)
182 throw new InvalidOperationException(SR.Format(SR.BufferWriterAdvancedTooFar, capacity));