UserRangePartitioner.cs
Go to the documentation of this file.
1 //
2 // UserRangePartitioner.cs
3 //
4 // Author:
5 // Jérémie "Garuma" Laval <jeremie.laval@gmail.com>
6 //
7 // Copyright (c) 2010 Jérémie "Garuma" Laval
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining a copy
10 // of this software and associated documentation files (the "Software"), to deal
11 // in the Software without restriction, including without limitation the rights
12 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 // copies of the Software, and to permit persons to whom the Software is
14 // furnished to do so, subject to the following conditions:
15 //
16 // The above copyright notice and this permission notice shall be included in
17 // all copies or substantial portions of the Software.
18 //
19 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 // THE SOFTWARE.
26 
27 #if NET_4_0
28 
29 using System;
30 using System.Threading;
32 
33 namespace System.Collections.Concurrent.Partitioners
34 {
35  internal class UserRangePartitioner : OrderablePartitioner<Tuple<int, int>>
36  {
37  readonly int start;
38  readonly int end;
39  readonly int rangeSize;
40 
41  public UserRangePartitioner (int start, int end, int rangeSize) : base (true, true, true)
42  {
43  this.start = start;
44  this.end = end;
45  this.rangeSize = rangeSize;
46  }
47 
48  public override IList<IEnumerator<KeyValuePair<long, Tuple<int, int>>>> GetOrderablePartitions (int partitionCount)
49  {
50  if (partitionCount <= 0)
51  throw new ArgumentOutOfRangeException ("partitionCount");
52 
53  int currentIndex = 0;
54  Func<int> getNextIndex = () => Interlocked.Increment (ref currentIndex) - 1;
55 
56  var enumerators = new IEnumerator<KeyValuePair<long, Tuple<int, int>>>[partitionCount];
57  for (int i = 0; i < partitionCount; i++)
58  enumerators[i] = GetEnumerator (getNextIndex);
59 
60  return enumerators;
61  }
62 
63  IEnumerator<KeyValuePair<long, Tuple<int, int>>> GetEnumerator (Func<int> getNextIndex)
64  {
65  while (true) {
66  int index = getNextIndex ();
67  int sliceStart = index * rangeSize + start;
68 
69  if (sliceStart >= end)
70  break;
71 
72  yield return new KeyValuePair<long, Tuple<int, int>> (index, Tuple.Create (sliceStart, Math.Min (end, sliceStart + rangeSize)));
73  sliceStart += rangeSize;
74  }
75  }
76  }
77 
78  internal class UserLongRangePartitioner : OrderablePartitioner<Tuple<long, long>>
79  {
80  readonly long start;
81  readonly long end;
82  readonly long rangeSize;
83 
84  public UserLongRangePartitioner (long start, long end, long rangeSize) : base (true, true, true)
85  {
86  this.start = start;
87  this.end = end;
88  this.rangeSize = rangeSize;
89  }
90 
91  public override IList<IEnumerator<KeyValuePair<long, Tuple<long, long>>>> GetOrderablePartitions (int partitionCount)
92  {
93  if (partitionCount <= 0)
94  throw new ArgumentOutOfRangeException ("partitionCount");
95 
96  long currentIndex = 0;
97  Func<long> getNextIndex = () => Interlocked.Increment (ref currentIndex) - 1;
98 
99  var enumerators = new IEnumerator<KeyValuePair<long, Tuple<long, long>>>[partitionCount];
100  for (int i = 0; i < partitionCount; i++)
101  enumerators[i] = GetEnumerator (getNextIndex);
102 
103  return enumerators;
104  }
105 
106  IEnumerator<KeyValuePair<long, Tuple<long, long>>> GetEnumerator (Func<long> getNextIndex)
107  {
108  while (true) {
109  long index = getNextIndex ();
110  long sliceStart = index * rangeSize + start;
111 
112  if (sliceStart >= end)
113  break;
114 
115  yield return new KeyValuePair<long, Tuple<long, long>> (index, Tuple.Create (sliceStart, Math.Min (end, sliceStart + rangeSize)));
116  sliceStart += rangeSize;
117  }
118  }
119  }
120 }
121 #endif