Imported Upstream version 3.6.0

Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
This commit is contained in:
Jo Shields
2014-08-13 10:39:27 +01:00
commit a575963da9
50588 changed files with 8155799 additions and 0 deletions

View File

@@ -0,0 +1,27 @@
2010-04-15 Jérémie Laval <jeremie.laval@gmail.com>
* QueryBaseNode.cs:
* QueryCastNode.cs:
* QueryChildNode.cs:
* QueryConcatNode.cs:
* QueryDefaultEmptyNode.cs:
* QueryGroupByNode.cs:
* QueryMuxNode.cs:
* QueryOptionNode.cs:
* QueryOrderByNode.cs:
* QueryOrderGuardNode.cs:
* QueryOrderedStreamNode.cs:
* QueryReverseNode.cs:
* QuerySelectManyNode.cs:
* QuerySelectNode.cs:
* QuerySetNode.cs:
* QueryStartNode.cs:
* QueryStreamNode.cs:
* QueryWhereNode.cs:
* QueryZipNode.cs:
* WrapHelper.cs: Initial check-in of PLinq
2010-04-15 Jérémie Laval <jeremie.laval@gmail.com>
* SetInclusion.cs: Initial check-in of PLinq (enum)

View File

@@ -0,0 +1,53 @@
//
// QueryBaseNode.cs
//
// Author:
// Jérémie "Garuma" Laval <jeremie.laval@gmail.com>
//
// Copyright (c) 2010 Jérémie "Garuma" Laval
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if NET_4_0
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Generic;
namespace System.Linq.Parallel.QueryNodes
{
internal interface QueryBaseNode : IVisitableNode
{
}
internal abstract class QueryBaseNode<T> : QueryBaseNode
{
public virtual void Visit (INodeVisitor visitor)
{
visitor.Visit (this);
}
internal abstract IList<IEnumerable<T>> GetEnumerables (QueryOptions options);
internal abstract IList<IEnumerable<KeyValuePair<long, T>>> GetOrderedEnumerables (QueryOptions options);
internal abstract IEnumerable<T> GetSequential ();
}
}
#endif

View File

@@ -0,0 +1,64 @@
//
// QueryCastNode.cs
//
// Author:
// Jérémie "Garuma" Laval <jeremie.laval@gmail.com>
//
// Copyright (c) 2010 Jérémie "Garuma" Laval
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if NET_4_0
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Generic;
namespace System.Linq.Parallel.QueryNodes
{
internal class QueryCastNode<T> : QueryStreamNode<object, T>
{
public QueryCastNode (QueryBaseNode<T> source)
: base (source, false)
{
}
internal override IEnumerable<object> GetSequential ()
{
return Parent.GetSequential ().Cast<object> ();
}
internal override IList<IEnumerable<KeyValuePair<long, object>>> GetOrderedEnumerables (QueryOptions options)
{
return Parent.GetOrderedEnumerables (options)
.Select ((i) => i.Select ((e) => new KeyValuePair<long, object> (e.Key, (object)e.Value)))
.ToList ();
}
internal override IList<IEnumerable<object>> GetEnumerables (QueryOptions options)
{
return Parent.GetEnumerables (options)
.Select ((i) => i.Cast<object> ())
.ToList ();
}
}
}
#endif

View File

@@ -0,0 +1,62 @@
//
// QueryChildNode.cs
//
// Author:
// Jérémie "Garuma" Laval <jeremie.laval@gmail.com>
//
// Copyright (c) 2010 Jérémie "Garuma" Laval
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if NET_4_0
using System;
namespace System.Linq.Parallel.QueryNodes
{
internal interface QueryChildNode : IVisitableNode {
QueryBaseNode Parent { get; }
}
internal abstract class QueryChildNode<T, TParent> : QueryBaseNode<T>, QueryChildNode
{
QueryBaseNode<TParent> parent;
internal QueryChildNode (QueryBaseNode<TParent> parent)
// : base (isOrdered, true)
{
this.parent = parent;
}
QueryBaseNode QueryChildNode.Parent {
get { return parent; }
}
internal QueryBaseNode<TParent> Parent {
get {
return parent;
}
}
public override void Visit (INodeVisitor visitor)
{
visitor.Visit ((QueryChildNode)this);
}
}
}
#endif

View File

@@ -0,0 +1,78 @@
//
// QueryConcatNode.cs
//
// Author:
// Jérémie "Garuma" Laval <jeremie.laval@gmail.com>
//
// Copyright (c) 2010 Jérémie "Garuma" Laval
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if NET_4_0
using System;
using System.Threading;
using System.Collections;
using System.Collections.Generic;
namespace System.Linq.Parallel.QueryNodes
{
internal class QueryConcatNode<TSource> : QueryMuxNode<TSource, TSource, TSource>
{
public QueryConcatNode (QueryBaseNode<TSource> first, QueryBaseNode<TSource> second)
: base (first, second)
{
}
internal override IList<IEnumerable<TSource>> GetEnumerables (QueryOptions options)
{
var second = Second.GetEnumerables (options);
return Parent.GetEnumerables (options)
.Select ((f, i) => CombineEnumerables (f, second[i]))
.ToList ();
}
internal override IList<IEnumerable<KeyValuePair<long, TSource>>> GetOrderedEnumerables (QueryOptions options)
{
var second = Second.GetOrderedEnumerables (options);
return Parent.GetOrderedEnumerables (options)
.Select ((f, i) => CombineEnumerables (f, second[i]))
.ToList ();
}
internal override IEnumerable<TSource> GetSequential ()
{
IEnumerable<TSource> first = Parent.GetSequential ();
IEnumerable<TSource> second = Second.GetSequential ();
return first.Concat (second);
}
IEnumerable<TResult> CombineEnumerables<TResult> (IEnumerable<TResult> f, IEnumerable<TResult> s)
{
foreach (var e in f)
yield return e;
foreach (var e in s)
yield return e;
}
}
}
#endif

View File

