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,135 @@
//
// AggregationList.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;
namespace System.Linq.Parallel
{
internal class AggregationList<T> : IList<T>
{
readonly IList<IList<T>> listes;
readonly int count;
internal AggregationList (IList<IList<T>> listes)
{
this.listes = listes;
foreach (var l in listes)
count += l.Count;
}
public int IndexOf (T item)
{
throw new NotImplementedException();
}
public void Insert (int index, T item)
{
throw new NotImplementedException();
}
public void RemoveAt (int index)
{
throw new NotImplementedException();
}
public T this[int index] {
get {
int listIndex, newIndex;
GetModifiedIndexes (index, out listIndex, out newIndex);
return listes[listIndex][newIndex];
}
set {
throw new NotImplementedException();
}
}
void GetModifiedIndexes (int index, out int listIndex, out int newIndex)
{
listIndex = 0;
newIndex = index;
while (newIndex >= listes[listIndex].Count) {
newIndex -= listes[listIndex].Count;
listIndex++;
if (listIndex > listes.Count)
throw new ArgumentOutOfRangeException ();
}
}
public void Add (T item)
{
throw new NotImplementedException();
}
public void Clear ()
{
throw new NotImplementedException();
}
public bool Contains (T item)
{
throw new NotImplementedException();
}
public void CopyTo (T[] array, int arrayIndex)
{
throw new NotImplementedException();
}
public bool Remove (T item)
{
throw new NotImplementedException();
}
public int Count {
get {
return count;
}
}
public bool IsReadOnly {
get {
return true;
}
}
IEnumerator<T> IEnumerable<T>.GetEnumerator ()
{
return null;
}
IEnumerator IEnumerable.GetEnumerator ()
{
return null;
}
}
}
#endif

View File

@ -0,0 +1,17 @@
2010-04-29 Jérémie Laval <jeremie.laval@gmail.com>
* OrderingEnumerator.cs: Use new non-blocking collection
for storing indexed elements.
2010-04-15 Jérémie Laval <jeremie.laval@gmail.com>
* AggregationList.cs:
* ConcurrentGrouping.cs:
* ConcurrentLookup.cs:
* OrderingEnumerator.cs:
* ParallelQuickSort.cs:
* RangeList.cs:
* RepeatList.cs:
* ReverseList.cs:
* StripPartitioner.cs: Initial check-in of PLinq

View File

@ -0,0 +1,65 @@
//
// ConcurrentGrouping.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
{
internal class ConcurrentGrouping<TKey, TElement> : IGrouping<TKey, TElement>
{
TKey key;
IEnumerable<TElement> elements;
internal ConcurrentGrouping (TKey key, IEnumerable<TElement> elements)
{
this.key = key;
this.elements = elements;
}
public TKey Key {
get {
return key;
}
}
IEnumerator IEnumerable.GetEnumerator ()
{
return ((IEnumerable)elements).GetEnumerator ();
}
IEnumerator<TElement> IEnumerable<TElement>.GetEnumerator ()
{
return elements.GetEnumerator ();
}
}
}
#endif

View File

@ -0,0 +1,117 @@
//
// ConcurrentLookup.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
{
internal class ConcurrentLookup<TKey, TElement> : ILookup<TKey, TElement>
{
ConcurrentDictionary<TKey, IEnumerable<TElement>> dictionary;
private class AddSlot
{
TElement element;
internal AddSlot (TElement element)
{
this.element = element;
}
internal IEnumerable<TElement> AddMethod (TKey key)
{
List<TElement> list = new List<TElement> ();
list.Add (element);
return list;
}
internal IEnumerable<TElement> UpdateMethod (TKey key, IEnumerable<TElement> old)
{
ICollection<TElement> coll = (ICollection<TElement>)old;
coll.Add (element);
return coll;
}
}
internal ConcurrentLookup (IEqualityComparer<TKey> comparer)
{
this.dictionary = new ConcurrentDictionary<TKey, IEnumerable<TElement>> (comparer);
}
internal void Add (TKey key, TElement element)
{
AddSlot slot = new AddSlot (element);
dictionary.AddOrUpdate (key, slot.AddMethod, slot.UpdateMethod);
}
public bool Contains (TKey key)
{
return dictionary.ContainsKey (key);
}
public IEnumerable<TElement> this[TKey key] {
get {
return dictionary[key];
}
}
public int Count {
get {
return dictionary.Count;
}
}
public IList<TKey> Keys {
get {
return (IList<TKey>)dictionary.Keys;
}
}
IEnumerator IEnumerable.GetEnumerator ()
{
return (IEnumerator)GetEnumeratorInternal ();
}
IEnumerator<IGrouping<TKey, TElement>> IEnumerable<IGrouping<TKey, TElement>>.GetEnumerator ()
{
return GetEnumeratorInternal ();
}
IEnumerator<IGrouping<TKey, TElement>> GetEnumeratorInternal ()
{
return (IEnumerator<System.Linq.IGrouping<TKey,TElement>>) dictionary.Select ((pair) => new ConcurrentGrouping<TKey, TElement> (pair.Key, pair.Value)).GetEnumerator ();
}
}
}
#endif

