// 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);
}
}
}
}