@@ -0,0 +1,91 @@
//
// QueryDefaultEmptyNode.cs
//
// Author:
// Jérémie "Garuma" Laval <jeremie.laval@gmail.com>
//
// Copyright (c) 2010 Jérémie "Garuma" Laval
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if NET_4_0
using System;
using System.Threading;
using System.Collections;
using System.Collections.Generic;
namespace System.Linq.Parallel.QueryNodes
{
internal class QueryDefaultEmptyNode<TSource> : QueryStreamNode<TSource, TSource>
{
TSource defaultValue;
internal QueryDefaultEmptyNode (QueryBaseNode<TSource> parent, TSource defaultValue)
: base (parent, false)
{
this.defaultValue = defaultValue;
}
internal override IEnumerable<TSource> GetSequential ()
{
return Parent.GetSequential ().DefaultIfEmpty (defaultValue);
}
internal override IList<IEnumerable<TSource>> GetEnumerables (QueryOptions options)
{
IList<IEnumerable<TSource>> enumerables = Parent.GetEnumerables (options);
CountdownEvent evt = new CountdownEvent (enumerables.Count);
return enumerables
.Select ((e) => GetEnumerableInternal<TSource> (e,
evt,
(s) => s))
.ToList ();
}
internal override IList<IEnumerable<KeyValuePair<long, TSource>>> GetOrderedEnumerables (QueryOptions options)
{
IList<IEnumerable<KeyValuePair<long, TSource>>> enumerables = Parent.GetOrderedEnumerables (options);
CountdownEvent evt = new CountdownEvent (enumerables.Count);
return enumerables
.Select ((e) => GetEnumerableInternal<KeyValuePair<long, TSource>> (e,
evt,
(s) => new KeyValuePair<long, TSource> (0, s)))
.ToList ();
}
IEnumerable<TSecond> GetEnumerableInternal<TSecond> (IEnumerable<TSecond> source,
CountdownEvent evt,
Func<TSource, TSecond> converter)
{
bool processed = false;
foreach (TSecond second in source) {
processed = true;
yield return second;
}
if (!processed && evt.Signal ())
yield return converter (defaultValue);
}
}
}
#endif

View File

@@ -0,0 +1,90 @@
//
// QueryOrderByNode.cs
//
// Author:
// Jérémie "Garuma" Laval <jeremie.laval@gmail.com>
//
// Copyright (c) 2010 Jérémie "Garuma" Laval
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if NET_4_0
using System;
using System.Threading;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Concurrent;
namespace System.Linq.Parallel.QueryNodes
{
internal class QueryGroupByNode<TSource, TKey, TElement> : QueryStreamNode<IGrouping<TKey, TElement>, TSource>
{
Func<TSource, TKey> keySelector;
Func<TSource, TElement> elementSelector;
IEqualityComparer<TKey> comparer;
public QueryGroupByNode (QueryBaseNode<TSource> parent,
Func<TSource, TKey> keySelector,
Func<TSource, TElement> elementSelector,
IEqualityComparer<TKey> comparer)
: base (parent, false)
{
this.keySelector = keySelector;
this.elementSelector = elementSelector;
this.comparer = comparer;
}
internal override IEnumerable<IGrouping<TKey, TElement>> GetSequential ()
{
IEnumerable<TSource> src = Parent.GetSequential ();
return src.GroupBy (keySelector, elementSelector, comparer);
}
internal override IList<IEnumerable<IGrouping<TKey, TElement>>> GetEnumerables (QueryOptions options)
{
return ParallelPartitioner.CreateForChunks (GetGroupedElements ()).GetPartitions (options.PartitionCount).Wrap ();
}
internal override IList<IEnumerable<KeyValuePair<long, IGrouping<TKey, TElement>>>> GetOrderedEnumerables (QueryOptions options)
{
return ParallelPartitioner.CreateForChunks (GetGroupedElements ()).GetOrderablePartitions (options.PartitionCount).Wrap ();
}
internal IEnumerable<IGrouping<TKey, TElement>> GetGroupedElements ()
{
return (IEnumerable<System.Linq.IGrouping<TKey,TElement>>)GetStore ().Select (e => (IGrouping<TKey,TElement>)new ConcurrentGrouping<TKey, TElement> (e.Key, e.Value));
}
internal ConcurrentDictionary<TKey, ConcurrentQueue<TElement>> GetStore ()
{
var store = new ConcurrentDictionary<TKey, ConcurrentQueue<TElement>> ();
Func<TKey, ConcurrentQueue<TElement>> queueFactory = (_) => new ConcurrentQueue<TElement> ();
ParallelExecuter.ProcessAndBlock (Parent, (e, c) => {
ConcurrentQueue<TElement> queue = store.GetOrAdd (keySelector (e), queueFactory);
queue.Enqueue (elementSelector (e));
});
return store;
}
}
}
#endif

View File