View File

@ -0,0 +1,45 @@
//
// INodeVisitor.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.Parallel.QueryNodes;
namespace System.Linq.Parallel
{
internal interface INodeVisitor
{
void Visit (QueryBaseNode node);
void Visit (QueryChildNode node);
void Visit (QueryOptionNode node);
void Visit (QueryStartNode node);
void Visit (QueryStreamNode node);
void Visit (QueryOrderGuardNode node);
void Visit (QueryMuxNode node);
void Visit (QueryHeadWorkerNode node);
}
}
#endif

View File

@ -0,0 +1,37 @@
//
// IVisitableNode.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
{
internal interface IVisitableNode
{
void Visit (INodeVisitor visitor);
}
}
#endif

View File

@ -0,0 +1,219 @@
//
// OrderingEnumerator.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
{
internal class OrderingEnumerator<T> : IEnumerator<T>
{
internal class SlotBucket
{
readonly TemporaryArea<long, T> temporaryArea = new TemporaryArea<long, T> ();
readonly KeyValuePair<long, T>[] stagingArea;
long currentIndex;
readonly int count;
CountdownEvent stagingCount;
CountdownEvent participantCount;
CancellationTokenSource src = new CancellationTokenSource ();
CancellationToken mergedToken;
public SlotBucket (int count, CancellationToken token)
{
this.count = count;
stagingCount = new CountdownEvent (count);
participantCount = new CountdownEvent (count);
stagingArea = new KeyValuePair<long, T>[count];
currentIndex = -count;
mergedToken = CancellationTokenSource.CreateLinkedTokenSource (src.Token, token).Token;
}
public void Add (KeyValuePair<long, T> value)
{
long index = value.Key;
if (index >= currentIndex && index < currentIndex + count) {
stagingArea[index % count] = value;
stagingCount.Signal ();
} else {
temporaryArea.TryAdd (index, value.Value);
if (index >= currentIndex && index < currentIndex + count) {
T dummy;
if (temporaryArea.TryRemove (index, out dummy)) {
stagingArea[index % count] = value;
stagingCount.Signal ();
}
}
}
}
// Called by each worker's endAction
public void EndParticipation ()
{
if (participantCount.Signal ())
src.Cancel ();
}
// Called at the end with ContinueAll
public void Stop ()
{
src.Cancel ();
}
bool Skim ()
{
bool result = false;
for (int i = 0; i < count; i++) {
T temp;
int index = i + (int)currentIndex;
if (stagingArea[i].Key != -1)
continue;
if (!temporaryArea.TryRemove (index, out temp))
continue;
result = true;
stagingArea [i] = new KeyValuePair<long, T> (index, temp);
if (stagingCount.Signal ())
break;
}
return result;
}
void Clean ()
{
for (int i = 0; i < stagingArea.Length; i++)
stagingArea[i] = new KeyValuePair<long, T> (-1, default (T));
}
public KeyValuePair<long, T>[] Wait ()
{
Clean ();
stagingCount.Reset ();
Interlocked.Add (ref currentIndex, count);
Skim ();
while (!stagingCount.IsSet) {
if (!participantCount.IsSet) {
try {
stagingCount.Wait (mergedToken);
} catch {
Skim ();
}
}
if (participantCount.IsSet) {
if (Skim ())
continue;
// Totally finished
if (stagingArea[0].Key != -1)
break;
else
return null;
}
}
return stagingArea;
}
}
SlotBucket slotBucket;
KeyValuePair<long, T>[] slot;
int current;
internal OrderingEnumerator (int num, CancellationToken token)
{
slotBucket = new SlotBucket (num, token);
}
public void Dispose ()
{
slotBucket.Stop ();
}
public void Reset ()
{
}
public bool MoveNext ()
{
do {
if (slot == null || ++current >= slot.Length) {
if ((slot = slotBucket.Wait ()) == null)
return false;
current = 0;
}
} while (slot[current].Key == -1);
return true;
}
public T Current {
get {
return slot[current].Value;
}
}
object IEnumerator.Current {
get {
return slot[current].Value;
}
}
public void Add (KeyValuePair<long, T> value, CancellationToken token)
{
slotBucket.Add (value);
}
// Called by each worker's endAction
public void EndParticipation ()
{
slotBucket.EndParticipation ();
}
// Called at the end with ContinueAll
public void Stop ()
{
slotBucket.Stop ();
}
}
}
#endif

View File

