Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Core / System / Linq / ParallelEnumerable.cs / 1305376 / ParallelEnumerable.cs
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
//
// ParallelEnumerable.cs
//
// [....]
//
// The standard IEnumerable-based LINQ-to-Objects query provider. This class basically
// mirrors the System.Linq.Enumerable class, but (1) takes as input a special "parallel
// enumerable" data type and (2) uses an alternative implementation of the operators.
//
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
using System;
using System.Collections.Generic;
using System.Threading;
using System.Diagnostics.Contracts;
using System.Linq.Parallel;
using System.Collections.Concurrent;
using System.Collections;
using System.Threading.Tasks;
namespace System.Linq
{
//------------------------------------------------------------------------------------
// Languages like C# and VB that support query comprehensions translate queries
// into calls to a query provider which creates executable representations of the
// query. The LINQ-to-Objects provider is implemented as a static class with an
// extension method per-query operator; when invoked, these return enumerable
// objects that implement the querying behavior.
//
// We have a new sequence class for two reasons:
//
// (1) Developers can opt in to parallel query execution piecemeal, by using
// a special AsParallel API to wrap the data source.
// (2) Parallel LINQ uses a new representation for queries when compared to LINQ,
// which we must return from the new sequence operator implementations.
//
// Comments and documentation will be somewhat light in this file. Please refer
// to the "official" Standard Query Operators specification for details on each API:
// http://download.microsoft.com/download/5/8/6/5868081c-68aa-40de-9a45-a3803d8134b8/Standard_Query_Operators.doc
//
// Notes:
// The Standard Query Operators herein should be semantically equivalent to
// the specification linked to above. In some cases, we offer operators that
// aren't available in the sequential LINQ library; in each case, we will note
// why this is needed.
//
///
/// Provides a set of methods for querying objects that implement
/// ParallelQuery{TSource}. This is the parallel equivalent of
/// .
///
public static class ParallelEnumerable
{
// We pass this string constant to an attribute constructor. Unfortunately, we cannot access resources from
// an attribute constructor, so we have to store this string in source code.
private const string RIGHT_SOURCE_NOT_PARALLEL_STR =
"The second data source of a binary operator must be of type System.Linq.ParallelQuery rather than "
+ "System.Collections.Generic.IEnumerable. To fix this problem, use the AsParallel() extension method "
+ "to convert the right data source to System.Linq.ParallelQuery.";
//-----------------------------------------------------------------------------------
// Converts any IEnumerable into something that can be the target of parallel
// query execution.
//
// Arguments:
// source - the enumerable data source
// options - query analysis options to override the defaults
// degreeOfParallelism - the DOP to use instead of the system default, if any
//
// Notes:
// If the argument is already a parallel enumerable, such as a query operator,
// no new objects are allocated. Otherwise, a very simple wrapper is instantiated
// that exposes the IEnumerable as a ParallelQuery.
//
///
/// Enables parallelization of a query.
///
/// The type of elements of .
/// An
/// to convert to a .
/// The source as a to bind to
/// ParallelEnumerable extension methods.
///
/// is a null reference (Nothing in Visual Basic).
///
public static ParallelQuery AsParallel(this IEnumerable source)
{
if (source == null)
{
throw new ArgumentNullException("source");
}
return new ParallelEnumerableWrapper(source);
}
///
/// Enables parallelization of a query, as sourced by a partitioner
/// responsible for splitting the input sequence into partitions.
///
/// The type of elements of .
/// A partitioner over the input sequence.
/// The as a ParallelQuery to bind to ParallelEnumerable extension methods.
///
/// The source partitioner's GetOrderedPartitions method is used when ordering is enabled,
/// whereas the partitioner's GetPartitions is used if ordering is not enabled (the default).
/// The source partitioner's GetDynamicPartitions and GetDynamicOrderedPartitions are not used.
///
///
/// is a null reference (Nothing in Visual Basic).
///
public static ParallelQuery AsParallel(this Partitioner source)
{
if (source == null)
{
throw new ArgumentNullException("source");
}
return new PartitionerQueryOperator(source);
}
///
/// Enables treatment of a data source as if it was ordered, overriding the default of unordered.
/// AsOrdered may only be invoked on sequences returned by AsParallel, ParallelEnumerable.Range,
/// and ParallelEnumerable.Repeat.
///
/// The type of elements of .
/// The input sequence.
///
/// Thrown if is not one of AsParallel, ParallelEnumerable.Range, or ParallelEnumerable.Repeat.
///
///
/// is a null reference (Nothing in Visual Basic).
///
///
/// A natural tension exists between performance and preserving order in parallel processing. By default,
/// a parallelized query behaves as if the ordering of the results is arbitrary
/// unless AsOrdered is applied or there is an explicit OrderBy operator in the query.
///
/// The source sequence which will maintain ordering in the query.
public static ParallelQuery AsOrdered(this ParallelQuery source)
{
if (source == null)
{
throw new ArgumentNullException("source");
}
if (!(source is ParallelEnumerableWrapper || source is IParallelPartitionable))
{
PartitionerQueryOperator partitionerOp = source as PartitionerQueryOperator;
if (partitionerOp != null)
{
if (!partitionerOp.Orderable)
{
throw new InvalidOperationException(SR.GetString(SR.ParallelQuery_PartitionerNotOrderable));
}
}
else
{
throw new InvalidOperationException(SR.GetString(SR.ParallelQuery_InvalidAsOrderedCall));
}
}
return new OrderingQueryOperator(QueryOperator.AsQueryOperator(source), true);
}
///
/// Enables treatment of a data source as if it was ordered, overriding the default of unordered.
/// AsOrdered may only be invoked on sequences returned by AsParallel, ParallelEnumerable.Range,
/// and ParallelEnumerable.Repeat.
///
/// The input sequence.
///
/// Thrown if the is not one of AsParallel, ParallelEnumerable.Range, or ParallelEnumerable.Repeat.
///
///
/// is a null reference (Nothing in Visual Basic).
///
///
/// A natural tension exists between performance and preserving order in parallel processing. By default,
/// a parallelized query behaves as if the ordering of the results is arbitrary unless AsOrdered
/// is applied or there is an explicit OrderBy operator in the query.
///
/// The source sequence which will maintain ordering in the query.
public static ParallelQuery AsOrdered(this ParallelQuery source)
{
if (source == null)
{
throw new ArgumentNullException("source");
}
ParallelEnumerableWrapper wrapper = source as ParallelEnumerableWrapper;
if (wrapper == null)
{
throw new InvalidOperationException(SR.GetString(SR.ParallelQuery_InvalidNonGenericAsOrderedCall));
}
return new OrderingQueryOperator(QueryOperator.AsQueryOperator(wrapper), true);
}
///
/// Allows an intermediate query to be treated as if no ordering is implied among the elements.
///
///
/// AsUnordered may provide
/// performance benefits when ordering is not required in a portion of a query.
///
/// The type of elements of .
/// The input sequence.
/// The source sequence with arbitrary order.
///
/// is a null reference (Nothing in Visual Basic).
///
public static ParallelQuery AsUnordered(this ParallelQuery source)
{
if (source == null)
{
throw new ArgumentNullException("source");
}
return new OrderingQueryOperator(QueryOperator.AsQueryOperator(source), false);
}
///
/// Enables parallelization of a query.
///
/// An to convert
/// to a .
///
/// The source as a ParallelQuery to bind to
/// ParallelEnumerable extension methods.
///
///
/// is a null reference (Nothing in Visual Basic).
///
public static ParallelQuery AsParallel(this IEnumerable source)
{
if (source == null) throw new ArgumentNullException("source");
return new ParallelEnumerableWrapper(source);
}
//-----------------------------------------------------------------------------------
// Converts a parallel enumerable into something that forces sequential execution.
//
// Arguments:
// source - the parallel enumerable data source
//
///
/// Converts a into an
/// to force sequential
/// evaluation of the query.
///
/// The type of elements of .
/// A to convert to an .
/// The source as an
/// to bind to sequential extension methods.
///
/// is a null reference (Nothing in Visual Basic).
///
public static IEnumerable AsSequential(this ParallelQuery source)
{
if (source == null) throw new ArgumentNullException("source");
// Ditch the wrapper, if there is one.
ParallelEnumerableWrapper wrapper = source as ParallelEnumerableWrapper;
if (wrapper != null)
{
return wrapper.WrappedEnumerable;
}
else
{
return source;
}
}
///
/// Sets the task scheduler to execute the query.
///
/// The type of elements of .
/// A ParallelQuery on which to set the task scheduler option.
/// Task scheduler to execute the query.
/// ParallelQuery representing the same query as source, but with the task scheduler option set.
///
/// or is a null reference (Nothing in Visual Basic).
///
///
/// WithTaskScheduler is used multiple times in the query.
///
internal static ParallelQuery WithTaskScheduler(this ParallelQuery source, TaskScheduler taskScheduler)
{
if (source == null) throw new ArgumentNullException("source");
if (taskScheduler == null) throw new ArgumentNullException("taskScheduler");
QuerySettings settings = QuerySettings.Empty;
settings.TaskScheduler = taskScheduler;
return new QueryExecutionOption(
QueryOperator.AsQueryOperator(source), settings);
}
///
/// Sets the degree of parallelism to use in a query. Degree of parallelism is the maximum number of concurrently
/// executing tasks that will be used to process the query.
///
/// The type of elements of .
/// A ParallelQuery on which to set the limit on the degrees of parallelism.
/// The degree of parallelism for the query.
/// ParallelQuery representing the same query as source, with the limit on the degrees of parallelism set.
///
/// is a null reference (Nothing in Visual Basic).
///
///
/// WithDegreeOfParallelism is used multiple times in the query.
///
///
/// is less than 1 or greater than 63.
///
public static ParallelQuery WithDegreeOfParallelism(this ParallelQuery source, int degreeOfParallelism)
{
if (source == null) throw new ArgumentNullException("source");
if (degreeOfParallelism < 1 || degreeOfParallelism > Scheduling.MAX_SUPPORTED_DOP)
{
throw new ArgumentOutOfRangeException("degreeOfParallelism");
}
QuerySettings settings = QuerySettings.Empty;
settings.DegreeOfParallelism = degreeOfParallelism;
return new QueryExecutionOption(
QueryOperator.AsQueryOperator(source), settings);
}
///
/// Sets the to associate with the query.
///
/// The type of elements of .
/// A ParallelQuery on which to set the option.
/// A cancellation token.
/// ParallelQuery representing the same query as source, but with the
/// registered.
///
/// is a null reference (Nothing in Visual Basic).
///
///
/// WithCancellation is used multiple times in the query.
///
///
/// The associated with the has been disposed.
///
public static ParallelQuery WithCancellation(this ParallelQuery source, CancellationToken cancellationToken)
{
if (source == null) throw new ArgumentNullException("source");
// also a convenience check whether the cancellationTokenSource backing the token is already disposed.
// do this via a dummy registration as there is no public IsDipsosed property on CT.
CancellationTokenRegistration dummyRegistration = new CancellationTokenRegistration();
try
{
dummyRegistration = cancellationToken.Register(() => { });
}
catch (ObjectDisposedException)
{
throw new ArgumentException(SR.GetString(SR.ParallelEnumerable_WithCancellation_TokenSourceDisposed), "cancellationToken");
}
finally
{
dummyRegistration.Dispose();
}
QuerySettings settings = QuerySettings.Empty;
settings.CancellationState = new CancellationState(cancellationToken);
return new QueryExecutionOption(
QueryOperator.AsQueryOperator(source), settings);
}
///
/// Sets the execution mode of the query.
///
/// The type of elements of .
/// A ParallelQuery on which to set the option.
/// The mode in which to execute the query.
/// ParallelQuery representing the same query as source, but with the
/// registered.
///
/// is a null reference (Nothing in Visual Basic).
///
///
/// is not a valid value.
///
///
/// WithExecutionMode is used multiple times in the query.
///
public static ParallelQuery WithExecutionMode(this ParallelQuery source, ParallelExecutionMode executionMode)
{
if (source == null) throw new ArgumentNullException("source");
if (executionMode != ParallelExecutionMode.Default && executionMode != ParallelExecutionMode.ForceParallelism)
{
throw new ArgumentException(SR.GetString(SR.ParallelEnumerable_WithQueryExecutionMode_InvalidMode));
}
QuerySettings settings = QuerySettings.Empty;
settings.ExecutionMode = executionMode;
return new QueryExecutionOption(
QueryOperator.AsQueryOperator(source), settings);
}
///
/// Sets the merge options for this query, which specify how the query will buffer output.
///
/// The type of elements of .
/// A ParallelQuery on which to set the option.
/// The merge optiosn to set for this query.
/// ParallelQuery representing the same query as source, but with the
/// registered.
///
/// is a null reference (Nothing in Visual Basic).
///
///
/// is not a valid value.
///
///
/// WithMergeOptions is used multiple times in the query.
///
public static ParallelQuery WithMergeOptions(this ParallelQuery source, ParallelMergeOptions mergeOptions)
{
if (source == null) throw new ArgumentNullException("source");
if (mergeOptions != ParallelMergeOptions.Default
&& mergeOptions != ParallelMergeOptions.AutoBuffered
&& mergeOptions != ParallelMergeOptions.NotBuffered
&& mergeOptions != ParallelMergeOptions.FullyBuffered)
{
throw new ArgumentException(SR.GetString(SR.ParallelEnumerable_WithMergeOptions_InvalidOptions));
}
QuerySettings settings = QuerySettings.Empty;
settings.MergeOptions = mergeOptions;
return new QueryExecutionOption(
QueryOperator.AsQueryOperator(source), settings);
}
//-----------------------------------------------------------------------------------
// Range generates a sequence of numbers that can be used as input to a query.
//
///
/// Generates a parallel sequence of integral numbers within a specified range.
///
/// The value of the first integer in the sequence.
/// The number of sequential integers to generate.
/// An IEnumerable<Int32> in C# or IEnumerable(Of Int32) in
/// Visual Basic that contains a range of sequential integral numbers.
///
/// is less than 0
/// -or-
/// + - 1 is larger than .
///
public static ParallelQuery Range(int start, int count)
{
if (count < 0 || (count > 0 && Int32.MaxValue - (count - 1) < start)) throw new ArgumentOutOfRangeException("count");
return new RangeEnumerable(start, count);
}
//------------------------------------------------------------------------------------
// Repeat just generates a sequence of size 'count' containing 'element'.
//
///
/// Generates a parallel sequence that contains one repeated value.
///
/// The type of the value to be repeated in the result sequence.
/// The value to be repeated.
/// The number of times to repeat the value in the generated sequence.
/// A sequence that contains a repeated value.
///
/// is less than 0.
///
public static ParallelQuery Repeat(TResult element, int count)
{
if (count < 0) throw new ArgumentOutOfRangeException("count");
return new RepeatEnumerable(element, count);
}
//-----------------------------------------------------------------------------------
// Returns an always-empty sequence.
//
///
/// Returns an empty ParallelQuery{TResult} that has the specified type argument.
///
/// The type to assign to the type parameter of the returned
/// generic sequence.
/// An empty sequence whose type argument is .
public static ParallelQuery Empty()
{
return System.Linq.Parallel.EmptyEnumerable.Instance;
}
//------------------------------------------------------------------------------------
// A new query operator that allows an arbitrary user-specified "action" to be
// tacked on to the query tree. The action will be invoked for every element in the
// underlying data source, avoiding a costly final merge in the query's execution,
// which can lead to much better scalability. The caveat is that these occur in
// parallel, so the user providing an action must take care to eliminate shared state
// accesses or to synchronize as appropriate.
//
// Arguments:
// source - the data source over which the actions will be invoked
// action - a delegate representing the per-element action to be invoked
//
// Notes:
// Neither source nor action may be null, otherwise this method throws.
//
///
/// Invokes in parallel the specified action for each element in the .
///
///
/// This is an efficient way to process the output from a parallelized query because it does
/// not require a merge step at the end. However, order of execution is non-deterministic.
///
/// The type of elements of .
/// The whose elements will be processed by
/// .
/// An Action to invoke on each element.
///
/// or is a null reference (Nothing in Visual Basic).
///
///
/// One or more exceptions occurred during the evaluation of the query.
///
///
/// The query was canceled.
///
public static void ForAll(this ParallelQuery source, Action action)
{
if (source == null) throw new ArgumentNullException("source");
if (action == null) throw new ArgumentNullException("action");
// We just instantiate the forall operator and invoke it synchronously on this thread.
// By the time it returns, the entire query has been executed and the actions run..
new ForAllOperator(source, action).RunSynchronously();
}
/*====================================================================================
* BASIC OPERATORS
*===================================================================================*/
//-----------------------------------------------------------------------------------
// Where is an operator that filters any elements from the data source for which the
// user-supplied predictate returns false.
//
///
/// Filters in parallel a sequence of values based on a predicate.
///
/// The type of the elements of source.
/// A sequence to filter.
/// A function to test each element for a condition.
/// A sequence that contains elements from the input sequence that satisfy
/// the condition.
///
/// or is a null reference (Nothing in Visual Basic).
///
public static ParallelQuery Where(this ParallelQuery source, Func predicate)
{
if (source == null) throw new ArgumentNullException("source");
if (predicate == null) throw new ArgumentNullException("predicate");
return new WhereQueryOperator(source, predicate);
}
///
/// Filters in parallel a sequence of values based on a predicate. Each element's index is used in the logic of the predicate function.
///
/// The type of the elements of source.
/// A sequence to filter.
/// A function to test each element for a condition.
/// A sequence that contains elements from the input sequence that satisfy the condition.
///
/// or is a null reference (Nothing in Visual Basic).
///
public static ParallelQuery Where(this ParallelQuery source, Func predicate)
{
if (source == null) throw new ArgumentNullException("source");
if (predicate == null) throw new ArgumentNullException("predicate");
return new IndexedWhereQueryOperator(source, predicate);
}
//------------------------------------------------------------------------------------
// Select merely maps a selector delegate over each element in the data source.
//
///
/// Projects in parallel each element of a sequence into a new form.
///
/// The type of the elements of .
/// The type of elements resturned by selector .
/// A sequence of values to invoke a transform function on.
/// A transform function to apply to each element.
/// A sequence whose elements are the result of invoking the transform function on each
/// element of .
///
/// or is a null reference (Nothing in Visual Basic).
///
public static ParallelQuery Select(
this ParallelQuery source, Func selector)
{
if (source == null) throw new ArgumentNullException("source");
if (selector == null) throw new ArgumentNullException("selector");
return new SelectQueryOperator(source, selector);
}
///
/// Projects in parallel each element of a sequence into a new form by incorporating the element's index.
///
/// The type of the elements of .
/// The type of elements resturned by selector .
/// A sequence of values to invoke a transform function on.
/// A transform function to apply to each element.
/// A sequence whose elements are the result of invoking the transform function on each
/// element of .
///
/// or is a null reference (Nothing in Visual Basic).
///
public static ParallelQuery Select(
this ParallelQuery source, Func selector)
{
if (source == null) throw new ArgumentNullException("source");
if (selector == null) throw new ArgumentNullException("selector");
return new IndexedSelectQueryOperator(source, selector);
}
//-----------------------------------------------------------------------------------
// Zip combines an outer and inner data source into a single output data stream.
//
///
/// Merges in parallel two sequences by using the specified predicate function.
///
/// The type of the elements of the first sequence.
/// The type of the elements of the second sequence.
/// The type of the return elements.
/// The first sequence to zip.
/// The second sequence to zip.
/// A function to create a result element from two matching elements.
///
/// A sequence that has elements of type that are obtained by performing
/// resultSelector pairwise on two sequences. If the sequence lengths are unequal, this truncates
/// to the length of the shorter sequence.
///
///
/// or or is a null reference (Nothing in Visual Basic).
///
public static ParallelQuery Zip(
this ParallelQuery first, ParallelQuery second, Func resultSelector)
{
if (first == null) throw new ArgumentNullException("first");
if (second == null) throw new ArgumentNullException("second");
if (resultSelector == null) throw new ArgumentNullException("resultSelector");
return new ZipQueryOperator(first, second, resultSelector);
}
///
/// This Zip overload should never be called.
/// This method is marked as obsolete and always throws
/// when invoked.
///
/// This type parameter is not used.
/// This type parameter is not used.
/// This type parameter is not used.
/// This parameter is not used.
/// This parameter is not used.
/// This parameter is not used.
/// This overload always throws a .
/// The exception that occurs when this method is called.
///
/// This overload exists to disallow usage of Zip with a left data source of type
/// and a right data source of type .
/// Otherwise, the Zip operator would appear to be bind to the parallel implementation, but would in reality bind to the sequential implementation.
///
[Obsolete(RIGHT_SOURCE_NOT_PARALLEL_STR)]
public static ParallelQuery Zip(
this ParallelQuery first, IEnumerable second, Func resultSelector)
{
throw new NotSupportedException(SR.GetString(SR.ParallelEnumerable_BinaryOpMustUseAsParallel));
}
//-----------------------------------------------------------------------------------
// Join is an inner join operator, i.e. elements from outer with no inner matches
// will yield no results in the output data stream.
//
///
/// Correlates in parallel the elements of two sequences based on matching keys.
/// The default equality comparer is used to compare keys.
///
/// The type of the elements of the first sequence.
/// The type of the elements of the second sequence.
/// The type of the keys returned by the key selector functions.
/// The type of the result elements.
/// The first sequence to join.
/// The sequence to join to the first sequence.
/// A function to extract the join key from each element of
/// the first sequence.
/// A function to extract the join key from each element of
/// the second sequence.
/// A function to create a result element from two matching elements.
/// A sequence that has elements of type that are obtained by performing
/// an inner join on two sequences.
///
/// or or or
/// or is a null reference (Nothing in Visual Basic).
///
public static ParallelQuery Join(
this ParallelQuery outer, ParallelQuery inner,
Func outerKeySelector, Func innerKeySelector,
Func resultSelector)
{
return Join(
outer, inner, outerKeySelector, innerKeySelector, resultSelector, null);
}
///
/// This Join overload should never be called.
/// This method is marked as obsolete and always throws when invoked.
///
/// This type parameter is not used.
/// This type parameter is not used.
/// This type parameter is not used.
/// This type parameter is not used.
/// This parameter is not used.
/// This parameter is not used.
/// This parameter is not used.
/// This parameter is not used.
/// This parameter is not used.
/// This overload always throws a .
/// The exception that occurs when this method is called.
///
/// This overload exists to disallow usage Join with a left data source of type
/// and a right data source of type .
/// Otherwise, the Join operator would appear to be binding to the parallel implementation, but would in reality bind to the sequential implementation.
///
[Obsolete(RIGHT_SOURCE_NOT_PARALLEL_STR)]
public static ParallelQuery Join(
this ParallelQuery outer, IEnumerable inner,
Func outerKeySelector, Func innerKeySelector,
Func resultSelector)
{
throw new NotSupportedException(SR.GetString(SR.ParallelEnumerable_BinaryOpMustUseAsParallel));
}
///
/// Correlates in parallel the elements of two sequences based on matching keys.
/// A specified IEqualityComparer{T} is used to compare keys.
///
/// The type of the elements of the first sequence.
/// The type of the elements of the second sequence.
/// The type of the keys returned by the key selector functions.
/// The type of the result elements.
/// The first sequence to join.
/// The sequence to join to the first sequence.
/// A function to extract the join key from each element
/// of the first sequence.
/// A function to extract the join key from each element
/// of the second sequence.
/// A function to create a result element from two matching elements.
/// An IEqualityComparer<(Of <(T>)>) to hash and compare keys.
/// A sequence that has elements of type that are obtained by performing
/// an inner join on two sequences.
///
/// or or or
/// or is a null reference (Nothing in Visual Basic).
///
public static ParallelQuery Join(
this ParallelQuery outer, ParallelQuery inner,
Func outerKeySelector, Func innerKeySelector,
Func resultSelector, IEqualityComparer comparer)
{
if (outer == null) throw new ArgumentNullException("outer");
if (inner == null) throw new ArgumentNullException("inner");
if (outerKeySelector == null) throw new ArgumentNullException("outerKeySelector");
if (innerKeySelector == null) throw new ArgumentNullException("innerKeySelector");
if (resultSelector == null) throw new ArgumentNullException("resultSelector");
return new JoinQueryOperator(
outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer);
}
///
/// This Join overload should never be called.
/// This method is marked as obsolete and always throws when invoked.
///
/// This type parameter is not used.
/// This type parameter is not used.
/// This type parameter is not used.
/// This type parameter is not used.
/// This parameter is not used.
/// This parameter is not used.
/// This parameter is not used.
/// This parameter is not used.
/// This parameter is not used.
/// This parameter is not used.
/// This overload always throws a .
/// The exception that occurs when this method is called.
///
/// This overload exists to disallow usage of Join with a left data source of type
/// and a right data source of type .
/// Otherwise, the Join operator would appear to be binding to the parallel implementation, but would in reality bind to the sequential implementation.
///
[Obsolete(RIGHT_SOURCE_NOT_PARALLEL_STR)]
public static ParallelQuery Join(
this ParallelQuery outer, IEnumerable inner,
Func outerKeySelector, Func innerKeySelector,
Func resultSelector, IEqualityComparer comparer)
{
throw new NotSupportedException(SR.GetString(SR.ParallelEnumerable_BinaryOpMustUseAsParallel));
}
//-----------------------------------------------------------------------------------
// GroupJoin is an outer join operator, i.e. elements from outer with no inner matches
// will yield results (empty lists) in the output data stream.
//
///
/// Correlates in parallel the elements of two sequences based on equality of keys and groups the results.
/// The default equality comparer is used to compare keys.
///
/// The type of the elements of the first sequence.
/// The type of the elements of the second sequence.
/// The type of the keys returned by the key selector functions.
/// The type of the result elements.
/// The first sequence to join.
/// The sequence to join to the first sequence.
/// A function to extract the join key from each element
/// of the first sequence.
/// A function to extract the join key from each element
/// of the second sequence.
/// A function to create a result element from an element from
/// the first sequence and a collection of matching elements from the second sequence.
/// A sequence that has elements of type that are obtained by performing
/// a grouped join on two sequences.
///
/// or or or
/// or is a null reference (Nothing in Visual Basic).
///
public static ParallelQuery GroupJoin(
this ParallelQuery outer, ParallelQuery inner,
Func outerKeySelector, Func innerKeySelector,
Func, TResult> resultSelector)
{
return GroupJoin(
outer, inner, outerKeySelector, innerKeySelector, resultSelector, null);
}
///
/// This GroupJoin overload should never be called.
/// This method is marked as obsolete and always throws when called.
///
/// This type parameter is not used.
/// This type parameter is not used.
/// This type parameter is not used.
/// This type parameter is not used.
/// This parameter is not used.
/// This parameter is not used.
/// This parameter is not used.
/// This parameter is not used.
/// This parameter is not used.
/// This overload always throws a .
/// The exception that occurs when this method is called.
///
/// This overload exists to disallow usage of GroupJoin with a left data source of type
/// and a right data source of type .
/// Otherwise, the GroupJoin operator would appear to be binding to the parallel implementation,
/// but would in reality bind to the sequential implementation.
///
[Obsolete(RIGHT_SOURCE_NOT_PARALLEL_STR)]
public static ParallelQuery GroupJoin(
this ParallelQuery outer, IEnumerable inner,
Func outerKeySelector, Func innerKeySelector,
Func, TResult> resultSelector)
{
throw new NotSupportedException(SR.GetString(SR.ParallelEnumerable_BinaryOpMustUseAsParallel));
}
///
/// Correlates in parallel the elements of two sequences based on key equality and groups the results.
/// A specified IEqualityComparer{T} is used to compare keys.
///
/// The type of the elements of the first sequence.
/// The type of the elements of the second sequence.
/// The type of the keys returned by the key selector functions.
/// The type of the result elements.
/// The first sequence to join.
/// The sequence to join to the first sequence.
/// A function to extract the join key from each element
/// of the first sequence.
/// A function to extract the join key from each element
/// of the second sequence.
/// A function to create a result element from an element from
/// the first sequence and a collection of matching elements from the second sequence.
/// An IEqualityComparer<(Of <(T>)>) to hash and compare keys.
/// A sequence that has elements of type that are obtained by performing
/// a grouped join on two sequences.
///
/// or or or
/// or is a null reference (Nothing in Visual Basic).
///
public static ParallelQuery GroupJoin(
this ParallelQuery outer, ParallelQuery inner,
Func outerKeySelector, Func innerKeySelector,
Func, TResult> resultSelector, IEqualityComparer comparer)
{
if (outer == null) throw new ArgumentNullException("outer");
if (inner == null) throw new ArgumentNullException("inner");
if (outerKeySelector == null) throw new ArgumentNullException("outerKeySelector");
if (innerKeySelector == null) throw new ArgumentNullException("innerKeySelector");
if (resultSelector == null) throw new ArgumentNullException("resultSelector");
return new GroupJoinQueryOperator(outer, inner,
outerKeySelector, innerKeySelector, resultSelector, comparer);
}
///
/// This GroupJoin overload should never be called.
/// This method is marked as obsolete and always throws when called.
///
/// This type parameter is not used.
/// This type parameter is not used.
/// This type parameter is not used.
/// This type parameter is not used.
/// This parameter is not used.
/// This parameter is not used.
/// This parameter is not used.
/// This parameter is not used.
/// This parameter is not used.
/// This parameter is not used.
/// This overload always throws a .
/// The exception that occurs when this method is called.
///
/// This overload exists to disallow usage of GroupJoin with a left data source of type
/// and a right data source of type .
/// Otherwise, the GroupJoin operator would appear to be binding to the parallel implementation,
/// but would in reality bind to the sequential implementation.
///
[Obsolete(RIGHT_SOURCE_NOT_PARALLEL_STR)]
public static ParallelQuery GroupJoin(
this ParallelQuery outer, IEnumerable inner,
Func outerKeySelector, Func innerKeySelector,
Func, TResult> resultSelector, IEqualityComparer comparer)
{
throw new NotSupportedException(SR.GetString(SR.ParallelEnumerable_BinaryOpMustUseAsParallel));
}
//------------------------------------------------------------------------------------
// SelectMany is a kind of nested loops join. For each element in the outer data
// source, we enumerate each element in the inner data source, yielding the result
// with some kind of selection routine. A few different flavors are supported.
//
///
/// Projects in parallel each element of a sequence to an IEnumerable{T}
/// and flattens the resulting sequences into one sequence.
///
/// The type of elements of .
/// The type of the elements of the sequence returned by selector .
/// A sequence of values to project.
/// A transform function to apply to each element.
/// A sequence whose elements are the result of invoking the one-to-many transform
/// function on each element of the input sequence.
///
/// or is a null reference (Nothing in Visual Basic).
///
public static ParallelQuery SelectMany(
this ParallelQuery source, Func> selector)
{
if (source == null) throw new ArgumentNullException("source");
if (selector == null) throw new ArgumentNullException("selector");
return new SelectManyQueryOperator(source, selector, null, null);
}
///
/// Projects in parallel each element of a sequence to an IEnumerable{T}, and flattens the resulting
/// sequences into one sequence. The index of each source element is used in the projected form of
/// that element.
///
/// The type of elements of .
/// The type of the elements of the sequence returned by selector .
/// A sequence of values to project.
/// A transform function to apply to each element.
/// A sequence whose elements are the result of invoking the one-to-many transform
/// function on each element of the input sequence.
///
/// or is a null reference (Nothing in Visual Basic).
///
public static ParallelQuery SelectMany(
this ParallelQuery source, Func> selector)
{
if (source == null) throw new ArgumentNullException("source");
if (selector == null) throw new ArgumentNullException("selector");
return new SelectManyQueryOperator(source, null, selector, null);
}
///
/// Projects each element of a sequence to an IEnumerable{T},
/// flattens the resulting sequences into one sequence, and invokes a result selector
/// function on each element therein.
///
/// The type of elements of .
/// The type of the intermediate elements collected by .
///
/// A sequence of values to project.
/// A transform function to apply to each source element;
/// the second parameter of the function represents the index of the source element.
/// A function to create a result element from an element from
/// the first sequence and a collection of matching elements from the second sequence.
/// A sequence whose elements are the result of invoking the one-to-many transform
/// function on each element of and then mapping
/// each of those sequence elements and their corresponding source element to a result element.
///
/// or or
/// is a null reference (Nothing in Visual Basic).
///
public static ParallelQuery SelectMany(
this ParallelQuery source, Func> collectionSelector,
Func resultSelector)
{
if (source == null) throw new ArgumentNullException("source");
if (collectionSelector == null) throw new ArgumentNullException("collectionSelector");
if (resultSelector == null) throw new ArgumentNullException("resultSelector");
return new SelectManyQueryOperator(source, collectionSelector, null, resultSelector);
}
///
/// Projects each element of a sequence to an IEnumerable{T}, flattens the resulting
/// sequences into one sequence, and invokes a result selector function on each element
/// therein. The index of each source element is used in the intermediate projected
/// form of that element.
///
/// The type of elements of .
/// The type of the intermediate elements collected by
/// .
/// The type of elements to return.
/// A sequence of values to project.
/// A transform function to apply to each source element;
/// the second parameter of the function represents the index of the source element.
/// A function to create a result element from an element from
/// the first sequence and a collection of matching elements from the second sequence.
///
/// A sequence whose elements are the result of invoking the one-to-many transform
/// function on each element of and then mapping
/// each of those sequence elements and their corresponding source element to a
/// result element.
///
///
/// or or
/// is a null reference (Nothing in Visual Basic).
///
public static ParallelQuery SelectMany(
this ParallelQuery source, Func> collectionSelector,
Func resultSelector)
{
if (source == null) throw new ArgumentNullException("source");
if (collectionSelector == null) throw new ArgumentNullException("collectionSelector");
if (resultSelector == null) throw new ArgumentNullException("resultSelector");
return new SelectManyQueryOperator(source, null, collectionSelector, resultSelector);
}
//-----------------------------------------------------------------------------------
// OrderBy and ThenBy establish an ordering among elements, using user-specified key
// selection and key comparison routines. There are also descending sort variants.
//
///
/// Sorts in parallel the elements of a sequence in ascending order according to a key.
///
///
/// In contrast to the sequential implementation, this is not a stable sort.
/// To achieve a stable sort, change a query of the form:
/// var ordered = source.OrderBy((e) => e.k);
/// to instead be formed as:
/// var ordered = source.Select((e,i) => new { E=e, I=i }).OrderBy((v) => v.i).Select((v) => v.e);
///
/// The type of elements of .
/// The type of the key returned by .
/// A sequence of values to order.
/// A function to extract a key from an element.
/// An OrderedParallelQuery{TSource} whose elements are sorted
/// according to a key.
///
/// or is a null reference (Nothing in Visual Basic).
///
public static OrderedParallelQuery OrderBy(
this ParallelQuery source, Func keySelector)
{
if (source == null) throw new ArgumentNullException("source");
if (keySelector == null) throw new ArgumentNullException("keySelector");
return new OrderedParallelQuery(
new SortQueryOperator(source, keySelector, null, false));
}
///
/// Sorts in parallel the elements of a sequence in ascending order by using a specified comparer.
///
///
/// In contrast to the sequential implementation, this is not a stable sort.
/// See the remarks for OrderBy(ParallelQuery{TSource}, Func{TSource,TKey}) for
/// an approach to implementing a stable sort.
///
/// The type of elements of .
/// The type of the key returned by .
/// A sequence of values to order.
/// A function to extract a key from an element.
/// An IComparer{TKey} to compare keys.
/// An OrderedParallelQuery{TSource} whose elements are sorted according
/// to a key.
///
/// or is a null reference (Nothing in Visual Basic).
///
public static OrderedParallelQuery OrderBy(
this ParallelQuery source, Func keySelector, IComparer comparer)
{
if (source == null) throw new ArgumentNullException("source");
if (keySelector == null) throw new ArgumentNullException("keySelector");
return new OrderedParallelQuery(
new SortQueryOperator(source, keySelector, comparer, false));
}
///
/// Sorts in parallel the elements of a sequence in descending order according to a key.
///
///
/// In contrast to the sequential implementation, this is not a stable sort.
/// See the remarks for OrderBy(ParallelQuery{TSource}, Func{TSource,TKey}) for
/// an approach to implementing a stable sort.
///
/// The type of elements of .
/// The type of the key returned by .
/// A sequence of values to order.
/// A function to extract a key from an element.
/// An OrderedParallelQuery{TSource} whose elements are sorted
/// descending according to a key.
///
/// or is a null reference (Nothing in Visual Basic).
///
public static OrderedParallelQuery OrderByDescending(
this ParallelQuery source, Func keySelector)
{
if (source == null) throw new ArgumentNullException("source");
if (keySelector == null) throw new ArgumentNullException("keySelector");
return new OrderedParallelQuery(new SortQueryOperator(source, keySelector, null, true));
}
///
/// Sorts the elements of a sequence in descending order by using a specified comparer.
///
///
/// In contrast to the sequential implementation, this is not a stable sort.
/// See the remarks for OrderBy(ParallelQuery{TSource}, Func{TSource,TKey}) for
/// an approach to implementing a stable sort.
///
/// The type of elements of .
/// The type of the key returned by .
/// A sequence of values to order.
/// A function to extract a key from an element.
/// An IComparer{TKey} to compare keys.
/// An OrderedParallelQuery{TSource} whose elements are sorted descending
/// according to a key.
///
/// or is a null reference (Nothing in Visual Basic).
///
public static OrderedParallelQuery OrderByDescending(
this ParallelQuery source, Func keySelector, IComparer comparer)
{
if (source == null) throw new ArgumentNullException("source");
if (keySelector == null) throw new ArgumentNullException("keySelector");
return new OrderedParallelQuery(
new SortQueryOperator(source, keySelector, comparer, true));
}
///
/// Performs in parallel a subsequent ordering of the elements in a sequence
/// in ascending order according to a key.
///
///
/// In contrast to the sequential implementation, this is not a stable sort.
/// See the remarks for OrderBy(ParallelQuery{TSource}, Func{TSource,TKey}) for
/// an approach to implementing a stable sort.
///
/// The type of elements of .
/// The type of the key returned by .
/// An OrderedParallelQuery{TSource} than
/// contains elements to sort.
/// A function to extract a key from an element.
/// An OrderedParallelQuery{TSource} whose elements are
/// sorted according to a key.
///
/// or is a null reference (Nothing in Visual Basic).
///
public static OrderedParallelQuery ThenBy(
this OrderedParallelQuery source, Func keySelector)
{
if (source == null) throw new ArgumentNullException("source");
if (keySelector == null) throw new ArgumentNullException("keySelector");
return new OrderedParallelQuery(
(QueryOperator)source.OrderedEnumerable.CreateOrderedEnumerable(keySelector, null, false));
}
///
/// Performs in parallel a subsequent ordering of the elements in a sequence in
/// ascending order by using a specified comparer.
///
///
/// In contrast to the sequential implementation, this is not a stable sort.
/// See the remarks for OrderBy(ParallelQuery{TSource}, Func{TSource,TKey}) for
/// an approach to implementing a stable sort.
///
/// The type of elements of .
/// The type of the key returned by .
/// An OrderedParallelQuery{TSource} that contains
/// elements to sort.
/// A function to extract a key from an element.
/// An IComparer{TKey} to compare keys.
/// An OrderedParallelQuery{TSource} whose elements are sorted
/// according to a key.
///
/// or is a null reference (Nothing in Visual Basic).
///
public static OrderedParallelQuery ThenBy(
this OrderedParallelQuery source, Func keySelector, IComparer comparer)
{
if (source == null) throw new ArgumentNullException("source");
if (keySelector == null) throw new ArgumentNullException("keySelector");
return new OrderedParallelQuery(
(QueryOperator)source.OrderedEnumerable.CreateOrderedEnumerable(keySelector, comparer, false));
}
///
/// Performs in parallel a subsequent ordering of the elements in a sequence in
/// descending order, according to a key.
///
///
/// In contrast to the sequential implementation, this is not a stable sort.
/// See the remarks for OrderBy(ParallelQuery{TSource}, Func{TSource,TKey}) for
/// an approach to implementing a stable sort.
///
/// The type of elements of .
/// The type of the key returned by .
/// An OrderedParallelQuery{TSource} than contains
/// elements to sort.
/// A function to extract a key from an element.
/// An OrderedParallelQuery{TSource} whose elements are sorted
/// descending according to a key.
///
/// or is a null reference (Nothing in Visual Basic).
///
public static OrderedParallelQuery ThenByDescending(
this OrderedParallelQuery source, Func keySelector)
{
if (source == null) throw new ArgumentNullException("source");
if (keySelector == null) throw new ArgumentNullException("keySelector");
return new OrderedParallelQuery(
(QueryOperator)source.OrderedEnumerable.CreateOrderedEnumerable(keySelector, null, true));
}
///
/// Performs in parallel a subsequent ordering of the elements in a sequence in descending
/// order by using a specified comparer.
///
///
/// In contrast to the sequential implementation, this is not a stable sort.
/// See the remarks for OrderBy(ParallelQuery{TSource}, Func{TSource,TKey}) for
/// an approach to implementing a stable sort.
///
/// The type of elements of .
/// The type of the key returned by .
/// An OrderedParallelQuery{TSource} than contains
/// elements to sort.
/// A function to extract a key from an element.
/// An IComparer{TKey} to compare keys.
/// An OrderedParallelQuery{TSource} whose elements are sorted
/// descending according to a key.
///
/// or is a null reference (Nothing in Visual Basic).
///
public static OrderedParallelQuery ThenByDescending(
this OrderedParallelQuery source, Func keySelector, IComparer comparer)
{
if (source == null) throw new ArgumentNullException("source");
if (keySelector == null) throw new ArgumentNullException("keySelector");
return new OrderedParallelQuery(
(QueryOperator)source.OrderedEnumerable.CreateOrderedEnumerable(keySelector, comparer, true));
}
//------------------------------------------------------------------------------------
// A GroupBy operation groups inputs based on a key-selection routine, yielding a
// one-to-many value of key-to-elements to the consumer.
//
///
/// Groups in parallel the elements of a sequence according to a specified key selector function.
///
/// The type of elements of .
/// The type of the key returned by .
/// An OrderedParallelQuery{TSource}than contains
/// elements to sort.
/// A function to extract a key from an element.
/// An OrderedParallelQuery{TSource}whose elements are sorted
/// descending according to a key.
public static ParallelQuery> GroupBy(
this ParallelQuery source, Func keySelector)
{
return GroupBy(source, keySelector, null);
}
///
/// Groups in parallel the elements of a sequence according to a specified key selector function and compares the keys by using a specified comparer.
///
/// The type of elements of .
/// The type of the key returned by >.
/// An OrderedParallelQuery{TSource} than contains
/// elements to sort.
/// A function to extract a key from an element.
/// An IComparer{TSource} to compare keys.
/// An OrderedParallelQuery{TSource} whose elements are sorted
/// descending according to a key.
///
/// or is a null reference (Nothing in Visual Basic).
///
public static ParallelQuery> GroupBy(
this ParallelQuery