File: System\Linq\Parallel\Utils\ListChunk.cs
Web Access
Project: src\src\libraries\System.Linq.Parallel\src\System.Linq.Parallel.csproj (System.Linq.Parallel)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
//
// ListChunk.cs
//
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 
using System.Collections.Generic;
using System.Diagnostics;
 
namespace System.Linq.Parallel
{
    /// <summary>
    /// A linked list of array chunks. Allows direct access to its arrays.
    /// </summary>
    /// <typeparam name="TInputOutput">The elements held within.</typeparam>
    internal sealed class ListChunk<TInputOutput> : IEnumerable<TInputOutput>
    {
        internal TInputOutput[] _chunk;
        private int _chunkCount;
        private ListChunk<TInputOutput>? _nextChunk;
        private ListChunk<TInputOutput> _tailChunk;
 
        /// <summary>
        /// Allocates a new root chunk of a particular size.
        /// </summary>
        internal ListChunk(int size)
        {
            Debug.Assert(size > 0);
            _chunk = new TInputOutput[size];
            _chunkCount = 0;
            _tailChunk = this;
        }
 
        /// <summary>
        /// Adds an element to this chunk.  Only ever called on the root.
        /// </summary>
        /// <param name="e">The new element.</param>
        internal void Add(TInputOutput e)
        {
            ListChunk<TInputOutput> tail = _tailChunk;
            if (tail._chunkCount == tail._chunk.Length)
            {
                _tailChunk = new ListChunk<TInputOutput>(tail._chunkCount * 2);
                tail = (tail._nextChunk = _tailChunk);
            }
 
            tail._chunk[tail._chunkCount++] = e;
        }
 
        /// <summary>
        /// The next chunk in the linked chain.
        /// </summary>
        internal ListChunk<TInputOutput>? Next
        {
            get { return _nextChunk; }
        }
 
        /// <summary>
        /// The number of elements contained within this particular chunk.
        /// </summary>
        internal int Count
        {
            get { return _chunkCount; }
        }
 
        /// <summary>
        /// Fetches an enumerator to walk the elements in all chunks rooted from this one.
        /// </summary>
        public IEnumerator<TInputOutput> GetEnumerator()
        {
            ListChunk<TInputOutput>? curr = this;
            while (curr != null)
            {
                for (int i = 0; i < curr._chunkCount; i++)
                {
                    yield return curr._chunk[i];
                }
                Debug.Assert(curr._chunkCount == curr._chunk.Length || curr._nextChunk == null);
                curr = curr._nextChunk;
            }
        }
 
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return ((IEnumerable<TInputOutput>)this).GetEnumerator();
        }
    }
}