@@ -0,0 +1,150 @@
//
// QueryConcatNode.cs
//
// Author:
// Jérémie "Garuma" Laval <jeremie.laval@gmail.com>
//
// Copyright (c) 2010 Jérémie "Garuma" Laval
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if NET_4_0
using System;
using System.Threading;
using System.Collections;
using System.Collections.Generic;
namespace System.Linq.Parallel.QueryNodes
{
internal interface QueryHeadWorkerNode : IVisitableNode {
int? Count { get; }
}
/* This is the QueryNode used by Take(While) operator
* it symbolize operators that are preferably working on the head elements of a query and can prematurely
* stop providing elements following the one they were processing is of a greater value in a specific
* order to be defined by the instance (e.g. simple numerical order when working on indexes).
*/
internal class QueryHeadWorkerNode<TSource> : QueryStreamNode<TSource, TSource>, QueryHeadWorkerNode
{
/* This variable will receive an index value that represent the "stop point"
* when used with GetOrderedEnumerables i.e. values that are above the indexes are discarded
* (if the partitioner is ordered in a partition it even stop the processing) and value below are still tested just
* in case and can still lower this gap limit.
*/
readonly int count;
readonly Func<TSource, int, bool> predicate;
internal QueryHeadWorkerNode (QueryBaseNode<TSource> parent, int count)
: base (parent, false)
{
this.count = count;
}
internal QueryHeadWorkerNode (QueryBaseNode<TSource> parent, Func<TSource, int, bool> predicate, bool indexed)
: base (parent, indexed)
{
this.predicate = predicate;
}
public int? Count {
get {
return predicate == null ? count : (int?)null;
}
}
internal override IEnumerable<TSource> GetSequential ()
{
IEnumerable<TSource> parent = Parent.GetSequential ();
return predicate == null ? parent.Take (count) : parent.TakeWhile (predicate);
}
public override void Visit (INodeVisitor visitor)
{
visitor.Visit ((QueryHeadWorkerNode)this);
}
internal override IList<IEnumerable<TSource>> GetEnumerablesIndexed (QueryOptions options)
{
return Parent.GetOrderedEnumerables (options)
.Select ((i) => i.TakeWhile ((e) => predicate (e.Value, (int)e.Key)).Select ((e) => e.Value))
.ToList ();
}
internal override IList<IEnumerable<TSource>> GetEnumerablesNonIndexed (QueryOptions options)
{
return Parent.GetEnumerables (options)
.Select (GetSelector (count))
.ToList ();
}
Func<IEnumerable<TSource>, IEnumerable<TSource>> GetSelector (int c)
{
if (predicate == null)
return (i) => i.TakeWhile ((e) => c > 0 && Interlocked.Decrement (ref c) >= 0);
else
return (i) => i.TakeWhile ((e) => predicate (e, -1));
}
internal override IList<IEnumerable<KeyValuePair<long, TSource>>> GetOrderedEnumerables (QueryOptions options)
{
return Parent.GetOrderedEnumerables (options)
.Select ((i) => GetEnumerableInternal (i, options))
.ToList ();
}
IEnumerable<KeyValuePair<long, TSource>> GetEnumerableInternal (IEnumerable<KeyValuePair<long, TSource>> source, QueryOptions options)
{
IEnumerator<KeyValuePair<long, TSource>> current = source.GetEnumerator ();
long gapIndex = predicate == null ? count : long.MaxValue;
Func<KeyValuePair<long, TSource>, bool> cond;
if (predicate == null)
cond = (kv) => kv.Key < count;
else
cond = (kv) => predicate (kv.Value, (int)kv.Key);
try {
while (current.MoveNext ()) {
KeyValuePair<long, TSource> kvp = current.Current;
/* When filtering is based on a predicate, this short-circuit is only valid
* if the partitioner used ensure items are ordered in each partition
* (valid w/ default partitioners)
*/
if (kvp.Key >= gapIndex && options.PartitionerSettings.Item2)
break;
if (!cond (kvp)) {
if (gapIndex > kvp.Key && predicate != null)
gapIndex = kvp.Key;
continue;
}
yield return kvp;
}
} finally {
current.Dispose ();
}
}
}
}
#endif

View File

@@ -0,0 +1,188 @@
//
// QueryJoinNode.cs
//
// Author:
// Jérémie "Garuma" Laval <jeremie.laval@gmail.com>
//
// Copyright (c) 2010 Jérémie "Garuma" Laval
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if NET_4_0
using System;
using System.Threading;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Concurrent;
namespace System.Linq.Parallel.QueryNodes
{
internal class QueryJoinNode<TFirst, TSecond, TKey, TResult> : QueryMuxNode<TFirst, TSecond, TResult>
{
struct VSlot<T>
{
public readonly bool HasValue;
public readonly T Value;
public VSlot (T value)
{
HasValue = true;
Value = value;
}
}
Func<TFirst, TKey> firstKeySelector;
Func<TSecond, TKey> secondKeySelector;
Func<TFirst, TSecond, TResult> resultSelector;
IEqualityComparer<TKey> comparer;
internal QueryJoinNode (QueryBaseNode<TFirst> first,
QueryBaseNode<TSecond> second,
Func<TFirst, TKey> firstKeySelector,
Func<TSecond, TKey> secondKeySelector,
Func<TFirst, TSecond, TResult> resultSelector,
IEqualityComparer<TKey> comparer) : base (first, second)
{
this.firstKeySelector = firstKeySelector;
this.secondKeySelector = secondKeySelector;
this.resultSelector = resultSelector;
this.comparer = comparer;
}
internal override IEnumerable<TResult> GetSequential ()
{
return Parent.GetSequential ().Join (Second.GetSequential (),
firstKeySelector,
secondKeySelector,
resultSelector,
comparer);
}
internal override IList<IEnumerable<TResult>> GetEnumerables (QueryOptions options)
{
var first = Parent.GetEnumerables (options);
var second = Second.GetEnumerables (options);
if (first.Count != second.Count)
throw new InvalidOperationException ("Internal size mismatch");
var store = new TemporaryArea<TKey, Tuple<VSlot<TFirst>, VSlot<TSecond>>> (comparer);
return first
.Select ((f, i) => GetEnumerable (f, second[i], store, firstKeySelector, secondKeySelector, resultSelector))
.ToList ();
}
internal override IList<IEnumerable<KeyValuePair<long, TResult>>> GetOrderedEnumerables (QueryOptions options)
{
var first = Parent.GetOrderedEnumerables (options);
var second = Second.GetOrderedEnumerables (options);
if (first.Count != second.Count)
throw new InvalidOperationException ("Internal size mismatch");
var store = new TemporaryArea<TKey, Tuple<VSlot<KeyValuePair<long, TFirst>>, VSlot<KeyValuePair<long, TSecond>>>> (comparer);
return first
.Select ((f, i) => GetEnumerable<KeyValuePair<long, TFirst>, KeyValuePair<long, TSecond>, KeyValuePair<long, TResult>> (f,
second[i],
store,
(e) => firstKeySelector (e.Value),
(e) => secondKeySelector (e.Value),
(e1, e2) => new KeyValuePair<long, TResult> (e1.Key, resultSelector (e1.Value, e2.Value))))
.ToList ();
}
IEnumerable<T> GetEnumerable<U, V, T> (IEnumerable<U> first,
IEnumerable<V> second,
TemporaryArea<TKey, Tuple<VSlot<U>, VSlot<V>>> store,
Func<U, TKey> fKeySelect,
Func<V, TKey> sKeySelect,
Func<U, V, T> resultor)
{
IEnumerator<U> eFirst = first.GetEnumerator ();
IEnumerator<V> eSecond = second.GetEnumerator ();
try {
bool fstHasCurrent = false, sndHasCurrent = false;
Tuple<VSlot<U>, VSlot<V>> kvp;
while ((fstHasCurrent = eFirst.MoveNext ()) & (sndHasCurrent = eSecond.MoveNext ())) {
U e1 = eFirst.Current;
V e2 = eSecond.Current;
TKey key1 = fKeySelect (e1);
TKey key2 = sKeySelect (e2);
if (comparer.Equals (key1, key2)) {
yield return resultor (e1, e2);
continue;
}
do {
if (store.TryRemove (key1, out kvp) && kvp.Item2.HasValue) {
yield return resultor (e1, kvp.Item2.Value);
break;
}
} while (!store.TryAdd (key1, Tuple.Create (new VSlot<U> (e1), new VSlot<V> ())));
do {
if (store.TryRemove (key2, out kvp) && kvp.Item1.HasValue) {
yield return resultor (kvp.Item1.Value, e2);
break;
}
} while (!store.TryAdd (key2, Tuple.Create (new VSlot<U> (), new VSlot<V> (e2))));
}
if (fstHasCurrent) {
do {
U e1 = eFirst.Current;
TKey key1 = fKeySelect (e1);
do {
if (store.TryRemove (key1, out kvp) && kvp.Item2.HasValue) {
yield return resultor (e1, kvp.Item2.Value);
break;
}
} while (!store.TryAdd (key1, Tuple.Create (new VSlot<U> (e1), new VSlot<V> ())));
} while (eFirst.MoveNext ());
}
if (sndHasCurrent) {
do {
V e2 = eSecond.Current;
TKey key2 = sKeySelect (e2);
do {
if (store.TryRemove (key2, out kvp) && kvp.Item1.HasValue) {
yield return resultor (kvp.Item1.Value, e2);
break;
}
} while (!store.TryAdd (key2, Tuple.Create (new VSlot<U> (), new VSlot<V> (e2))));
} while (eSecond.MoveNext ());
}
} finally {
eFirst.Dispose ();
eSecond.Dispose ();
}
}
}
}
#endif

