소스 검색

Implement Partitioner.Create int and long overloads. Add corresponding unit tests.

Jérémie Laval 15 년 전
부모
커밋
90e64cabf9

+ 32 - 17
mcs/class/corlib/System.Collections.Concurrent/Partitioner.cs

@@ -52,34 +52,49 @@ namespace System.Collections.Concurrent
 			return new ListPartitioner<TSource> (source);
 		}
 		
-		[MonoTODO("What range size is supposed to be in context and what the result returned looks like")]
 		public static OrderablePartitioner<Tuple<int, int>> Create (int fromInclusive,
-		                                                             int toExclusive)
+		                                                            int toExclusive)
 		{
-			return Create (fromInclusive, toExclusive, 1);
+			// This formula that is somewhat non-straighforward was guessed based on MS output
+			int rangeSize = (toExclusive - fromInclusive) / (Environment.ProcessorCount * 3);
+			if (rangeSize < 1)
+				rangeSize = 1;
+
+			return Create (fromInclusive, toExclusive, rangeSize);
 		}
-		
-		[MonoTODO("What range size is supposed to be in context and what the result returned looks like")]
+
 		public static OrderablePartitioner<Tuple<int, int>> Create (int fromInclusive,
-		                                                             int toExclusive,
-		                                                             int rangeSize)
+		                                                            int toExclusive,
+		                                                            int rangeSize)
 		{
-			throw new NotImplementedException ();
+			if (fromInclusive >= toExclusive)
+				throw new ArgumentOutOfRangeException ("toExclusive");
+			if (rangeSize <= 0)
+				throw new ArgumentOutOfRangeException ("rangeSize");
+
+			return new UserRangePartitioner (fromInclusive, toExclusive, rangeSize);
 		}
-		
-		[MonoTODO("What range size is supposed to be in context and what the result returned looks like")]
+
 		public static OrderablePartitioner<Tuple<long, long>> Create (long fromInclusive,
-		                                                               long toExclusive)
+		                                                              long toExclusive)
 		{
-			return Create (fromInclusive, toExclusive, 1);
+			long rangeSize = (toExclusive - fromInclusive) / (Environment.ProcessorCount * 3);
+			if (rangeSize < 1)
+				rangeSize = 1;
+
+			return Create (fromInclusive, toExclusive, rangeSize);
 		}
-		
-		[MonoTODO("What range size is supposed to be in context and what the result returned looks like")]
+
 		public static OrderablePartitioner<Tuple<long, long>> Create (long fromInclusive,
-		                                                               long toExclusive,
-		                                                               long rangeSize)
+		                                                              long toExclusive,
+		                                                              long rangeSize)
 		{
-			throw new NotImplementedException ();
+			if (rangeSize <= 0)
+				throw new ArgumentOutOfRangeException ("rangeSize");
+			if (fromInclusive >= toExclusive)
+				throw new ArgumentOutOfRangeException ("toExclusive");
+
+			return new UserLongRangePartitioner (fromInclusive, toExclusive, rangeSize);
 		}
 	}
 	

+ 123 - 0
mcs/class/corlib/System.Collections.Concurrent/Partitioners/UserRangePartitioner.cs

