File: PooledObjects\PooledList`1.cs
Web Access
Project: src\src\Razor\src\Shared\Microsoft.AspNetCore.Razor.Utilities.Shared\Microsoft.AspNetCore.Razor.Utilities.Shared.csproj (Microsoft.AspNetCore.Razor.Utilities.Shared)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
 
namespace Microsoft.AspNetCore.Razor.PooledObjects;
 
/// <summary>
///  Wraps a pooled <see cref="List{T}"/> but doesn't allocate it until
///  it's needed. Note: Dispose this to ensure that the pooled list is returned
///  to the pool.
/// </summary>
internal ref partial struct PooledList<T>
{
    private readonly ListPool<T> _pool;
    private List<T>? _list;
 
    public PooledList()
        : this(ListPool<T>.Default)
    {
    }
 
    public PooledList(ListPool<T> pool)
    {
        _pool = pool;
    }
 
    public void Dispose()
    {
        ClearAndFree();
    }
 
    public int Count
        => _list?.Count ?? 0;
 
    public T this[int index]
    {
        readonly get
        {
            if (_list is { } list)
            {
                return list[index];
            }
 
            // Throw moved to separate method to encourage better JIT inlining.
            return ThrowIndexOutOfRangeException();
 
            [DoesNotReturn]
            static T ThrowIndexOutOfRangeException()
            {
                throw new IndexOutOfRangeException();
            }
        }
 
        set
        {
            _list ??= _pool.Get();
            _list[index] = value;
        }
    }
 
    public void Add(T item)
    {
        _list ??= _pool.Get();
        _list.Add(item);
    }
 
    public void AddRange(IReadOnlyList<T> items)
    {
        if (items.Count == 0)
        {
            return;
        }
 
        _list ??= _pool.Get();
        _list.AddRange(items);
    }
 
    public void AddRange(IEnumerable<T> items)
    {
        _list ??= _pool.Get();
        _list.AddRange(items);
    }
 
    public readonly Enumerator GetEnumerator()
        => _list is { } list
            ? new Enumerator(list)
            : default;
 
    public void ClearAndFree()
    {
        if (_list is { } list)
        {
            _pool.Return(list);
            _list = null;
        }
    }
 
    public readonly T[] ToArray()
        => _list.ToArrayOrEmpty();
}