View File

@@ -0,0 +1,61 @@
//
// QueryMuxNode.cs
//
// Author:
// Jérémie "Garuma" Laval <jeremie.laval@gmail.com>
//
// Copyright (c) 2010 Jérémie "Garuma" Laval
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if NET_4_0
using System;
using System.Linq;
using System.Collections.Generic;
using System.Collections.Concurrent;
namespace System.Linq.Parallel.QueryNodes
{
internal interface QueryMuxNode : IVisitableNode {
}
internal abstract class QueryMuxNode<TFirst, TSecond, TResult> : QueryChildNode<TResult, TFirst>, QueryMuxNode
{
QueryBaseNode<TSecond> second;
internal QueryMuxNode (QueryBaseNode<TFirst> parent, QueryBaseNode<TSecond> second)
: base (parent)
{
this.second = second;
}
internal QueryBaseNode<TSecond> Second {
get {
return second;
}
}
public override void Visit (INodeVisitor visitor)
{
visitor.Visit ((QueryMuxNode)this);
}
}
}
#endif

View File

@@ -0,0 +1,160 @@
//
// QueryOptionNode.cs
//
// Author:
// Jérémie "Garuma" Laval <jeremie.laval@gmail.com>
//
// Copyright (c) 2010 Jérémie "Garuma" Laval
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if NET_4_0
using System;
using System.Threading;
using System.Collections.Generic;
namespace System.Linq.Parallel.QueryNodes
{
// The first four elements correspond to the public operator With*
// Last CancellationToken parameter is used internally for ImplementerToken
using OptionsList = Tuple<ParallelMergeOptions?, ParallelExecutionMode?, CancellationToken?, int, CancellationTokenSource>;
interface QueryOptionNode : IVisitableNode {
OptionsList GetOptions ();
}
internal class QueryOptionNode<T> : QueryChildNode<T, T>, QueryOptionNode
{
public QueryOptionNode (QueryBaseNode<T> parent)
: base (parent)
{
}
public virtual OptionsList GetOptions ()
{
return new OptionsList (null, null, null, -1, null);
}
internal override IList<IEnumerable<T>> GetEnumerables (QueryOptions options)
{
return Parent.GetEnumerables (options);
}
internal override IList<IEnumerable<KeyValuePair<long, T>>> GetOrderedEnumerables (QueryOptions options)
{
return Parent.GetOrderedEnumerables (options);
}
internal override IEnumerable<T> GetSequential ()
{
return Parent.GetSequential ();
}
public override void Visit (INodeVisitor visitor)
{
visitor.Visit ((QueryOptionNode)this);
}
}
internal class ParallelExecutionModeNode<T> : QueryOptionNode<T>
{
ParallelExecutionMode mode;
internal ParallelExecutionModeNode (ParallelExecutionMode mode, QueryBaseNode<T> parent)
: base (parent)
{
this.mode = mode;
}
public override OptionsList GetOptions ()
{
return new OptionsList (null, mode, null, -1, null);
}
}
internal class ParallelMergeOptionsNode<T> : QueryOptionNode<T>
{
ParallelMergeOptions opts;
internal ParallelMergeOptionsNode (ParallelMergeOptions opts, QueryBaseNode<T> parent)
: base (parent)
{
this.opts = opts;
}
public override OptionsList GetOptions ()
{
return new OptionsList (opts, null, null, -1, null);
}
}
internal class CancellationTokenNode<T> : QueryOptionNode<T>
{
CancellationToken token;
internal CancellationTokenNode (CancellationToken token, QueryBaseNode<T> parent)
: base (parent)
{
this.token = token;
}
public override OptionsList GetOptions ()
{
return new OptionsList (null, null, token, -1, null);
}
}
internal class DegreeOfParallelismNode<T> : QueryOptionNode<T>
{
int degreeParallelism;
internal DegreeOfParallelismNode (int degreeParallelism, QueryBaseNode<T> parent)
: base (parent)
{
this.degreeParallelism = degreeParallelism;
}
public override OptionsList GetOptions ()
{
return new OptionsList (null, null, null, degreeParallelism, null);
}
}
internal class ImplementerTokenNode<T> : QueryOptionNode<T>
{
CancellationTokenSource source;
internal ImplementerTokenNode (CancellationTokenSource token, QueryBaseNode<T> parent)
: base (parent)
{
this.source = token;
}
public override OptionsList GetOptions ()
{
return new OptionsList (null, null, null, -1, source);
}
}
}
#endif