@@ -0,0 +1,123 @@
+// 
+// UserRangePartitioner.cs
+//  
+// Author:
+//       Jérémie "Garuma" Laval <[email protected]>
+// 
+// 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.
+
+using System;
+using System.Collections.Generic;
+
+#if NET_4_0
+
+namespace System.Collections.Concurrent
+{
+	internal class UserRangePartitioner : OrderablePartitioner<Tuple<int,  int>>
+	{
+		readonly int start;
+		readonly int end;
+		readonly int rangeSize;
+
+		public UserRangePartitioner (int start, int end, int rangeSize) : base (true, true, true)
+		{
+			this.start = start;
+			this.end = end;
+			this.rangeSize = rangeSize;
+		}
+		
+		public override IList<IEnumerator<KeyValuePair<long, Tuple<int, int>>>> GetOrderablePartitions (int partitionCount)
+		{
+			if (partitionCount <= 0)
+				throw new ArgumentOutOfRangeException ("partitionCount");
+			
+			var enumerators = new IEnumerator<KeyValuePair<long, Tuple<int, int>>>[partitionCount];
+			for (int i = 1; i < partitionCount; i++)
+				enumerators[i] = GetEmpty ();
+			
+			enumerators[0] = GetEnumerator ();
+
+			return enumerators;
+		}
+		
+		IEnumerator<KeyValuePair<long, Tuple<int, int>>> GetEnumerator ()
+		{
+			int sliceStart = start;
+			long index = -1;
+			
+			while (sliceStart <= end) {
+				yield return new KeyValuePair<long, Tuple<int, int>> (++index, Tuple.Create (sliceStart, Math.Min (end, sliceStart + rangeSize)));
+				sliceStart += rangeSize;
+			}
+		}
+
+		IEnumerator<KeyValuePair<long, Tuple<int, int>>> GetEmpty ()
+		{
+			yield break;
+		}		
+	}
+
+	internal class UserLongRangePartitioner : OrderablePartitioner<Tuple<long,  long>>
+	{
+		readonly long start;
+		readonly long end;
+		readonly long rangeSize;
+
+		public UserLongRangePartitioner (long start, long end, long rangeSize) : base (true, true, true)
+		{
+			this.start = start;
+			this.end = end;
+			this.rangeSize = rangeSize;
+		}
+		
+		public override IList<IEnumerator<KeyValuePair<long, Tuple<long, long>>>> GetOrderablePartitions (int partitionCount)
+		{
+			if (partitionCount <= 0)
+				throw new ArgumentOutOfRangeException ("partitionCount");
+			
+			var enumerators = new IEnumerator<KeyValuePair<long, Tuple<long, long>>>[partitionCount];
+			for (int i = 1; i < partitionCount; i++)
+				enumerators[i] = GetEmpty ();
+			
+			enumerators[0] = GetEnumerator ();
+
+			return enumerators;
+		}
+		
+		IEnumerator<KeyValuePair<long, Tuple<long, long>>> GetEnumerator ()
+		{
+			long sliceStart = start;
+			long index = -1;
+			
+			while (sliceStart <= end) {
+				yield return new KeyValuePair<long, Tuple<long, long>> (++index, Tuple.Create (sliceStart, Math.Min (end, sliceStart + rangeSize)));
+				sliceStart += rangeSize;
+			}
+		}
+
+		IEnumerator<KeyValuePair<long, Tuple<long, long>>> GetEmpty ()
+		{
+			yield break;
+		}		
+	}
+
+}
+#endif

+ 0 - 1
mcs/class/corlib/System.Threading.Tasks/Task.cs

@@ -603,7 +603,6 @@ namespace System.Threading.Tasks
 			if (millisecondsTimeout == -1)
 				return WaitAny (tasks);
 
-			Watch sw = Watch.StartNew ();
 			return WaitAny (tasks, millisecondsTimeout, CancellationToken.None);
 		}
 

+ 93 - 0
mcs/class/corlib/Test/System.Collections.Concurrent/PartitionerTests.cs