@ -0,0 +1,265 @@
//
// ParallelExecuter.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;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Linq.Parallel.QueryNodes;
namespace System.Linq.Parallel
{
internal static class ParallelExecuter
{
internal static QueryOptions CheckQuery<T> (QueryBaseNode<T> startingNode)
{
return CheckQuery<T> (startingNode, false);
}
internal static QueryOptions CheckQuery<T> (QueryBaseNode<T> startingNode, bool blocking)
{
return CheckQuery (startingNode, GetBestWorkerNumber (blocking));
}
internal static QueryOptions CheckQuery<T> (QueryBaseNode<T> startingNode, int partitionCount)
{
QueryCheckerVisitor visitor = new QueryCheckerVisitor (partitionCount);
startingNode.Visit (visitor);
return visitor.Options;
}
internal static CancellationToken Chain (this CancellationToken self, CancellationTokenSource other)
{
CancellationTokenSource linked = CancellationTokenSource.CreateLinkedTokenSource (self, other.Token);
return linked.Token;
}
internal static bool IsOrdered<TSource> (this QueryBaseNode<TSource> source)
{
QueryIsOrderedVisitor visitor = new QueryIsOrderedVisitor ();
source.Visit (visitor);
return visitor.BehindOrderGuard;
}
internal static int GetBestWorkerNumber ()
{
return GetBestWorkerNumber (false);
}
internal static int GetBestWorkerNumber (bool blocking)
{
return blocking && Task.CurrentId == null ? Environment.ProcessorCount + 1 : Environment.ProcessorCount;
}
internal static Task[] Process<TSource, TElement> (QueryBaseNode<TSource> node,
Action<TElement, CancellationToken> call,
Func<QueryBaseNode<TSource>, QueryOptions, IList<IEnumerable<TElement>>> acquisitionFunc,
QueryOptions options)
{
return Process<TSource, TElement> (node, call, acquisitionFunc, null, options);
}
internal static Task[] Process<TSource, TElement> (QueryBaseNode<TSource> node,
Action<TElement, CancellationToken> call,
Func<QueryBaseNode<TSource>, QueryOptions, IList<IEnumerable<TElement>>> acquisitionFunc,
Action endAction,
QueryOptions options)
{
CancellationTokenSource src
= CancellationTokenSource.CreateLinkedTokenSource (options.ImplementerToken, options.Token);
IList<IEnumerable<TElement>> enumerables = acquisitionFunc (node, options);
Task[] tasks = new Task[enumerables.Count];
for (int i = 0; i < tasks.Length; i++) {
int index = i;
tasks[i] = Task.Factory.StartNew (() => {
try {
foreach (TElement item in enumerables[index]) {
if (!CheckTokens (options))
break;
try {
call (item, src.Token);
} catch (OperationCanceledException canceledException) {
if (canceledException.CancellationToken != src.Token)
throw canceledException;
}
if (!CheckTokens (options))
break;
}
} finally {
if (endAction != null)
endAction ();
}
}, options.Token, TaskCreationOptions.AttachedToParent | TaskCreationOptions.LongRunning, TaskScheduler.Default);
}
return tasks;
}
static bool CheckTokens (QueryOptions options)
{
// This is from specific operators
if (options.ImplementerToken.IsCancellationRequested)
return false;
if (options.Token.IsCancellationRequested)
throw new OperationCanceledException (options.Token);
return true;
}
internal static void ProcessAndBlock<T> (QueryBaseNode<T> node, Action<T, CancellationToken> call)
{
QueryOptions options = CheckQuery (node, true);
Task[] tasks = Process (node, call, new QueryBaseNodeHelper<T> ().GetEnumerables, options);
Task.WaitAll (tasks, options.Token);
}
internal static Action ProcessAndCallback<T> (QueryBaseNode<T> node, Action<T, CancellationToken> call,
Action callback, QueryOptions options)
{
Task[] tasks = Process (node, call, new QueryBaseNodeHelper<T> ().GetEnumerables, options);
if (callback != null)
Task.Factory.ContinueWhenAll (tasks, (_) => callback ());
return () => Task.WaitAll (tasks, options.Token);
}
internal static Action ProcessAndCallback<T> (QueryBaseNode<T> node, Action<KeyValuePair<long, T>, CancellationToken> call,
Action endAction,
Action callback, QueryOptions options)
{
Task[] tasks = Process (node, call, new QueryBaseNodeHelper<T> ().GetOrderedEnumerables, endAction, options);
if (callback != null)
Task.Factory.ContinueWhenAll (tasks, (_) => callback ());
return () => Task.WaitAll (tasks, options.Token);
}
internal static void ProcessAndAggregate<T, U> (QueryBaseNode<T> node,
Func<U> seedFunc,
Func<U, T, U> localCall,
Action<IList<U>> call)
{
QueryOptions options = CheckQuery (node, true);
IList<IEnumerable<T>> enumerables = node.GetEnumerables (options);
U[] locals = new U[enumerables.Count];
Task[] tasks = new Task[enumerables.Count];
if (seedFunc != null) {
for (int i = 0; i < locals.Length; i++)
locals[i] = seedFunc ();
}
for (int i = 0; i < tasks.Length; i++) {
var procSlot = new AggregateProcessSlot<T, U> (options,
i,
enumerables[i].GetEnumerator (),
locals,
localCall,
seedFunc);
tasks[i] = Task.Factory.StartNew (procSlot.Process, options.Token);
}
Task.WaitAll (tasks, options.Token);
if (call != null)
call (locals);
}
class AggregateProcessSlot<T, U>
{
readonly QueryOptions options;
readonly int index;
readonly IEnumerator<T> enumerator;
readonly U[] locals;
readonly Func<U, T, U> localCall;
readonly Func<U> seedFunc;
public AggregateProcessSlot (QueryOptions options,
int index,
IEnumerator<T> enumerator,
U[] locals,
Func<U, T, U> localCall,
Func<U> seedFunc)
{
this.options = options;
this.index = index;
this.enumerator = enumerator;
this.locals = locals;
this.localCall = localCall;
this.seedFunc = seedFunc;
}
public void Process ()
{
var token = options.Token;
var implementerToken = options.ImplementerToken;
try {
if (seedFunc == null) {
if (!enumerator.MoveNext ())
return;
locals[index] = (U)(object)enumerator.Current;
}
while (enumerator.MoveNext ()) {
if (implementerToken.IsCancellationRequested)
break;
token.ThrowIfCancellationRequested ();
locals[index] = localCall (locals[index], enumerator.Current);
}
} finally {
enumerator.Dispose ();
}
}
}
class QueryBaseNodeHelper<T>
{
internal IList<IEnumerable<T>> GetEnumerables (QueryBaseNode<T> source, QueryOptions options)
{
return source.GetEnumerables (options);
}
internal IList<IEnumerable<KeyValuePair<long,T>>> GetOrderedEnumerables (QueryBaseNode<T> source, QueryOptions options)
{
return source.GetOrderedEnumerables (options);
}
}
}
}
#endif