View File

@@ -0,0 +1,122 @@
//
// QueryOrderByNode.cs
//
// Author:
// Jérémie "Garuma" Laval <jeremie.laval@gmail.com>
//
// Copyright (c) 2010 Jérémie "Garuma" Laval
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if NET_4_0
using System;
using System.Threading;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Concurrent;
namespace System.Linq.Parallel.QueryNodes
{
internal class QueryOrderByNode<T> : QueryOrderGuardNode<T>
{
Comparison<T> comparison;
public QueryOrderByNode (QueryBaseNode<T> parent, Comparison<T> comparison)
: base (parent, true)
{
this.comparison = comparison;
}
public QueryOrderByNode (QueryOrderByNode<T> parent, Comparison<T> comparison)
: base (parent.Parent, true)
{
this.comparison = MergeComparison (parent.ComparisonFunc, comparison);
}
public Comparison<T> ComparisonFunc {
get {
return comparison;
}
}
internal override IEnumerable<T> GetSequential ()
{
return Parent.GetSequential ().OrderBy ((e) => e, new ComparisonComparer (comparison));
}
private class ComparisonComparer : IComparer<T>
{
Comparison<T> comparison;
internal ComparisonComparer (Comparison<T> comparison)
{
this.comparison = comparison;
}
int IComparer<T>.Compare (T x, T y)
{
return comparison (x, y);
}
}
internal override IList<IEnumerable<T>> GetEnumerables (QueryOptions options)
{
throw new InvalidOperationException ("Shouldn't be called");
}
internal override IList<IEnumerable<KeyValuePair<long, T>>> GetOrderedEnumerables (QueryOptions options)
{
int partitionCount;
IList<T> aggregList = GetAggregatedList (out partitionCount);
IList<T> result = ParallelQuickSort<T>.Sort (aggregList, comparison);
OrderablePartitioner<T> partitioner = ParallelPartitioner.CreateForStrips (result, 1);
return WrapHelper.Wrap (partitioner.GetOrderablePartitions (options.PartitionCount));
}
IList<T> GetAggregatedList (out int partitionCount)
{
AggregationList<T> result = null;
partitionCount = -1;
ParallelExecuter.ProcessAndAggregate<T, IList<T>> (Parent, () => new List<T> (),
LocalCall,
(ls) => { result = new AggregationList<T> (ls); });
return result;
}
IList<T> LocalCall (IList<T> list, T element)
{
list.Add (element);
return list;
}
static Comparison<T> MergeComparison (Comparison<T> source, Comparison<T> other)
{
return (e1, e2) => {
int result = source (e1, e2);
return result == 0 ? other (e1, e2) : result;
};
}
}
}
#endif

View File

@@ -0,0 +1,103 @@
// QueryOrderGuardNode.cs
//
// Author:
// Jérémie "Garuma" Laval <jeremie.laval@gmail.com>
//
// Copyright (c) 2010 Jérémie "Garuma" Laval
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if NET_4_0
using System;
using System.Collections.Generic;
namespace System.Linq.Parallel.QueryNodes
{
internal interface QueryOrderGuardNode : IVisitableNode {
bool EnsureOrder { get; }
}
internal abstract class QueryOrderGuardNode<T> : QueryStreamNode<T, T>, QueryOrderGuardNode
{
bool ensureOrder;
internal QueryOrderGuardNode (QueryBaseNode<T> parent, bool ensureOrder)
: base (parent, ensureOrder)
{
this.ensureOrder = ensureOrder;
}
public bool EnsureOrder {
get {
return ensureOrder;
}
}
internal override IEnumerable<T> GetSequential ()
{
return Parent.GetSequential ();
}
public override void Visit (INodeVisitor visitor)
{
visitor.Visit ((QueryOrderGuardNode)this);
}
}
internal class QueryAsUnorderedNode<T> : QueryOrderGuardNode<T>
{
internal QueryAsUnorderedNode (QueryBaseNode<T> parent)
: base (parent, false)
{
}
internal override IList<IEnumerable<T>> GetEnumerables (QueryOptions options)
{
return Parent.GetEnumerables (options);
}
internal override IList<IEnumerable<KeyValuePair<long, T>>> GetOrderedEnumerables (QueryOptions options)
{
return Parent.GetOrderedEnumerables (options);
}
}
internal class QueryAsOrderedNode<T> : QueryOrderGuardNode<T>
{
internal QueryAsOrderedNode (QueryBaseNode<T> parent)
: base (parent, true)
{
}
internal override IList<IEnumerable<T>> GetEnumerables (QueryOptions options)
{
return Parent.GetEnumerables (options);
}
internal override IList<IEnumerable<KeyValuePair<long, T>>> GetOrderedEnumerables (QueryOptions options)
{
return Parent.GetOrderedEnumerables (options);
}
}
}
#endif

View File

@@ -0,0 +1,40 @@
//
// QueryOrderedStreamNode.cs
//
// Author:
// Jérémie "Garuma" Laval <jeremie.laval@gmail.com>
//
// Copyright (c) 2010 Jérémie "Garuma" Laval
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if NET_4_0
using System;
namespace System.Linq.Parallel.QueryNodes
{
internal abstract class QueryOrderedStreamNode<T, TParent> : QueryStreamNode<T, TParent>
{
internal QueryOrderedStreamNode (QueryBaseNode<TParent> parent, bool isIndexed)
: base (parent, isIndexed)
{
}
}
}
#endif