@@ -0,0 +1,93 @@
+// 
+// PartitionerTests.cs
+//  
+// Author:
+//       Jérémie "Garuma" Laval <[email protected]>
+// 
+// Copyright (c) 2009 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 NUnit.Framework;
+
+namespace MonoTests.System.Collections.Concurrent
+{
+	[TestFixture]
+	public class PartitionerTests
+	{
+		[Test]
+		public void PartitionerCreateIntegerWithExplicitRange ()
+		{
+			OrderablePartitioner<Tuple<int, int>> partitioner = Partitioner.Create (1, 20, 5);
+			var partitions = partitioner.GetOrderablePartitions (3);
+			Assert.AreEqual (3, partitions.Count);
+			CollectionAssert.AllItemsAreNotNull (partitions);
+			var iterator = partitions[0];			
+			Assert.IsTrue (iterator.MoveNext ());
+			Assert.IsTrue (iterator.Current.Equals (Create (0, 1, 6)));
+			Assert.IsTrue (iterator.MoveNext ());
+			Assert.IsTrue (iterator.Current.Equals (Create (1, 6, 11)));
+			Assert.IsTrue (iterator.MoveNext ());
+			Assert.IsTrue (iterator.Current.Equals (Create (2, 11, 16)));
+			Assert.IsTrue (iterator.MoveNext ());
+			Assert.IsTrue (iterator.Current.Equals (Create (3, 16, 20)));
+			
+			Assert.IsFalse (partitions[1].MoveNext ());
+			Assert.IsFalse (partitions[2].MoveNext ());
+		}
+
+		[Test]
+		public void PartitionerCreateLongWithExplicitRange ()
+		{
+			OrderablePartitioner<Tuple<long, long>> partitioner = Partitioner.Create ((long)1, (long)20, (long)5);
+			var partitions = partitioner.GetOrderablePartitions (3);
+			Assert.AreEqual (3, partitions.Count);
+			CollectionAssert.AllItemsAreNotNull (partitions);
+			var iterator = partitions[0];			
+			Assert.IsTrue (iterator.MoveNext ());
+			Assert.IsTrue (iterator.Current.Equals (CreateL (0, 1, 6)));
+			Assert.IsTrue (iterator.MoveNext ());
+			Assert.IsTrue (iterator.Current.Equals (CreateL (1, 6, 11)));
+			Assert.IsTrue (iterator.MoveNext ());
+			Assert.IsTrue (iterator.Current.Equals (CreateL (2, 11, 16)));
+			Assert.IsTrue (iterator.MoveNext ());
+			Assert.IsTrue (iterator.Current.Equals (CreateL (3, 16, 20)));
+			
+			Assert.IsFalse (partitions[1].MoveNext ());
+			Assert.IsFalse (partitions[2].MoveNext ());
+		}
+
+		static KeyValuePair<long, Tuple<int, int>> Create (long ind, int i1, int i2)
+		{
+			return new KeyValuePair<long, Tuple<int, int>> (ind, Tuple.Create (i1, i2));
+		}
+
+		static KeyValuePair<long, Tuple<long, long>> CreateL (long ind, long i1, long i2)
+		{
+			return new KeyValuePair<long, Tuple<long, long>> (ind, Tuple.Create (i1, i2));
+		}
+	}
+}
+#endif

+ 1 - 0
mcs/class/corlib/corlib.dll.sources

@@ -1544,6 +1544,7 @@ System.Collections.Concurrent/ConcurrentQueue.cs
 System.Collections.Concurrent/ConcurrentSkipList.cs
 System.Collections.Concurrent/Partitioners/ListPartitioner.cs
 System.Collections.Concurrent/Partitioners/EnumerablePartitioner.cs
+System.Collections.Concurrent/Partitioners/UserRangePartitioner.cs
 System.Collections.Concurrent/IProducerConsumerCollection.cs
 System.Collections.Concurrent/ConcurrentStack.cs
 System.Collections.Concurrent/SplitOrderedList.cs

+ 1 - 0
mcs/class/corlib/corlib_test.dll.sources

@@ -439,6 +439,7 @@ System.Threading.Tasks/ParallelTestHelper.cs
 System.Threading.Tasks/ParallelTests.cs
 System.Collections.Concurrent/ParallelConcurrentStackTests.cs
 System.Collections.Concurrent/ConcurrentSkipListTests.cs
+System.Collections.Concurrent/PartitionerTests.cs
 ../System.Collections.Concurrent/ConcurrentSkipList.cs
 System.Collections.Concurrent/ConcurrentQueueTests.cs
 System.Collections.Concurrent/ConcurrentBagTests.cs