View File

@ -0,0 +1,77 @@
//
// ParallelPartitioner.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;
using System.Collections.Concurrent;
using System.Collections.Concurrent.Partitioners;
namespace System.Linq.Parallel
{
internal static class ParallelPartitioner
{
internal static OrderablePartitioner<T> CreateForChunks<T> (IEnumerable<T> source)
{
return Partitioner.Create (source);
}
internal static OrderablePartitioner<T> CreateForRange<T> (IList<T> source)
{
return Partitioner.Create (source, true);
}
internal static OrderablePartitioner<T> CreateBest<T> (IEnumerable<T> source)
{
IList<T> temp = source as IList<T>;
if (temp != null)
return CreateForRange (temp);
return CreateForChunks (source);
}
internal static OrderablePartitioner<T> CreateForStrips<T> (IEnumerable<T> source, int stripSize)
{
IList<T> temp = source as IList<T>;
if (temp != null)
return new StripPartitioner<T> (temp);
return new EnumerablePartitioner<T> (source, stripSize, 1);
}
internal static OrderablePartitioner<int> CreateForRange (int start, int count)
{
return CreateForRange<int> (new RangeList (start, count));
}
internal static OrderablePartitioner<T> CreateForRepeat<T> (T obj, int count)
{
return CreateForRange<T> (new RepeatList<T> (obj, count));
}
}
}
#endif

View File

@ -0,0 +1,131 @@
//
// ParallelEnumerator.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;
using System.Linq.Parallel.QueryNodes;
namespace System.Linq.Parallel
{
internal class ParallelQueryEnumerator<T> : IEnumerator<T>
{
readonly int DefaultBufferSize = ParallelExecuter.GetBestWorkerNumber () * 50;
BlockingCollection<T> buffer;
IEnumerator<T> loader;
QueryOptions options;
OrderingEnumerator<T> ordEnumerator;
T current;
Action waitAction;
internal ParallelQueryEnumerator (QueryBaseNode<T> node)
{
this.options = ParallelExecuter.CheckQuery (node);
if (options.ShouldBeSequential && options.Mode != ParallelExecutionMode.ForceParallelism) {
IEnumerable<T> buffer = node.GetSequential ();
loader = buffer.GetEnumerator ();
} else {
Setup ();
// Launch adding to the buffer asynchronously via Tasks
if (options.BehindOrderGuard.Value) {
waitAction = ParallelExecuter.ProcessAndCallback (node,
ordEnumerator.Add,
ordEnumerator.EndParticipation,
ordEnumerator.Stop,
options);
} else {
waitAction = ParallelExecuter.ProcessAndCallback (node,
buffer.Add,
buffer.CompleteAdding,
options);
}
if (options.Options.HasValue && options.Options.Value == ParallelMergeOptions.FullyBuffered)
waitAction ();
}
}
void Setup ()
{
if (!options.BehindOrderGuard.Value) {
if (options.Options.HasValue && (options.Options.Value == ParallelMergeOptions.NotBuffered
|| options.Options.Value == ParallelMergeOptions.FullyBuffered)) {
buffer = new BlockingCollection<T> ();
} else {
buffer = new BlockingCollection<T> (DefaultBufferSize);
}
IEnumerable<T> source = buffer.GetConsumingEnumerable (options.MergedToken);
loader = source.GetEnumerator ();
} else {
loader = ordEnumerator = new OrderingEnumerator<T> (options.PartitionCount, options.MergedToken);
}
}
public void Dispose ()
{
}
public void Reset ()
{
throw new NotSupportedException ();
}
public bool MoveNext ()
{
// If there are no stuff in the buffer
// but CompleteAdding hasn't been called,
// MoveNext blocks until further results are produced
if (!loader.MoveNext ())
return false;
current = loader.Current;
return true;
}
public T Current {
get {
return current;
}
}
object IEnumerator.Current {
get {
return current;
}
}
}
}
#endif