View File

@@ -0,0 +1,67 @@
//
// QueryReverseNode.cs
//
// Author:
// Jérémie "Garuma" Laval <jeremie.laval@gmail.com>
//
// Copyright (c) 2010 Jérémie "Garuma" Laval
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if NET_4_0
using System;
using System.Linq;
using System.Threading;
using System.Collections.Generic;
using System.Collections.Concurrent;
namespace System.Linq.Parallel.QueryNodes
{
internal class QueryReverseNode<TSource> : QueryStreamNode<TSource, TSource>
{
ParallelQuery<TSource> source;
public QueryReverseNode (ParallelQuery<TSource> source)
: base (source.Node, false)
{
this.source = source;
}
internal override IEnumerable<TSource> GetSequential ()
{
return Parent.GetSequential ().Reverse ();
}
// As stated in the doc, in this case we do nothing
internal override IList<IEnumerable<TSource>> GetEnumerables (QueryOptions options)
{
return Parent.GetEnumerables (options);
}
internal override IList<IEnumerable<KeyValuePair<long, TSource>>> GetOrderedEnumerables (QueryOptions options)
{
ReverseList<TSource> reversed = new ReverseList<TSource> (source.ToListOrdered ());
OrderablePartitioner<TSource> partitioner = ParallelPartitioner.CreateForStrips (reversed, 1);
return WrapHelper.Wrap (partitioner.GetOrderablePartitions (options.PartitionCount));
}
}
}
#endif

View File

@@ -0,0 +1,207 @@
//
// QueryConcatNode.cs
//
// Author:
// Jérémie "Garuma" Laval <jeremie.laval@gmail.com>
//
// Copyright (c) 2010 Jérémie "Garuma" Laval
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if NET_4_0
using System;
using System.Threading;
using System.Collections;
using System.Collections.Generic;
namespace System.Linq.Parallel.QueryNodes
{
internal class QuerySelectManyNode<TSource, TCollection, TResult> : QueryStreamNode<TResult, TSource>
{
Func<TSource, IEnumerable<TCollection>> collectionSelector;
Func<TSource, int, IEnumerable<TCollection>> collectionSelectorIndexed;
Func<TSource, TCollection, TResult> resultSelector;
internal QuerySelectManyNode (QueryBaseNode<TSource> parent,
Func<TSource, int, IEnumerable<TCollection>> collectionSelectorIndexed,
Func<TSource, TCollection, TResult> resultSelector)
: base (parent, true)
{
this.collectionSelectorIndexed = collectionSelectorIndexed;
this.resultSelector = resultSelector;
}
internal QuerySelectManyNode (QueryBaseNode<TSource> parent,
Func<TSource, IEnumerable<TCollection>> collectionSelector,
Func<TSource, TCollection, TResult> resultSelector)
: base (parent, false)
{
this.collectionSelector = collectionSelector;
this.resultSelector = resultSelector;
}
internal override IEnumerable<TResult> GetSequential ()
{
IEnumerable<TSource> source = Parent.GetSequential ();
return IsIndexed ?
source.SelectMany (collectionSelectorIndexed, resultSelector) :
source.SelectMany (collectionSelector, resultSelector);
}
internal override IList<IEnumerable<TResult>> GetEnumerablesIndexed (QueryOptions options)
{
return Parent.GetOrderedEnumerables (options)
.Select ((i) => GetEnumerableInternal (i,
(kv) => collectionSelectorIndexed (kv.Value, (int)kv.Key),
(e, c) => resultSelector (e.Value, c)))
.ToList ();
}
internal override IList<IEnumerable<TResult>> GetEnumerablesNonIndexed (QueryOptions options)
{
return Parent.GetEnumerables (options)
.Select ((i) => GetEnumerableInternal (i,
collectionSelector,
(e, c) => resultSelector (e, c)))
.ToList ();
}
internal override IList<IEnumerable<KeyValuePair<long, TResult>>> GetOrderedEnumerables (QueryOptions options)
{
var source = Parent.GetOrderedEnumerables (options);
var sizeRequests = new SizeRequest[source.Count];
long deviation = 0;
Barrier barrier = new Barrier (source.Count, delegate (Barrier b) {
Array.Sort (sizeRequests, KeyComparator);
for (int i = 0; i < b.ParticipantCount; ++i) {
if (sizeRequests[i].Key == -1)
continue;
sizeRequests[i].Key = deviation;
deviation += sizeRequests[i].Size;
}
});
return source
.Select ((i, ind) => GetOrderedEnumerableInternal (i, sizeRequests, ind, barrier))
.ToList ();
}
IEnumerable<TResult> GetEnumerableInternal<T> (IEnumerable<T> source,
Func<T, IEnumerable<TCollection>> collectionner,
Func<T, TCollection, TResult> packer)
{
foreach (T element in source)
foreach (TCollection item in collectionner (element))
yield return packer (element, item);
}
IEnumerable<KeyValuePair<long, TResult>> GetOrderedEnumerableInternal (IEnumerable<KeyValuePair<long, TSource>> source,
SizeRequest[] sizeRequests,
int index,
Barrier barrier)
{
IEnumerator<KeyValuePair<long, TSource>> enumerator = source.GetEnumerator ();
bool isIndexed = IsIndexed;
try {
while (true) {
KeyValuePair<long, TSource> element;
IEnumerable<TCollection> collection;
if (enumerator.MoveNext ()) {
element = enumerator.Current;
collection = isIndexed ?
collectionSelectorIndexed (element.Value, (int)element.Key) :
collectionSelector (element.Value);
var count = GetCount (ref collection);
sizeRequests[index].Update (element.Key, count, collection, element.Value);
}
barrier.SignalAndWait ();
long i = sizeRequests[index].Key;
collection = sizeRequests[index].Collection;
var elementValue = sizeRequests[index].ElementValue;
sizeRequests[index].Clear ();
if (i == -1)
break;
foreach (TCollection item in collection)
yield return new KeyValuePair<long, TResult> (i++, resultSelector (elementValue, item));
}
} finally {
barrier.RemoveParticipant ();
enumerator.Dispose ();
}
}
/* If getting Count is a O(1) operation (i.e. actual is a ICollection) then return it immediatly
* if not process the IEnumerable into a List and return the Count from that (i.e. enumerable
* processing will only happen once in case of e.g. a Linq query)
*/
static int GetCount<T> (ref IEnumerable<T> actual)
{
ICollection coll = actual as ICollection;
if (coll != null)
return coll.Count;
var foo = actual.ToList ();
actual = foo;
return foo.Count;
}
static int KeyComparator (SizeRequest e1, SizeRequest e2)
{
return e1.Key.CompareTo (e2.Key);
}
struct SizeRequest
{
public long Key;
public int Size;
public IEnumerable<TCollection> Collection;
public TSource ElementValue;
public void Update (long k, int s, IEnumerable<TCollection> c, TSource ev)
{
Key = k;
Size = s;
Collection = c;
ElementValue = ev;
}
public void Clear ()
{
Key = -1;
Size = 0;
Collection = null;
ElementValue = default (TSource);
}
}
}
}
#endif

