File: System\Linq\Parallel\Merging\ArrayMergeHelper.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.
 
// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
//
// ArrayMergeHelper.cs
//
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Linq.Parallel;
using System.Text;
using System.Threading.Tasks;
 
namespace System.Linq.Parallel
{
    /// <summary>
    /// A special merge helper for indexable queries. Given an indexable query, we know how many elements
    /// we'll have in the result set, so we can allocate the array ahead of time. Then, as each result element
    /// is produced, we can directly insert it into the appropriate position in the output array, paying
    /// no extra cost for ordering.
    /// </summary>
    /// <typeparam name="TInputOutput"></typeparam>
    internal sealed class ArrayMergeHelper<TInputOutput> : IMergeHelper<TInputOutput>
    {
        private readonly QueryResults<TInputOutput> _queryResults; // Indexable query results
        private readonly TInputOutput[] _outputArray; // The output array.
        private QuerySettings _settings; // Settings for the query.
 
        /// <summary>
        /// Instantiates the array merge helper.
        /// </summary>
        /// <param name="settings">The query settings</param>
        /// <param name="queryResults">The query results</param>
        public ArrayMergeHelper(QuerySettings settings, QueryResults<TInputOutput> queryResults)
        {
            _settings = settings;
            _queryResults = queryResults;
 
            int count = _queryResults.Count;
            _outputArray = new TInputOutput[count];
        }
 
        /// <summary>
        /// A method used as a delegate passed into the ForAll operator
        /// </summary>
        private void ToArrayElement(int index)
        {
            _outputArray[index] = _queryResults[index];
        }
 
 
        /// <summary>
        /// Schedules execution of the merge itself.
        /// </summary>
        public void Execute()
        {
            ParallelQuery<int> query = ParallelEnumerable.Range(0, _queryResults.Count);
            query = new QueryExecutionOption<int>(QueryOperator<int>.AsQueryOperator(query), _settings);
            query.ForAll(ToArrayElement);
        }
 
        /// <summary>
        /// Gets the enumerator over the results.
        ///
        /// We never expect this method to be called. ArrayMergeHelper is intended to be used when we want
        /// to consume the results using GetResultsAsArray().
        /// </summary>
        [ExcludeFromCodeCoverage(Justification = "ArrayMergeHelper<>.GetEnumerator() is not intended to be used")]
        public IEnumerator<TInputOutput> GetEnumerator()
        {
            Debug.Fail("ArrayMergeHelper<>.GetEnumerator() is not intended to be used. Call GetResultsAsArray() instead.");
            return ((IEnumerable<TInputOutput>)GetResultsAsArray()).GetEnumerator();
        }
 
        /// <summary>
        /// Returns the merged results as an array.
        /// </summary>
        /// <returns></returns>
        public TInputOutput[] GetResultsAsArray()
        {
            Debug.Assert(_outputArray != null);
            return _outputArray;
        }
    }
}