View File

@ -0,0 +1,285 @@
//
// ParallelQuickSort.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;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Generic;
namespace System.Linq.Parallel
{
// HACK: ATM: parallelization of the sort is disabled as task
// add more overhead than gain
internal class ParallelQuickSort<T>
{
readonly Comparison<T> comparison;
readonly IList<T> list;
readonly int[] indexes;
class SortedCollection : IList<T>
{
int[] indexes;
IList<T> source;
public SortedCollection (IList<T> source, int[] indexes)
{
this.indexes = indexes;
this.source = source;
}
public int IndexOf (T item)
{
throw new NotImplementedException();
}
public void Insert (int index, T item)
{
throw new NotImplementedException();
}
public void RemoveAt (int index)
{
throw new NotImplementedException();
}
public T this[int index] {
get {
return source[indexes[index]];
}
set {
throw new NotImplementedException();
}
}
public void Add (T item)
{
throw new NotImplementedException();
}
public void Clear ()
{
throw new NotImplementedException();
}
public bool Contains (T item)
{
throw new NotImplementedException();
}
public void CopyTo (T[] array, int arrayIndex)
{
throw new NotImplementedException();
}
public bool Remove (T item)
{
throw new NotImplementedException();
}
public int Count {
get {
return source.Count;
}
}
public bool IsReadOnly {
get {
return true;
}
}
IEnumerator<T> IEnumerable<T>.GetEnumerator ()
{
return null;
}
IEnumerator IEnumerable.GetEnumerator ()
{
return null;
}
}
private ParallelQuickSort (IList<T> list, Comparison<T> comparison)
{
this.comparison = comparison;
this.list = list;
this.indexes = CreateIndexes (list.Count);
}
static int[] CreateIndexes (int length)
{
var indexes = new int[length];
for (int i = 0; i < length; i++)
indexes [i] = i;
return indexes;
}
SortedCollection DoSort ()
{
if (list.Count > 1) {
if (list.Count < 5)
InsertionSort (0, list.Count - 1);
else
Sort (0, list.Count - 1);
}
return new SortedCollection (list, indexes);
}
int Comparison (int index1, int index2)
{
return comparison (list[index1], list[index2]);
}
void Sort (int left, int right)
{
if (left + 3 <= right) {
int l = left, r = right - 1, pivot = MedianOfThree (left, right);
while (true) {
while (Comparison (indexes [++l], pivot) < 0) { }
while (Comparison (indexes [--r], pivot) > 0) { }
if (l < r)
Swap (l, r);
else
break;
}
// Restore pivot
Swap (l, right - 1);
// Partition and sort
Sort (left, l - 1);
Sort (l + 1, right);
} else
// If there are three items in the subarray, insertion sort is better
InsertionSort (left, right);
}
/*void Sort (int left, int right, int depth)
{
int l = left, r = right - 1, pivot = MedianOfThree (left, right);
while (true) {
while (Comparison (indexes[++l], pivot) < 0);
while (Comparison (indexes[--r], pivot) > 0);
if (l < r)
Swap (l, r);
else
break;
}
// Restore pivot
Swap (l, right - 1);
// Partition and sort in parallel if appropriate
/*if (depth < maxDepth) {
depth <<= 1;
Task t = Task.Factory.StartNew (() => Sort (left, l - 1, depth));
Sort (l + 1, right, depth);
t.Wait ();
} else {*/
// Sequential
/* Sort (left, l - 1);
Sort (l + 1, right);
//}
}*/
/*void ShellSort (int left, int right)
{
int[] gaps = new int[] { 4, 1};
for (int ic = 0; ic < gaps.Length; ic++) {
int inc = gaps[ic];
int l = left + inc;
for (int i = l; i <= right; i++) {
T temp = list[i];
int j = i;
for (; j >= l && comparison (list[j - inc], temp) > 1; j -= inc)
list[j] = list[j - inc];
list[j] = temp;
}
}
}*/
void InsertionSort (int left, int right)
{
for (int i = left + 1; i <= right; i++) {
int j, tmp = indexes [i];
for (j = i; j > left && Comparison (tmp, indexes [j - 1]) < 0; j--)
indexes [j] = indexes [j - 1];
indexes [j] = tmp;
}
}
/*
void InsertionSort (int left, int right)
{
for (int i = left + 1; i <= right; i++) {
int j;
T tmp = list[i];
for (j = i; j > left && comparison (tmp, list [j - 1]) < 0; j--)
list [j] = list [j - 1];
list [j] = tmp;
}
}*/
void Swap (int left, int right)
{
int temp = indexes [right];
indexes [right] = indexes [left];
indexes [left] = temp;
}
int MedianOfThree (int left, int right)
{
int center = (left + right) >> 1;
if (Comparison (indexes[center], indexes[left]) < 0)
Swap (left, center);
if (Comparison (indexes[right], indexes[left]) < 0)
Swap (left, right);
if (Comparison (indexes[right], indexes[center]) < 0)
Swap (center, right);
Swap (center, right - 1);
return indexes[right - 1];
}
public static IList<T> Sort (IList<T> list, Comparison<T> comparison)
{
ParallelQuickSort<T> qs = new ParallelQuickSort<T> (list, comparison);
return qs.DoSort ();
}
}
}
#endif

