File: System\Dynamic\Utils\ListArgumentProvider.cs
Web Access
Project: src\src\libraries\System.Linq.Expressions\src\System.Linq.Expressions.csproj (System.Linq.Expressions)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq.Expressions;
using LinqError = System.Linq.Expressions.Error;
 
namespace System.Dynamic.Utils
{
    internal abstract class ListProvider<T> : IList<T>
        where T : class
    {
        protected abstract T First { get; }
        protected abstract int ElementCount { get; }
        protected abstract T GetElement(int index);
 
        #region IList<T> Members
 
        public int IndexOf(T item)
        {
            if (First == item)
            {
                return 0;
            }
 
            for (int i = 1, n = ElementCount; i < n; i++)
            {
                if (GetElement(i) == item)
                {
                    return i;
                }
            }
 
            return -1;
        }
 
        [ExcludeFromCodeCoverage(Justification = "Unreachable")]
        public void Insert(int index, T item)
        {
            throw ContractUtils.Unreachable;
        }
 
        [ExcludeFromCodeCoverage(Justification = "Unreachable")]
        public void RemoveAt(int index)
        {
            throw ContractUtils.Unreachable;
        }
 
        public T this[int index]
        {
            get
            {
                if (index == 0)
                {
                    return First;
                }
 
                return GetElement(index);
            }
            [ExcludeFromCodeCoverage(Justification = "Unreachable")]
            set
            {
                throw ContractUtils.Unreachable;
            }
        }
 
        #endregion
 
        #region ICollection<T> Members
 
        [ExcludeFromCodeCoverage(Justification = "Unreachable")]
        public void Add(T item)
        {
            throw ContractUtils.Unreachable;
        }
 
        [ExcludeFromCodeCoverage(Justification = "Unreachable")]
        public void Clear()
        {
            throw ContractUtils.Unreachable;
        }
 
        public bool Contains(T item) => IndexOf(item) != -1;
 
        public void CopyTo(T[] array, int index)
        {
            ArgumentNullException.ThrowIfNull(array);
            if (index < 0)
            {
                throw LinqError.ArgumentOutOfRange(nameof(index));
            }
 
            int n = ElementCount;
            Debug.Assert(n > 0);
            if (index + n > array.Length)
            {
                throw new ArgumentException();
            }
 
            array[index++] = First;
            for (int i = 1; i < n; i++)
            {
                array[index++] = GetElement(i);
            }
        }
 
        public int Count => ElementCount;
 
        [ExcludeFromCodeCoverage(Justification = "Unreachable")]
        public bool IsReadOnly => true;
 
        [ExcludeFromCodeCoverage(Justification = "Unreachable")]
        public bool Remove(T item)
        {
            throw ContractUtils.Unreachable;
        }
 
        #endregion
 
        #region IEnumerable<T> Members
 
        public IEnumerator<T> GetEnumerator()
        {
            yield return First;
 
            for (int i = 1, n = ElementCount; i < n; i++)
            {
                yield return GetElement(i);
            }
        }
 
        #endregion
 
        #region IEnumerable Members
 
        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
 
        #endregion
    }
 
    /// <summary>
    /// Provides a wrapper around an IArgumentProvider which exposes the argument providers
    /// members out as an IList of Expression.  This is used to avoid allocating an array
    /// which needs to be stored inside of a ReadOnlyCollection.  Instead this type has
    /// the same amount of overhead as an array without duplicating the storage of the
    /// elements.  This ensures that internally we can avoid creating and copying arrays
    /// while users of the Expression trees also don't pay a size penalty for this internal
    /// optimization.  See IArgumentProvider for more general information on the Expression
    /// tree optimizations being used here.
    /// </summary>
    internal sealed class ListArgumentProvider : ListProvider<Expression>
    {
        private readonly IArgumentProvider _provider;
        private readonly Expression _arg0;
 
        internal ListArgumentProvider(IArgumentProvider provider, Expression arg0)
        {
            _provider = provider;
            _arg0 = arg0;
        }
 
        protected override Expression First => _arg0;
        protected override int ElementCount => _provider.ArgumentCount;
        protected override Expression GetElement(int index) => _provider.GetArgument(index);
    }
}