View File

@@ -0,0 +1,84 @@
//
// QuerySelectNode.cs
//
// Author:
// Jérémie "Garuma" Laval <jeremie.laval@gmail.com>
//
// Copyright (c) 2010 Jérémie "Garuma" Laval
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if NET_4_0
using System;
using System.Linq;
using System.Collections.Generic;
using System.Collections.Concurrent;
namespace System.Linq.Parallel.QueryNodes
{
internal class QuerySelectNode<TResult, TSource> : QueryStreamNode<TResult, TSource>
{
Func<TSource, int, TResult> indexedSelector;
Func<TSource, TResult> selector;
internal QuerySelectNode (QueryBaseNode<TSource> parent, Func<TSource, TResult> selector)
: base (parent, false)
{
this.selector = selector;
}
internal QuerySelectNode (QueryBaseNode<TSource> parent, Func<TSource, int, TResult> selector)
: base (parent, true)
{
this.indexedSelector = selector;
}
internal override IEnumerable<TResult> GetSequential ()
{
return IsIndexed ?
Parent.GetSequential ().Select (indexedSelector) :
Parent.GetSequential ().Select (selector);
}
internal override IList<IEnumerable<TResult>> GetEnumerablesIndexed (QueryOptions options)
{
return Parent.GetOrderedEnumerables (options)
.Select ((i) => i.Select ((e) => indexedSelector (e.Value, (int)e.Key)))
.ToList ();
}
internal override IList<IEnumerable<TResult>> GetEnumerablesNonIndexed (QueryOptions options)
{
return Parent.GetEnumerables (options)
.Select ((i) => i.Select (selector))
.ToList ();
}
internal override IList<IEnumerable<KeyValuePair<long, TResult>>> GetOrderedEnumerables (QueryOptions options)
{
return Parent.GetOrderedEnumerables (options)
.Select ((i) =>
IsIndexed ?
i.Select ((e) => new KeyValuePair<long, TResult> (e.Key, indexedSelector (e.Value, (int)e.Key))) :
i.Select ((e) => new KeyValuePair<long, TResult> (e.Key, selector (e.Value))))
.ToList ();
}
}
}
#endif

View File

@@ -0,0 +1,144 @@
//
// QueryMuxNode.cs
//
// Author:
// Jérémie "Garuma" Laval <jeremie.laval@gmail.com>
//
// Copyright (c) 2010 Jérémie "Garuma" Laval
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if NET_4_0
using System;
using System.Linq;
using System.Collections.Generic;
using System.Collections.Concurrent;
namespace System.Linq.Parallel.QueryNodes
{
internal class QuerySetNode<TSource> : QueryMuxNode<TSource, TSource, TSource>
{
readonly SetInclusion setInclusion;
readonly IEqualityComparer<TSource> comparer;
internal QuerySetNode (SetInclusion setInclusion, IEqualityComparer<TSource> comparer,
QueryBaseNode<TSource> first, QueryBaseNode<TSource> second)
: base (first, second)
{
this.setInclusion = setInclusion;
this.comparer = comparer;
}
internal override IEnumerable<TSource> GetSequential ()
{
var first = Parent.GetSequential ();
var second = Second == null ? null : Second.GetSequential ();
// We try to do some guessing based on the default
switch (setInclusion) {
case SetInclusionDefaults.Union:
return first.Union (second, comparer);
case SetInclusionDefaults.Intersect:
return first.Intersect (second, comparer);
case SetInclusionDefaults.Except:
return first.Except (second, comparer);
case SetInclusionDefaults.Distinct:
return first.Distinct (comparer);
}
// Default is we return the bare source enumerable
return first;
}
internal override IList<IEnumerable<TSource>> GetEnumerables (QueryOptions options)
{
var first = Parent.GetEnumerables (options);
var second = Second.GetEnumerables (options);
var checker = new ConcurrentDictionary<TSource, object> (comparer);
InitConcurrentDictionary (checker, second, (e) => e);
return first
.Select ((f, i) => GetEnumerable<TSource> (f, second[i], checker, (e) => e))
.ToList ();
}
internal override IList<IEnumerable<KeyValuePair<long, TSource>>> GetOrderedEnumerables (QueryOptions options)
{
var first = Parent.GetOrderedEnumerables (options);
var second = Second.GetOrderedEnumerables (options);
var checker = new ConcurrentDictionary<TSource, object> (comparer);
InitConcurrentDictionary (checker, second, (e) => e.Value);
return first
.Select ((f, i) => GetEnumerable<KeyValuePair<long, TSource>> (f, second[i], checker, (e) => e.Value))
.ToList ();
}
void InitConcurrentDictionary<TExtract> (ConcurrentDictionary<TSource, object> checker,
IList<IEnumerable<TExtract>> feeds,
Func<TExtract, TSource> extractor)
{
if ((setInclusion & SetInclusion.Preload) == 0)
return;
foreach (IEnumerable<TExtract> feed in feeds)
foreach (TExtract item in feed)
checker.TryAdd (extractor (item), null);
}
IEnumerable<TExtract> GetEnumerable<TExtract> (IEnumerable<TExtract> first,
IEnumerable<TExtract> second,
ConcurrentDictionary<TSource, object> checker,
Func<TExtract, TSource> extractor)
{
IEnumerator<TExtract> eFirst = first.GetEnumerator ();
IEnumerator<TExtract> eSecond = second == null ? null : second.GetEnumerator ();
IEnumerator<TExtract> current = eFirst;
bool outInclusion = (setInclusion & SetInclusion.Out) > 0;
bool preload = (setInclusion & SetInclusion.Preload) > 0;
bool relaxed = (setInclusion & SetInclusion.Relaxed) > 0;
try {
while (current != null) {
while (current.MoveNext ()) {
bool result = relaxed ?
checker.ContainsKey (extractor (current.Current)) : checker.TryAdd (extractor (current.Current), null);
if ((result && outInclusion)
|| (!result && !outInclusion))
yield return current.Current;
}
if (current == eFirst && !preload)
current = eSecond;
else
break;
}
} finally {
eFirst.Dispose ();
eSecond.Dispose ();
}
}
}
}
#endif