View File

@ -0,0 +1,188 @@
//
// QueryCheckerVisitor.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.Linq.Parallel.QueryNodes;
namespace System.Linq.Parallel
{
using OptionsList = Tuple<ParallelMergeOptions?, ParallelExecutionMode?, CancellationToken?, int, CancellationTokenSource>;
internal class QueryCheckerVisitor : INodeVisitor
{
const int minSequentialThreshold = 20;
// Information gathering
ParallelMergeOptions? options = null;
ParallelExecutionMode? mode = null;
CancellationToken? token = null;
int? degreeOfParallelism = null;
CancellationToken implementerToken = CancellationToken.None;
int partitionCount;
bool? behindOrderGuard = null;
internal QueryCheckerVisitor (int partitionCount)
{
this.partitionCount = partitionCount;
}
#region INodeVisitor implementation
public void Visit (QueryBaseNode node)
{
// Nothing to do atm. Later we can check if the node is a
// Take or a Skip and set accordingly UseStrip
}
public void Visit (QueryChildNode node)
{
node.Parent.Visit (this);
}
public void Visit (QueryOptionNode node)
{
MergeOptions (node.GetOptions ());
Visit ((QueryChildNode)node);
}
public void Visit (QueryStartNode node)
{
if (behindOrderGuard == null)
behindOrderGuard = false;
if (degreeOfParallelism != null)
partitionCount = degreeOfParallelism.Value;
int count;
if ((count = node.Count) != -1 && count < minSequentialThreshold)
ShouldBeSequential = true;
}
public void Visit (QueryStreamNode node)
{
if (node.IsIndexed)
UseStrip = true;
Visit ((QueryChildNode)node);
}
public void Visit (QueryOrderGuardNode node)
{
if (behindOrderGuard == null) {
if (node.EnsureOrder) {
behindOrderGuard = true;
//UseStrip = true;
} else {
behindOrderGuard = false;
}
}
Visit ((QueryStreamNode)node);
}
public void Visit (QueryMuxNode node)
{
Visit ((QueryChildNode)node);
}
public void Visit (QueryHeadWorkerNode node)
{
// Wouldn't it be better with standard Linq?
if (node.Count.HasValue && node.Count < partitionCount)
ShouldBeSequential = true;
Visit ((QueryStreamNode)node);
}
#endregion
internal QueryOptions Options {
get {
return new QueryOptions (options, mode, token == null ? CancellationToken.None : token.Value,
UseStrip, behindOrderGuard, partitionCount, implementerToken, ShouldBeSequential);
}
}
internal bool UseStrip {
get;
private set;
}
internal bool BehindOrderGuard {
get {
return behindOrderGuard.Value;
}
}
internal bool ShouldBeSequential {
get;
private set;
}
void MergeOptions (OptionsList list)
{
if (list.Item1 != null) {
if (options == null)
options = list.Item1;
else
Throw ("WithMergeOptions");
}
if (list.Item2 != null) {
if (mode == null)
mode = list.Item2;
else
Throw ("WithExecutionMode");
}
if (list.Item3 != null) {
if (token == null)
token = list.Item3;
else
Throw ("WithCancellationToken");
}
if (list.Item4 != -1) {
if (degreeOfParallelism == null)
degreeOfParallelism = list.Item4;
else
Throw ("WithDegreeOfParallelism");
}
// That one is treated specially
if (list.Item5 != null) {
implementerToken = implementerToken.Chain (list.Item5);
}
}
void Throw (string methName)
{
throw new InvalidOperationException ("You can't have more than one " + methName + " node in a query");
}
}
}
#endif

