// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Runtime.CompilerServices; namespace Microsoft.AspNetCore.Blazor.RenderTree { /// /// Implements a list that uses an array of objects to store the elements. /// internal class ArrayBuilder { private const int MinCapacity = 10; private T[] _items; private int _itemsInUse; /// /// Constructs a new instance of . /// public ArrayBuilder() : this(MinCapacity) { } /// /// Constructs a new instance of . /// public ArrayBuilder(int capacity) { _items = new T[capacity < MinCapacity ? MinCapacity : capacity]; _itemsInUse = 0; } /// /// Gets the number of items. /// public int Count => _itemsInUse; /// /// Gets the underlying buffer. /// public T[] Buffer => _items; /// /// Appends a new item, automatically resizing the underlying array if necessary. /// /// The item to append. [MethodImpl(MethodImplOptions.AggressiveInlining)] // Just like System.Collections.Generic.List public void Append(in T item) { if (_itemsInUse == _items.Length) { SetCapacity(_itemsInUse * 2, preserveContents: true); } _items[_itemsInUse++] = item; } /// /// Removes the last item. /// public void RemoveLast() { _itemsInUse--; _items[_itemsInUse] = default(T); // Release to GC } /// /// Marks the array as empty, also shrinking the underlying storage if it was /// not being used to near its full capacity. /// public void Clear() { var previousItemsInUse = _itemsInUse; _itemsInUse = 0; if (_items.Length > previousItemsInUse * 1.5) { SetCapacity((previousItemsInUse + _items.Length) / 2, preserveContents: false); } else { Array.Clear(_items, 0, _itemsInUse); // Release to GC } } /// /// Produces an structure describing the current contents. /// /// The . public ArrayRange ToRange() => new ArrayRange(_items, _itemsInUse); private void SetCapacity(int desiredCapacity, bool preserveContents) { if (desiredCapacity < _itemsInUse) { throw new ArgumentOutOfRangeException(nameof(desiredCapacity), $"The value cannot be less than {nameof(Count)}"); } var newCapacity = desiredCapacity < MinCapacity ? MinCapacity : desiredCapacity; if (newCapacity != _items.Length) { var newItems = new T[newCapacity]; if (preserveContents) { Array.Copy(_items, newItems, _itemsInUse); } _items = newItems; } else if (!preserveContents) { Array.Clear(_items, 0, _items.Length); } } } }