| File: System\Collections\Generic\ArrayBuilder.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. namespace System.Collections.Generic; /// <summary> /// Array based collection that tries to avoid copying the internal array and caps the maximum capacity. /// </summary> /// <remarks> /// <para> /// To mitigate corrupted length attacks, the backing array has an initial allocation size cap. /// </para> /// </remarks> internal class ArrayBuilder<T> { private const int MaxInitialArrayLength = 1024 * 10; private T[] _items; private readonly int _maxCount; private int _count; /// <param name="expectedCount"> /// The <see cref="_count"/> cannot grow past this value and is expected to be this value /// when the collection is "finished". /// </param> internal ArrayBuilder(int expectedCount) { _items = new T[Math.Min(expectedCount, MaxInitialArrayLength)]; _maxCount = expectedCount; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Add(T item) { T[] array = _items; int count = _count; if ((uint)count < (uint)_items.Length) { _count = count + 1; array[count] = item; } else { AddWithResize(item); } } private void AddWithResize(T item) { if (_items.Length == _maxCount) { throw new ArgumentOutOfRangeException(nameof(item), "Collection is at max capacity."); } Debug.Assert(_count == _items.Length); int size = _count; Debug.Assert(_items.Length > 0); int newCapacity = Math.Min(_maxCount, 2 * _items.Length); Array.Resize(ref _items, newCapacity); _count = size + 1; _items[size] = item; } public T[] ToArray() { Debug.Assert(_count == _maxCount); Debug.Assert(_count == _items.Length); return _items; } }