File: System\Reflection\Runtime\General\ListBuilder.cs
Web Access
Project: src\src\libraries\System.Reflection.MetadataLoadContext\src\System.Reflection.MetadataLoadContext.csproj (System.Reflection.MetadataLoadContext)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Diagnostics;
 
namespace System.Reflection.Runtime.General
{
    //
    // Struct-based list builder that's special cased to avoid allocations for lists of one element.
    //
    internal struct ListBuilder<T> where T : class
    {
        public ListBuilder(int capacity)
        {
            _items = null;
            _item = null;
            _count = 0;
            _capacity = capacity;
#if DEBUG
            _toArrayAlreadyCalled = false;
#endif // DEBUG
        }
 
        public T this[int index]
        {
            get
            {
                Debug.Assert(index < Count);
                return (_items != null) ? _items[index] : _item!;
            }
        }
 
        public T[] ToArray()
        {
#if DEBUG
            // ListBuilder does not always allocate a new array, though the ToArray() name connotates that it does (and in fact, we do pass the results
            // of this method across api boundaries.) The minimizing of allocations is desirable, however, so instead, we restrict you to one call per ListBuilder.
            Debug.Assert(!_toArrayAlreadyCalled, "Cannot call ListBuilder.ToArray() a second time. Copy the one you already got.");
#endif // DEBUG
            if (_count == 0)
                return Array.Empty<T>();
            if (_count == 1)
                return new T[1] { _item! };
 
            Array.Resize(ref _items, _count);
 
#if DEBUG
            _toArrayAlreadyCalled = true;
#endif // DEBUG
 
            return _items;
        }
 
        public void CopyTo(object[] array, int index)
        {
            if (_count == 0)
                return;
 
            if (_count == 1)
            {
                array[index] = _item!;
                return;
            }
 
            Array.Copy(_items!, 0, array, index, _count);
        }
 
        public int Count
        {
            get
            {
                return _count;
            }
        }
 
        public void Add(T item)
        {
            if (_count == 0)
            {
                _item = item;
            }
            else
            {
                if (_count == 1)
                {
                    if (_capacity < 2)
                        _capacity = 4;
                    _items = new T[_capacity];
                    _items[0] = _item!;
                }
                else if (_capacity == _count)
                {
                    int newCapacity = 2 * _capacity;
                    Array.Resize(ref _items, newCapacity);
                    _capacity = newCapacity;
                }
 
                _items![_count] = item;
            }
            _count++;
        }
 
        private T[]? _items;
        private T? _item;
        private int _count;
        private int _capacity;
#if DEBUG
        private bool _toArrayAlreadyCalled;
#endif // DEBUG
    }
}