View File

@ -0,0 +1,83 @@
//
// QueryIsOrderedVisitor.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.Linq.Parallel.QueryNodes;
namespace System.Linq.Parallel
{
internal class QueryIsOrderedVisitor : INodeVisitor
{
internal bool BehindOrderGuard {
get;
private set;
}
#region INodeVisitor implementation
public void Visit (QueryBaseNode node)
{
}
public void Visit (QueryChildNode node)
{
node.Parent.Visit (this);
}
public void Visit (QueryOptionNode node)
{
Visit ((QueryChildNode)node);
}
public void Visit (QueryStartNode node)
{
}
public void Visit (QueryStreamNode node)
{
Visit ((QueryChildNode)node);
}
public void Visit (QueryOrderGuardNode node)
{
BehindOrderGuard = node.EnsureOrder;
}
public void Visit (QueryMuxNode node)
{
Visit ((QueryChildNode)node);
}
public void Visit (QueryHeadWorkerNode node)
{
Visit ((QueryStreamNode)node);
}
#endregion
}
}
#endif

View File

@ -0,0 +1,129 @@
//
// QueryOptions.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;
namespace System.Linq.Parallel
{
internal class QueryOptions
{
public ParallelMergeOptions? Options {
get;
private set;
}
public ParallelExecutionMode? Mode {
get;
private set;
}
public CancellationToken Token {
get;
private set;
}
/* This token is to be used by some operator (like Take) to tell that
* the execution of the query can be prematurly stopped
*
* It is set when passing QueryOptions to the different node's Get method
* and ParallelExecuter should check after the call to this method is this guy has been
* set. Operator may chain up multiple cancellation token that way.
* When checking for this token, the task body should simply return.
*/
public CancellationToken ImplementerToken {
get;
private set;
}
public bool UseStrip {
get;
private set;
}
public bool? BehindOrderGuard {
get;
private set;
}
public int PartitionCount {
get;
private set;
}
public Tuple<bool, bool, bool> PartitionerSettings {
get;
internal set;
}
public CancellationToken MergedToken {
get;
private set;
}
public bool ShouldBeSequential {
get;
private set;
}
public QueryOptions (ParallelMergeOptions? options,
ParallelExecutionMode? mode,
CancellationToken token,
bool useStrip,
bool? behindOrderGuard,
int partitionCount,
CancellationToken implementerToken,
bool shouldBeSequential)
{
Options = options;
Mode = mode;
Token = token;
UseStrip = useStrip;
BehindOrderGuard = behindOrderGuard;
PartitionCount = partitionCount;
PartitionerSettings = null;
ImplementerToken = implementerToken;
ShouldBeSequential = shouldBeSequential;
MergeTokens (token, implementerToken);
}
void MergeTokens (CancellationToken token, CancellationToken implementerToken)
{
bool implementedNone = implementerToken == CancellationToken.None;
bool tokenNone = token == CancellationToken.None;
if (!implementedNone && !tokenNone)
MergedToken = CancellationTokenSource.CreateLinkedTokenSource (implementerToken, token).Token;
else if (implementedNone && !tokenNone)
MergedToken = token;
else if (!implementedNone && tokenNone)
MergedToken = implementerToken;
else
MergedToken = CancellationToken.None;
}
}
}
#endif

View File

@ -0,0 +1,125 @@
//
// RangeList.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;
namespace System.Linq.Parallel
{
internal class RangeList : IList<int>
{
readonly int start;
readonly int count;
public RangeList (int start, int count)
{
this.start = start;
this.count = count;
}
public int IndexOf (int item)
{
if (!Contains(item))
return -1;
return item - start;
}
public void Insert (int index, int item)
{
throw new NotImplementedException();
}
public void RemoveAt (int index)
{
throw new NotImplementedException();
}
public int this[int index] {
get {
if (index <= count)
return start + index;
return -1;
}
set {
throw new NotImplementedException();
}
}
public void Add (int item)
{
throw new NotImplementedException();
}
public void Clear ()
{
throw new NotImplementedException();
}
public bool Contains (int item)
{
return start <= item && item <= start + count - 1;
}
public void CopyTo (int[] array, int arrayIndex)
{
int counter = start;
for (int i = arrayIndex; i < array.Length && i < (i - arrayIndex) + count; i++)
array[i] = counter++;
}
public bool Remove (int item)
{
throw new NotImplementedException();
}
public int Count {
get {
return count;
}
}
public bool IsReadOnly {
get {
return true;
}
}
IEnumerator<int> IEnumerable<int>.GetEnumerator ()
{
return null;
}
IEnumerator IEnumerable.GetEnumerator ()
{
return null;
}
}
}
#endif

