1010using System . Runtime . InteropServices ;
1111using Microsoft . Toolkit . HighPerformance . Buffers . Views ;
1212using Microsoft . Toolkit . HighPerformance . Extensions ;
13+ using Microsoft . Toolkit . HighPerformance . Helpers . Internals ;
1314
1415namespace Microsoft . Toolkit . HighPerformance . Buffers
1516{
@@ -233,15 +234,15 @@ public void Advance(int count)
233234 /// <inheritdoc/>
234235 public Memory < T > GetMemory ( int sizeHint = 0 )
235236 {
236- CheckAndResizeBuffer ( sizeHint ) ;
237+ CheckBufferAndEnsureCapacity ( sizeHint ) ;
237238
238239 return this . array . AsMemory ( this . index ) ;
239240 }
240241
241242 /// <inheritdoc/>
242243 public Span < T > GetSpan ( int sizeHint = 0 )
243244 {
244- CheckAndResizeBuffer ( sizeHint ) ;
245+ CheckBufferAndEnsureCapacity ( sizeHint ) ;
245246
246247 return this . array . AsSpan ( this . index ) ;
247248 }
@@ -251,7 +252,7 @@ public Span<T> GetSpan(int sizeHint = 0)
251252 /// </summary>
252253 /// <param name="sizeHint">The minimum number of items to ensure space for in <see cref="array"/>.</param>
253254 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
254- private void CheckAndResizeBuffer ( int sizeHint )
255+ private void CheckBufferAndEnsureCapacity ( int sizeHint )
255256 {
256257 if ( this . array is null )
257258 {
@@ -268,12 +269,32 @@ private void CheckAndResizeBuffer(int sizeHint)
268269 sizeHint = 1 ;
269270 }
270271
271- if ( sizeHint > FreeCapacity )
272+ if ( sizeHint > array ! . Length - this . index )
272273 {
273- int minimumSize = this . index + sizeHint ;
274+ ResizeBuffer ( sizeHint ) ;
275+ }
276+ }
274277
275- this . pool . Resize ( ref this . array , minimumSize ) ;
278+ /// <summary>
279+ /// Resizes <see cref="array"/> to ensure it can fit the specified number of new items.
280+ /// </summary>
281+ /// <param name="sizeHint">The minimum number of items to ensure space for in <see cref="array"/>.</param>
282+ [ MethodImpl ( MethodImplOptions . NoInlining ) ]
283+ private void ResizeBuffer ( int sizeHint )
284+ {
285+ int minimumSize = this . index + sizeHint ;
286+
287+ // The ArrayPool<T> class has a maximum threshold of 1024 * 1024 for the maximum length of
288+ // pooled arrays, and once this is exceeded it will just allocate a new array every time
289+ // of exactly the requested size. In that case, we manually round up the requested size to
290+ // the nearest power of two, to ensure that repeated consecutive writes when the array in
291+ // use is bigger than that threshold don't end up causing a resize every single time.
292+ if ( minimumSize > 1024 * 1024 )
293+ {
294+ minimumSize = BitOperations . RoundUpPowerOfTwo ( minimumSize ) ;
276295 }
296+
297+ this . pool . Resize ( ref this . array , minimumSize ) ;
277298 }
278299
279300 /// <inheritdoc/>
0 commit comments