View File

@@ -0,0 +1,127 @@
//
// QueryStartNode.cs
//
// Author:
// Jérémie "Garuma" Laval <jeremie.laval@gmail.com>
//
// Copyright (c) 2010 Jérémie "Garuma" Laval
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if NET_4_0
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
namespace System.Linq.Parallel.QueryNodes
{
internal interface QueryStartNode : IVisitableNode {
int Count { get; }
}
internal class QueryStartNode<T> : QueryBaseNode<T>, QueryStartNode
{
readonly IEnumerable<T> source;
readonly Partitioner<T> customPartitioner;
internal QueryStartNode (IEnumerable<T> source)
{
if (source == null)
throw new ArgumentNullException ("source");
this.source = source;
}
internal QueryStartNode (Partitioner<T> custom)
{
if (custom == null)
throw new ArgumentNullException ("custom");
this.customPartitioner = custom;
}
// If possible, this property will return the number of element the query
// is going to process. If that number if pretty low, executing the query
// sequentially is better
public int Count {
get {
if (source == null)
return -1;
ICollection coll = source as ICollection;
return coll == null ? -1 : coll.Count;
}
}
public override void Visit (INodeVisitor visitor)
{
visitor.Visit ((QueryStartNode)this);
}
internal override IEnumerable<T> GetSequential ()
{
if (source != null)
return source;
return WrapHelper.Wrap (customPartitioner.GetPartitions (1))[0];
}
internal override IList<IEnumerable<T>> GetEnumerables (QueryOptions options)
{
if (customPartitioner != null) {
return WrapHelper.Wrap (customPartitioner.GetPartitions (options.PartitionCount));
}
Partitioner<T> partitioner
= (options.UseStrip) ? ParallelPartitioner.CreateForStrips (source, 1) : ParallelPartitioner.CreateBest (source);
return WrapHelper.Wrap (partitioner.GetPartitions (options.PartitionCount));
}
internal override IList<IEnumerable<KeyValuePair<long, T>>> GetOrderedEnumerables (QueryOptions options)
{
OrderablePartitioner<T> partitioner = null;
if (customPartitioner != null) {
partitioner = customPartitioner as OrderablePartitioner<T>;
if (partitioner == null)
throw new InvalidOperationException ("The partitionner you are using doesn't support ordered partitionning");
} else {
partitioner =
(options.UseStrip) ? ParallelPartitioner.CreateForStrips (source, 1) : ParallelPartitioner.CreateBest (source);
}
options.PartitionerSettings = Tuple.Create (partitioner.KeysOrderedAcrossPartitions,
partitioner.KeysOrderedInEachPartition,
partitioner.KeysNormalized);
// We only support one style of partitioning at the moment.
// Standard partitioners follow this style.
if (options.UseStrip && (!partitioner.KeysOrderedInEachPartition || partitioner.KeysOrderedAcrossPartitions))
throw new NotImplementedException ("Partitioner must have KeysOrderedInEachPartition "
+ "and !KeysOrderedAcrossPartitions"
+ "to be used with indexed operators");
return WrapHelper.Wrap (partitioner.GetOrderablePartitions (options.PartitionCount));
}
}
}
#endif

View File

@@ -0,0 +1,79 @@
//
// QueryStreamNode.cs
//
// Author:
// Jérémie "Garuma" Laval <jeremie.laval@gmail.com>
//
// Copyright (c) 2010 Jérémie "Garuma" Laval
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if NET_4_0
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Generic;
namespace System.Linq.Parallel.QueryNodes
{
internal interface QueryStreamNode : IVisitableNode {
bool IsIndexed { get; }
}
internal abstract class QueryStreamNode<T, TParent> : QueryChildNode<T, TParent>, QueryStreamNode
{
bool isIndexed;
internal QueryStreamNode (QueryBaseNode<TParent> parent, bool isIndexed)
: base (parent)
{
this.isIndexed = isIndexed;
}
internal override IList<IEnumerable<T>> GetEnumerables (QueryOptions options)
{
if (IsIndexed)
return GetEnumerablesIndexed (options);
else
return GetEnumerablesNonIndexed (options);
}
internal virtual IList<IEnumerable<T>> GetEnumerablesIndexed (QueryOptions options)
{
return null;
}
internal virtual IList<IEnumerable<T>> GetEnumerablesNonIndexed (QueryOptions options)
{
return null;
}
public override void Visit (INodeVisitor visitor)
{
visitor.Visit ((QueryStreamNode)this);
}
public bool IsIndexed {
get {
return isIndexed;
}
}
}
}
#endif

Some files were not shown because too many files have changed in this diff Show More