View File

@ -0,0 +1,119 @@
//
// RepeatList.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;
namespace System.Linq.Parallel
{
internal class RepeatList<T> : IList<T>
{
readonly int count;
readonly T element;
public RepeatList (T element, int count)
{
this.element = element;
this.count = count;
}
public int IndexOf (T item)
{
// No real index, we may just be interested if the value is different from -1
return Contains(item) ? 1 : -1;
}
public void Insert (int index, T item)
{
throw new NotImplementedException();
}
public void RemoveAt (int index)
{
throw new NotImplementedException();
}
public T this[int index] {
get {
return index < count ? element : default(T);
}
set {
throw new NotImplementedException();
}
}
public void Add (T item)
{
throw new NotImplementedException();
}
public void Clear ()
{
throw new NotImplementedException();
}
public bool Contains (T item)
{
return item.Equals(element);
}
public void CopyTo (T[] array, int arrayIndex)
{
for (int i = arrayIndex; i < array.Length && i < (i - arrayIndex) + count; i++)
array[i] = element;
}
public bool Remove (T item)
{
throw new NotImplementedException();
}
public int Count {
get {
return count;
}
}
public bool IsReadOnly {
get {
return true;
}
}
IEnumerator<T> IEnumerable<T>.GetEnumerator ()
{
return null;
}
IEnumerator IEnumerable.GetEnumerator ()
{
return null;
}
}
}
#endif

View File

@ -0,0 +1,119 @@
//
// 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.Linq;
using System.Threading;
using System.Collections;
using System.Collections.Generic;
namespace System.Linq.Parallel
{
internal class ReverseList<T> : IList<T>
{
readonly IList<T> backend;
readonly int count;
internal ReverseList (IList<T> backend)
{
this.backend = backend;
this.count = backend.Count;
}
public int IndexOf (T item)
{
throw new NotImplementedException();
}
public void Insert (int index, T item)
{
throw new NotImplementedException();
}
public void RemoveAt (int index)
{
throw new NotImplementedException();
}
public T this[int index] {
get {
return backend[count - 1 - index];
}
set {
throw new NotImplementedException();
}
}
public void Add (T item)
{
throw new NotImplementedException();
}
public void Clear ()
{
throw new NotImplementedException();
}
public bool Contains (T item)
{
throw new NotImplementedException();
}
public void CopyTo (T[] array, int arrayIndex)
{
throw new NotImplementedException();
}
public bool Remove (T item)
{
throw new NotImplementedException();
}
public int Count {
get {
return count;
}
}
public bool IsReadOnly {
get {
return true;
}
}
IEnumerator<T> IEnumerable<T>.GetEnumerator ()
{
return null;
}
IEnumerator IEnumerable.GetEnumerator ()
{
return null;
}
}
}
#endif

View File

@ -0,0 +1,62 @@
//
// StripPartitioner.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;
using System.Collections.Concurrent;
namespace System.Linq.Parallel
{
internal class StripPartitioner<T> : OrderablePartitioner<T>
{
IList<T> source;
public StripPartitioner (IList<T> source) : base (true, false, true)
{
this.source = source;
}
public override IList<IEnumerator<KeyValuePair<long, T>>> GetOrderablePartitions (int partitionCount)
{
IEnumerator<KeyValuePair<long, T>>[] array = new IEnumerator<KeyValuePair<long, T>>[partitionCount];
for (int i = 0; i < array.Length; i++)
array[i] = GetStripEnumerator (i, partitionCount);
return array;
}
IEnumerator<KeyValuePair<long, T>> GetStripEnumerator (int start, int partitionCount)
{
for (int i = start; i < source.Count; i += partitionCount) {
//Console.WriteLine ("Num {0} yielding [{1} : {2}]", start, i, source[i]);
yield return new KeyValuePair<long, T> (i, source [i]);
}
}
}
}
#endif

View File

@ -0,0 +1,71 @@
//
// TemporaryArea.cs
//
// Author:
// Jérémie "Garuma" Laval <jeremie.laval@gmail.com>
//
// Copyright (c) 2012 Xamarin, Inc.
//
// 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
{
internal class TemporaryArea<TKey, TValue>
{
Dictionary<TKey, TValue> dict;
public TemporaryArea () : this (EqualityComparer<TKey>.Default)
{
}
public TemporaryArea (IEqualityComparer<TKey> comparer)
{
this.dict = new Dictionary<TKey, TValue> (comparer);
}
public bool TryAdd (TKey index, TValue value)
{
lock (dict) {
if (dict.ContainsKey (index))
return false;
dict.Add (index, value);
return true;
}
}
public bool TryRemove (TKey index, out TValue value)
{
lock (dict) {
if (!dict.TryGetValue (index, out value))
return false;
return dict.Remove (index);
}
}
}
}
#endif