mscorlib(4.0.0.0) API with additions
Partitioner.cs
4 using System.Threading;
5 
7 {
10  [__DynamicallyInvokable]
11  [HostProtection(SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)]
12  public abstract class Partitioner<TSource>
13  {
16  [__DynamicallyInvokable]
17  public virtual bool SupportsDynamicPartitions
18  {
19  [__DynamicallyInvokable]
20  get
21  {
22  return false;
23  }
24  }
25 
29  [__DynamicallyInvokable]
30  public abstract IList<IEnumerator<TSource>> GetPartitions(int partitionCount);
31 
35  [__DynamicallyInvokable]
37  {
38  throw new NotSupportedException(Environment.GetResourceString("Partitioner_DynamicPartitionsNotSupported"));
39  }
40 
42  [__DynamicallyInvokable]
43  protected Partitioner()
44  {
45  }
46  }
48  [__DynamicallyInvokable]
49  [HostProtection(SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)]
50  public static class Partitioner
51  {
52  private abstract class DynamicPartitionEnumerator_Abstract<TSource, TSourceReader> : IEnumerator<KeyValuePair<long, TSource>>, IDisposable, IEnumerator
53  {
54  protected readonly TSourceReader m_sharedReader;
55 
56  protected static int s_defaultMaxChunkSize = GetDefaultChunkSize<TSource>();
57 
58  protected SharedInt m_currentChunkSize;
59 
60  protected SharedInt m_localOffset;
61 
62  private const int CHUNK_DOUBLING_RATE = 3;
63 
64  private int m_doublingCountdown;
65 
66  protected readonly int m_maxChunkSize;
67 
68  protected readonly SharedLong m_sharedIndex;
69 
70  protected abstract bool HasNoElementsLeft
71  {
72  get;
73  set;
74  }
75 
76  public abstract KeyValuePair<long, TSource> Current
77  {
78  get;
79  }
80 
81  object IEnumerator.Current
82  {
83  get
84  {
85  return Current;
86  }
87  }
88 
89  protected DynamicPartitionEnumerator_Abstract(TSourceReader sharedReader, SharedLong sharedIndex)
90  : this(sharedReader, sharedIndex, useSingleChunking: false)
91  {
92  }
93 
94  protected DynamicPartitionEnumerator_Abstract(TSourceReader sharedReader, SharedLong sharedIndex, bool useSingleChunking)
95  {
96  m_sharedReader = sharedReader;
97  m_sharedIndex = sharedIndex;
98  m_maxChunkSize = (useSingleChunking ? 1 : s_defaultMaxChunkSize);
99  }
100 
101  protected abstract bool GrabNextChunk(int requestedChunkSize);
102 
103  public abstract void Dispose();
104 
105  public void Reset()
106  {
107  throw new NotSupportedException();
108  }
109 
110  public bool MoveNext()
111  {
112  if (m_localOffset == null)
113  {
114  m_localOffset = new SharedInt(-1);
115  m_currentChunkSize = new SharedInt(0);
116  m_doublingCountdown = 3;
117  }
118  if (m_localOffset.Value < m_currentChunkSize.Value - 1)
119  {
120  m_localOffset.Value++;
121  return true;
122  }
123  int requestedChunkSize;
124  if (m_currentChunkSize.Value == 0)
125  {
126  requestedChunkSize = 1;
127  }
128  else if (m_doublingCountdown > 0)
129  {
130  requestedChunkSize = m_currentChunkSize.Value;
131  }
132  else
133  {
134  requestedChunkSize = Math.Min(m_currentChunkSize.Value * 2, m_maxChunkSize);
135  m_doublingCountdown = 3;
136  }
137  m_doublingCountdown--;
138  if (GrabNextChunk(requestedChunkSize))
139  {
140  m_localOffset.Value = 0;
141  return true;
142  }
143  return false;
144  }
145  }
146 
147  private class DynamicPartitionerForIEnumerable<TSource> : OrderablePartitioner<TSource>
148  {
149  private class InternalPartitionEnumerable : IEnumerable<KeyValuePair<long, TSource>>, IEnumerable, IDisposable
150  {
151  private readonly IEnumerator<TSource> m_sharedReader;
152 
153  private SharedLong m_sharedIndex;
154 
155  private volatile KeyValuePair<long, TSource>[] m_FillBuffer;
156 
157  private volatile int m_FillBufferSize;
158 
159  private volatile int m_FillBufferCurrentPosition;
160 
161  private volatile int m_activeCopiers;
162 
163  private SharedBool m_hasNoElementsLeft;
164 
165  private SharedBool m_sourceDepleted;
166 
167  private object m_sharedLock;
168 
169  private bool m_disposed;
170 
171  private SharedInt m_activePartitionCount;
172 
173  private readonly bool m_useSingleChunking;
174 
175  internal InternalPartitionEnumerable(IEnumerator<TSource> sharedReader, bool useSingleChunking, bool isStaticPartitioning)
176  {
177  m_sharedReader = sharedReader;
178  m_sharedIndex = new SharedLong(-1L);
179  m_hasNoElementsLeft = new SharedBool(value: false);
180  m_sourceDepleted = new SharedBool(value: false);
181  m_sharedLock = new object();
182  m_useSingleChunking = useSingleChunking;
183  if (!m_useSingleChunking)
184  {
185  int num = (PlatformHelper.ProcessorCount <= 4) ? 1 : 4;
186  m_FillBuffer = new KeyValuePair<long, TSource>[num * GetDefaultChunkSize<TSource>()];
187  }
188  if (isStaticPartitioning)
189  {
190  m_activePartitionCount = new SharedInt(0);
191  }
192  else
193  {
194  m_activePartitionCount = null;
195  }
196  }
197 
198  public IEnumerator<KeyValuePair<long, TSource>> GetEnumerator()
199  {
200  if (m_disposed)
201  {
202  throw new ObjectDisposedException(Environment.GetResourceString("PartitionerStatic_CanNotCallGetEnumeratorAfterSourceHasBeenDisposed"));
203  }
204  return new InternalPartitionEnumerator(m_sharedReader, m_sharedIndex, m_hasNoElementsLeft, m_sharedLock, m_activePartitionCount, this, m_useSingleChunking);
205  }
206 
208  {
209  return GetEnumerator();
210  }
211 
212  private void TryCopyFromFillBuffer(KeyValuePair<long, TSource>[] destArray, int requestedChunkSize, ref int actualNumElementsGrabbed)
213  {
214  actualNumElementsGrabbed = 0;
215  KeyValuePair<long, TSource>[] fillBuffer = m_FillBuffer;
216  if (fillBuffer != null && m_FillBufferCurrentPosition < m_FillBufferSize)
217  {
218  Interlocked.Increment(ref m_activeCopiers);
219  int num = Interlocked.Add(ref m_FillBufferCurrentPosition, requestedChunkSize);
220  int num2 = num - requestedChunkSize;
221  if (num2 < m_FillBufferSize)
222  {
223  actualNumElementsGrabbed = ((num < m_FillBufferSize) ? num : (m_FillBufferSize - num2));
224  Array.Copy(fillBuffer, num2, destArray, 0, actualNumElementsGrabbed);
225  }
226  Interlocked.Decrement(ref m_activeCopiers);
227  }
228  }
229 
230  internal bool GrabChunk(KeyValuePair<long, TSource>[] destArray, int requestedChunkSize, ref int actualNumElementsGrabbed)
231  {
232  actualNumElementsGrabbed = 0;
233  if (m_hasNoElementsLeft.Value)
234  {
235  return false;
236  }
237  if (m_useSingleChunking)
238  {
239  return GrabChunk_Single(destArray, requestedChunkSize, ref actualNumElementsGrabbed);
240  }
241  return GrabChunk_Buffered(destArray, requestedChunkSize, ref actualNumElementsGrabbed);
242  }
243 
244  internal bool GrabChunk_Single(KeyValuePair<long, TSource>[] destArray, int requestedChunkSize, ref int actualNumElementsGrabbed)
245  {
246  lock (m_sharedLock)
247  {
248  if (!m_hasNoElementsLeft.Value)
249  {
250  try
251  {
252  if (m_sharedReader.MoveNext())
253  {
254  m_sharedIndex.Value = checked(m_sharedIndex.Value + 1);
255  destArray[0] = new KeyValuePair<long, TSource>(m_sharedIndex.Value, m_sharedReader.Current);
256  actualNumElementsGrabbed = 1;
257  return true;
258  }
259  m_sourceDepleted.Value = true;
260  m_hasNoElementsLeft.Value = true;
261  return false;
262  }
263  catch
264  {
265  m_sourceDepleted.Value = true;
266  m_hasNoElementsLeft.Value = true;
267  throw;
268  }
269  }
270  return false;
271  }
272  }
273 
274  internal bool GrabChunk_Buffered(KeyValuePair<long, TSource>[] destArray, int requestedChunkSize, ref int actualNumElementsGrabbed)
275  {
276  TryCopyFromFillBuffer(destArray, requestedChunkSize, ref actualNumElementsGrabbed);
277  if (actualNumElementsGrabbed == requestedChunkSize)
278  {
279  return true;
280  }
281  if (m_sourceDepleted.Value)
282  {
283  m_hasNoElementsLeft.Value = true;
284  m_FillBuffer = null;
285  return actualNumElementsGrabbed > 0;
286  }
287  lock (m_sharedLock)
288  {
289  if (m_sourceDepleted.Value)
290  {
291  return actualNumElementsGrabbed > 0;
292  }
293  try
294  {
295  if (m_activeCopiers > 0)
296  {
297  SpinWait spinWait = default(SpinWait);
298  while (m_activeCopiers > 0)
299  {
300  spinWait.SpinOnce();
301  }
302  }
303  while (actualNumElementsGrabbed < requestedChunkSize)
304  {
305  if (!m_sharedReader.MoveNext())
306  {
307  m_sourceDepleted.Value = true;
308  break;
309  }
310  m_sharedIndex.Value = checked(m_sharedIndex.Value + 1);
311  destArray[actualNumElementsGrabbed] = new KeyValuePair<long, TSource>(m_sharedIndex.Value, m_sharedReader.Current);
312  actualNumElementsGrabbed++;
313  }
314  KeyValuePair<long, TSource>[] fillBuffer = m_FillBuffer;
315  if (!m_sourceDepleted.Value && fillBuffer != null && m_FillBufferCurrentPosition >= fillBuffer.Length)
316  {
317  for (int i = 0; i < fillBuffer.Length; i++)
318  {
319  if (!m_sharedReader.MoveNext())
320  {
321  m_sourceDepleted.Value = true;
322  m_FillBufferSize = i;
323  break;
324  }
325  m_sharedIndex.Value = checked(m_sharedIndex.Value + 1);
326  fillBuffer[i] = new KeyValuePair<long, TSource>(m_sharedIndex.Value, m_sharedReader.Current);
327  }
328  m_FillBufferCurrentPosition = 0;
329  }
330  }
331  catch
332  {
333  m_sourceDepleted.Value = true;
334  m_hasNoElementsLeft.Value = true;
335  throw;
336  }
337  }
338  return actualNumElementsGrabbed > 0;
339  }
340 
341  public void Dispose()
342  {
343  if (!m_disposed)
344  {
345  m_disposed = true;
346  m_sharedReader.Dispose();
347  }
348  }
349  }
350 
351  private class InternalPartitionEnumerator : DynamicPartitionEnumerator_Abstract<TSource, IEnumerator<TSource>>
352  {
353  private KeyValuePair<long, TSource>[] m_localList;
354 
355  private readonly SharedBool m_hasNoElementsLeft;
356 
357  private readonly object m_sharedLock;
358 
359  private readonly SharedInt m_activePartitionCount;
360 
361  private InternalPartitionEnumerable m_enumerable;
362 
363  protected override bool HasNoElementsLeft
364  {
365  get
366  {
367  return m_hasNoElementsLeft.Value;
368  }
369  set
370  {
371  m_hasNoElementsLeft.Value = true;
372  }
373  }
374 
375  public override KeyValuePair<long, TSource> Current
376  {
377  get
378  {
379  if (m_currentChunkSize == null)
380  {
381  throw new InvalidOperationException(Environment.GetResourceString("PartitionerStatic_CurrentCalledBeforeMoveNext"));
382  }
383  return m_localList[m_localOffset.Value];
384  }
385  }
386 
387  internal InternalPartitionEnumerator(IEnumerator<TSource> sharedReader, SharedLong sharedIndex, SharedBool hasNoElementsLeft, object sharedLock, SharedInt activePartitionCount, InternalPartitionEnumerable enumerable, bool useSingleChunking)
388  : base(sharedReader, sharedIndex, useSingleChunking)
389  {
390  m_hasNoElementsLeft = hasNoElementsLeft;
391  m_sharedLock = sharedLock;
392  m_enumerable = enumerable;
393  m_activePartitionCount = activePartitionCount;
394  if (m_activePartitionCount != null)
395  {
396  Interlocked.Increment(ref m_activePartitionCount.Value);
397  }
398  }
399 
400  protected override bool GrabNextChunk(int requestedChunkSize)
401  {
402  if (HasNoElementsLeft)
403  {
404  return false;
405  }
406  if (m_localList == null)
407  {
408  m_localList = new KeyValuePair<long, TSource>[m_maxChunkSize];
409  }
410  return m_enumerable.GrabChunk(m_localList, requestedChunkSize, ref m_currentChunkSize.Value);
411  }
412 
413  public override void Dispose()
414  {
415  if (m_activePartitionCount != null && Interlocked.Decrement(ref m_activePartitionCount.Value) == 0)
416  {
417  m_enumerable.Dispose();
418  }
419  }
420  }
421 
422  private IEnumerable<TSource> m_source;
423 
424  private readonly bool m_useSingleChunking;
425 
426  public override bool SupportsDynamicPartitions => true;
427 
428  internal DynamicPartitionerForIEnumerable(IEnumerable<TSource> source, EnumerablePartitionerOptions partitionerOptions)
429  : base(keysOrderedInEachPartition: true, keysOrderedAcrossPartitions: false, keysNormalized: true)
430  {
431  m_source = source;
432  m_useSingleChunking = ((partitionerOptions & EnumerablePartitionerOptions.NoBuffering) != EnumerablePartitionerOptions.None);
433  }
434 
435  public override IList<IEnumerator<KeyValuePair<long, TSource>>> GetOrderablePartitions(int partitionCount)
436  {
437  if (partitionCount <= 0)
438  {
439  throw new ArgumentOutOfRangeException("partitionCount");
440  }
442  IEnumerable<KeyValuePair<long, TSource>> enumerable = new InternalPartitionEnumerable(m_source.GetEnumerator(), m_useSingleChunking, isStaticPartitioning: true);
443  for (int i = 0; i < partitionCount; i++)
444  {
445  array[i] = enumerable.GetEnumerator();
446  }
447  return array;
448  }
449 
450  public override IEnumerable<KeyValuePair<long, TSource>> GetOrderableDynamicPartitions()
451  {
452  return new InternalPartitionEnumerable(m_source.GetEnumerator(), m_useSingleChunking, isStaticPartitioning: false);
453  }
454  }
455 
456  private abstract class DynamicPartitionerForIndexRange_Abstract<TSource, TCollection> : OrderablePartitioner<TSource>
457  {
458  private TCollection m_data;
459 
460  public override bool SupportsDynamicPartitions => true;
461 
462  protected DynamicPartitionerForIndexRange_Abstract(TCollection data)
463  : base(keysOrderedInEachPartition: true, keysOrderedAcrossPartitions: false, keysNormalized: true)
464  {
465  m_data = data;
466  }
467 
468  protected abstract IEnumerable<KeyValuePair<long, TSource>> GetOrderableDynamicPartitions_Factory(TCollection data);
469 
470  public override IList<IEnumerator<KeyValuePair<long, TSource>>> GetOrderablePartitions(int partitionCount)
471  {
472  if (partitionCount <= 0)
473  {
474  throw new ArgumentOutOfRangeException("partitionCount");
475  }
477  IEnumerable<KeyValuePair<long, TSource>> orderableDynamicPartitions_Factory = GetOrderableDynamicPartitions_Factory(m_data);
478  for (int i = 0; i < partitionCount; i++)
479  {
480  array[i] = orderableDynamicPartitions_Factory.GetEnumerator();
481  }
482  return array;
483  }
484 
485  public override IEnumerable<KeyValuePair<long, TSource>> GetOrderableDynamicPartitions()
486  {
487  return GetOrderableDynamicPartitions_Factory(m_data);
488  }
489  }
490 
491  private abstract class DynamicPartitionEnumeratorForIndexRange_Abstract<TSource, TSourceReader> : DynamicPartitionEnumerator_Abstract<TSource, TSourceReader>
492  {
493  protected int m_startIndex;
494 
495  protected abstract int SourceCount
496  {
497  get;
498  }
499 
500  protected override bool HasNoElementsLeft
501  {
502  get
503  {
504  return Volatile.Read(ref m_sharedIndex.Value) >= SourceCount - 1;
505  }
506  set
507  {
508  }
509  }
510 
511  protected DynamicPartitionEnumeratorForIndexRange_Abstract(TSourceReader sharedReader, SharedLong sharedIndex)
512  : base(sharedReader, sharedIndex)
513  {
514  }
515 
516  protected override bool GrabNextChunk(int requestedChunkSize)
517  {
518  while (!HasNoElementsLeft)
519  {
520  long num = Volatile.Read(ref m_sharedIndex.Value);
521  if (HasNoElementsLeft)
522  {
523  return false;
524  }
525  long num2 = Math.Min(SourceCount - 1, num + requestedChunkSize);
526  if (Interlocked.CompareExchange(ref m_sharedIndex.Value, num2, num) == num)
527  {
528  m_currentChunkSize.Value = (int)(num2 - num);
529  m_localOffset.Value = -1;
530  m_startIndex = (int)(num + 1);
531  return true;
532  }
533  }
534  return false;
535  }
536 
537  public override void Dispose()
538  {
539  }
540  }
541 
542  private class DynamicPartitionerForIList<TSource> : DynamicPartitionerForIndexRange_Abstract<TSource, IList<TSource>>
543  {
544  private class InternalPartitionEnumerable : IEnumerable<KeyValuePair<long, TSource>>, IEnumerable
545  {
546  private readonly IList<TSource> m_sharedReader;
547 
548  private SharedLong m_sharedIndex;
549 
550  internal InternalPartitionEnumerable(IList<TSource> sharedReader)
551  {
552  m_sharedReader = sharedReader;
553  m_sharedIndex = new SharedLong(-1L);
554  }
555 
556  public IEnumerator<KeyValuePair<long, TSource>> GetEnumerator()
557  {
558  return new InternalPartitionEnumerator(m_sharedReader, m_sharedIndex);
559  }
560 
562  {
563  return GetEnumerator();
564  }
565  }
566 
567  private class InternalPartitionEnumerator : DynamicPartitionEnumeratorForIndexRange_Abstract<TSource, IList<TSource>>
568  {
569  protected override int SourceCount => m_sharedReader.Count;
570 
571  public override KeyValuePair<long, TSource> Current
572  {
573  get
574  {
575  if (m_currentChunkSize == null)
576  {
577  throw new InvalidOperationException(Environment.GetResourceString("PartitionerStatic_CurrentCalledBeforeMoveNext"));
578  }
579  return new KeyValuePair<long, TSource>(m_startIndex + m_localOffset.Value, m_sharedReader[m_startIndex + m_localOffset.Value]);
580  }
581  }
582 
583  internal InternalPartitionEnumerator(IList<TSource> sharedReader, SharedLong sharedIndex)
584  : base(sharedReader, sharedIndex)
585  {
586  }
587  }
588 
589  internal DynamicPartitionerForIList(IList<TSource> source)
590  : base(source)
591  {
592  }
593 
594  protected override IEnumerable<KeyValuePair<long, TSource>> GetOrderableDynamicPartitions_Factory(IList<TSource> m_data)
595  {
596  return new InternalPartitionEnumerable(m_data);
597  }
598  }
599 
600  private class DynamicPartitionerForArray<TSource> : DynamicPartitionerForIndexRange_Abstract<TSource, TSource[]>
601  {
602  private class InternalPartitionEnumerable : IEnumerable<KeyValuePair<long, TSource>>, IEnumerable
603  {
604  private readonly TSource[] m_sharedReader;
605 
606  private SharedLong m_sharedIndex;
607 
608  internal InternalPartitionEnumerable(TSource[] sharedReader)
609  {
610  m_sharedReader = sharedReader;
611  m_sharedIndex = new SharedLong(-1L);
612  }
613 
615  {
616  return GetEnumerator();
617  }
618 
619  public IEnumerator<KeyValuePair<long, TSource>> GetEnumerator()
620  {
621  return new InternalPartitionEnumerator(m_sharedReader, m_sharedIndex);
622  }
623  }
624 
625  private class InternalPartitionEnumerator : DynamicPartitionEnumeratorForIndexRange_Abstract<TSource, TSource[]>
626  {
627  protected override int SourceCount => m_sharedReader.Length;
628 
629  public override KeyValuePair<long, TSource> Current
630  {
631  get
632  {
633  if (m_currentChunkSize == null)
634  {
635  throw new InvalidOperationException(Environment.GetResourceString("PartitionerStatic_CurrentCalledBeforeMoveNext"));
636  }
637  return new KeyValuePair<long, TSource>(m_startIndex + m_localOffset.Value, m_sharedReader[m_startIndex + m_localOffset.Value]);
638  }
639  }
640 
641  internal InternalPartitionEnumerator(TSource[] sharedReader, SharedLong sharedIndex)
642  : base(sharedReader, sharedIndex)
643  {
644  }
645  }
646 
647  internal DynamicPartitionerForArray(TSource[] source)
648  : base(source)
649  {
650  }
651 
652  protected override IEnumerable<KeyValuePair<long, TSource>> GetOrderableDynamicPartitions_Factory(TSource[] m_data)
653  {
654  return new InternalPartitionEnumerable(m_data);
655  }
656  }
657 
658  private abstract class StaticIndexRangePartitioner<TSource, TCollection> : OrderablePartitioner<TSource>
659  {
660  protected abstract int SourceCount
661  {
662  get;
663  }
664 
665  protected StaticIndexRangePartitioner()
666  : base(keysOrderedInEachPartition: true, keysOrderedAcrossPartitions: true, keysNormalized: true)
667  {
668  }
669 
670  protected abstract IEnumerator<KeyValuePair<long, TSource>> CreatePartition(int startIndex, int endIndex);
671 
672  public override IList<IEnumerator<KeyValuePair<long, TSource>>> GetOrderablePartitions(int partitionCount)
673  {
674  if (partitionCount <= 0)
675  {
676  throw new ArgumentOutOfRangeException("partitionCount");
677  }
678  int result;
679  int num = Math.DivRem(SourceCount, partitionCount, out result);
681  int num2 = -1;
682  for (int i = 0; i < partitionCount; i++)
683  {
684  int num3 = num2 + 1;
685  num2 = ((i >= result) ? (num3 + num - 1) : (num3 + num));
686  array[i] = CreatePartition(num3, num2);
687  }
688  return array;
689  }
690  }
691 
692  private abstract class StaticIndexRangePartition<TSource> : IEnumerator<KeyValuePair<long, TSource>>, IDisposable, IEnumerator
693  {
694  protected readonly int m_startIndex;
695 
696  protected readonly int m_endIndex;
697 
698  protected volatile int m_offset;
699 
700  public abstract KeyValuePair<long, TSource> Current
701  {
702  get;
703  }
704 
705  object IEnumerator.Current
706  {
707  get
708  {
709  return Current;
710  }
711  }
712 
713  protected StaticIndexRangePartition(int startIndex, int endIndex)
714  {
715  m_startIndex = startIndex;
716  m_endIndex = endIndex;
717  m_offset = startIndex - 1;
718  }
719 
720  public void Dispose()
721  {
722  }
723 
724  public void Reset()
725  {
726  throw new NotSupportedException();
727  }
728 
729  public bool MoveNext()
730  {
731  if (m_offset < m_endIndex)
732  {
733  m_offset++;
734  return true;
735  }
736  m_offset = m_endIndex + 1;
737  return false;
738  }
739  }
740 
741  private class StaticIndexRangePartitionerForIList<TSource> : StaticIndexRangePartitioner<TSource, IList<TSource>>
742  {
743  private IList<TSource> m_list;
744 
745  protected override int SourceCount => m_list.Count;
746 
747  internal StaticIndexRangePartitionerForIList(IList<TSource> list)
748  {
749  m_list = list;
750  }
751 
752  protected override IEnumerator<KeyValuePair<long, TSource>> CreatePartition(int startIndex, int endIndex)
753  {
754  return new StaticIndexRangePartitionForIList<TSource>(m_list, startIndex, endIndex);
755  }
756  }
757 
758  private class StaticIndexRangePartitionForIList<TSource> : StaticIndexRangePartition<TSource>
759  {
760  private volatile IList<TSource> m_list;
761 
762  public override KeyValuePair<long, TSource> Current
763  {
764  get
765  {
766  if (m_offset < m_startIndex)
767  {
768  throw new InvalidOperationException(Environment.GetResourceString("PartitionerStatic_CurrentCalledBeforeMoveNext"));
769  }
770  return new KeyValuePair<long, TSource>(m_offset, m_list[m_offset]);
771  }
772  }
773 
774  internal StaticIndexRangePartitionForIList(IList<TSource> list, int startIndex, int endIndex)
775  : base(startIndex, endIndex)
776  {
777  m_list = list;
778  }
779  }
780 
781  private class StaticIndexRangePartitionerForArray<TSource> : StaticIndexRangePartitioner<TSource, TSource[]>
782  {
783  private TSource[] m_array;
784 
785  protected override int SourceCount => m_array.Length;
786 
787  internal StaticIndexRangePartitionerForArray(TSource[] array)
788  {
789  m_array = array;
790  }
791 
792  protected override IEnumerator<KeyValuePair<long, TSource>> CreatePartition(int startIndex, int endIndex)
793  {
794  return new StaticIndexRangePartitionForArray<TSource>(m_array, startIndex, endIndex);
795  }
796  }
797 
798  private class StaticIndexRangePartitionForArray<TSource> : StaticIndexRangePartition<TSource>
799  {
800  private volatile TSource[] m_array;
801 
802  public override KeyValuePair<long, TSource> Current
803  {
804  get
805  {
806  if (m_offset < m_startIndex)
807  {
808  throw new InvalidOperationException(Environment.GetResourceString("PartitionerStatic_CurrentCalledBeforeMoveNext"));
809  }
810  return new KeyValuePair<long, TSource>(m_offset, m_array[m_offset]);
811  }
812  }
813 
814  internal StaticIndexRangePartitionForArray(TSource[] array, int startIndex, int endIndex)
815  : base(startIndex, endIndex)
816  {
817  m_array = array;
818  }
819  }
820 
821  private class SharedInt
822  {
823  internal volatile int Value;
824 
825  internal SharedInt(int value)
826  {
827  Value = value;
828  }
829  }
830 
831  private class SharedBool
832  {
833  internal volatile bool Value;
834 
835  internal SharedBool(bool value)
836  {
837  Value = value;
838  }
839  }
840 
841  private class SharedLong
842  {
843  internal long Value;
844 
845  internal SharedLong(long value)
846  {
847  Value = value;
848  }
849  }
850 
851  private const int DEFAULT_BYTES_PER_CHUNK = 512;
852 
858  [__DynamicallyInvokable]
859  public static OrderablePartitioner<TSource> Create<TSource>(IList<TSource> list, bool loadBalance)
860  {
861  if (list == null)
862  {
863  throw new ArgumentNullException("list");
864  }
865  if (loadBalance)
866  {
867  return new DynamicPartitionerForIList<TSource>(list);
868  }
869  return new StaticIndexRangePartitionerForIList<TSource>(list);
870  }
871 
877  [__DynamicallyInvokable]
878  public static OrderablePartitioner<TSource> Create<TSource>(TSource[] array, bool loadBalance)
879  {
880  if (array == null)
881  {
882  throw new ArgumentNullException("array");
883  }
884  if (loadBalance)
885  {
886  return new DynamicPartitionerForArray<TSource>(array);
887  }
888  return new StaticIndexRangePartitionerForArray<TSource>(array);
889  }
890 
895  [__DynamicallyInvokable]
897  {
898  return Create(source, EnumerablePartitionerOptions.None);
899  }
900 
907  [__DynamicallyInvokable]
909  {
910  if (source == null)
911  {
912  throw new ArgumentNullException("source");
913  }
914  if ((partitionerOptions & ~EnumerablePartitionerOptions.NoBuffering) != 0)
915  {
916  throw new ArgumentOutOfRangeException("partitionerOptions");
917  }
918  return new DynamicPartitionerForIEnumerable<TSource>(source, partitionerOptions);
919  }
920 
926  [__DynamicallyInvokable]
927  public static OrderablePartitioner<Tuple<long, long>> Create(long fromInclusive, long toExclusive)
928  {
929  int num = 3;
930  if (toExclusive <= fromInclusive)
931  {
932  throw new ArgumentOutOfRangeException("toExclusive");
933  }
934  long num2 = (toExclusive - fromInclusive) / (PlatformHelper.ProcessorCount * num);
935  if (num2 == 0L)
936  {
937  num2 = 1L;
938  }
939  return Create(CreateRanges(fromInclusive, toExclusive, num2), EnumerablePartitionerOptions.NoBuffering);
940  }
941 
948  [__DynamicallyInvokable]
949  public static OrderablePartitioner<Tuple<long, long>> Create(long fromInclusive, long toExclusive, long rangeSize)
950  {
951  if (toExclusive <= fromInclusive)
952  {
953  throw new ArgumentOutOfRangeException("toExclusive");
954  }
955  if (rangeSize <= 0)
956  {
957  throw new ArgumentOutOfRangeException("rangeSize");
958  }
959  return Create(CreateRanges(fromInclusive, toExclusive, rangeSize), EnumerablePartitionerOptions.NoBuffering);
960  }
961 
962  private static IEnumerable<Tuple<long, long>> CreateRanges(long fromInclusive, long toExclusive, long rangeSize)
963  {
964  bool shouldQuit = false;
965  for (long i = fromInclusive; i < toExclusive; i += rangeSize)
966  {
967  if (shouldQuit)
968  {
969  break;
970  }
971  long item = i;
972  long num;
973  try
974  {
975  num = checked(i + rangeSize);
976  }
977  catch (OverflowException)
978  {
979  num = toExclusive;
980  shouldQuit = true;
981  }
982  if (num > toExclusive)
983  {
984  num = toExclusive;
985  }
986  yield return new Tuple<long, long>(item, num);
987  }
988  }
989 
995  [__DynamicallyInvokable]
996  public static OrderablePartitioner<Tuple<int, int>> Create(int fromInclusive, int toExclusive)
997  {
998  int num = 3;
999  if (toExclusive <= fromInclusive)
1000  {
1001  throw new ArgumentOutOfRangeException("toExclusive");
1002  }
1003  int num2 = (toExclusive - fromInclusive) / (PlatformHelper.ProcessorCount * num);
1004  if (num2 == 0)
1005  {
1006  num2 = 1;
1007  }
1008  return Create(CreateRanges(fromInclusive, toExclusive, num2), EnumerablePartitionerOptions.NoBuffering);
1009  }
1010 
1017  [__DynamicallyInvokable]
1018  public static OrderablePartitioner<Tuple<int, int>> Create(int fromInclusive, int toExclusive, int rangeSize)
1019  {
1020  if (toExclusive <= fromInclusive)
1021  {
1022  throw new ArgumentOutOfRangeException("toExclusive");
1023  }
1024  if (rangeSize <= 0)
1025  {
1026  throw new ArgumentOutOfRangeException("rangeSize");
1027  }
1028  return Create(CreateRanges(fromInclusive, toExclusive, rangeSize), EnumerablePartitionerOptions.NoBuffering);
1029  }
1030 
1031  private static IEnumerable<Tuple<int, int>> CreateRanges(int fromInclusive, int toExclusive, int rangeSize)
1032  {
1033  bool shouldQuit = false;
1034  for (int i = fromInclusive; i < toExclusive; i += rangeSize)
1035  {
1036  if (shouldQuit)
1037  {
1038  break;
1039  }
1040  int item = i;
1041  int num;
1042  try
1043  {
1044  num = checked(i + rangeSize);
1045  }
1046  catch (OverflowException)
1047  {
1048  num = toExclusive;
1049  shouldQuit = true;
1050  }
1051  if (num > toExclusive)
1052  {
1053  num = toExclusive;
1054  }
1055  yield return new Tuple<int, int>(item, num);
1056  }
1057  }
1058 
1059  private static int GetDefaultChunkSize<TSource>()
1060  {
1061  if (typeof(TSource).IsValueType)
1062  {
1063  if (typeof(TSource).StructLayoutAttribute.Value == LayoutKind.Explicit)
1064  {
1065  return Math.Max(1, 512 / Marshal.SizeOf(typeof(TSource)));
1066  }
1067  return 128;
1068  }
1069  return 512 / IntPtr.Size;
1070  }
1071  }
1072 }
The exception that is thrown when a null reference (Nothing in Visual Basic) is passed to a method th...
TValue Value
Gets the value in the key/value pair.
Definition: KeyValuePair.cs:32
Provides support for spin-based waiting.
Definition: SpinWait.cs:8
Represents a non-generic collection of objects that can be individually accessed by index.
Definition: IList.cs:8
Provides a mechanism for releasing unmanaged resources.To browse the .NET Framework source code for t...
Definition: IDisposable.cs:8
LayoutKind
Controls the layout of an object when exported to unmanaged code.
Definition: LayoutKind.cs:7
Definition: __Canon.cs:3
Specifies the current position within a stream.
new IEnumerator< T > GetEnumerator()
Returns an enumerator that iterates through the collection.
The exception that is thrown when the value of an argument is outside the allowable range of values a...
static int SizeOf(object structure)
Returns the unmanaged size of an object in bytes.
Definition: Marshal.cs:159
Exposes the enumerator, which supports a simple iteration over a collection of a specified type....
Definition: IEnumerable.cs:9
Supports a simple iteration over a generic collection.
Definition: IEnumerator.cs:6
The exception that is thrown when an arithmetic, casting, or conversion operation in a checked contex...
Lets you control the physical layout of the data fields of a class or structure in memory.
Partitioner()
Creates a new partitioner instance.
Definition: Partitioner.cs:43
SecurityAction
Specifies the security actions that can be performed using declarative security.
Provides information about, and means to manipulate, the current environment and platform....
Definition: Environment.cs:21
LayoutKind Value
Gets the T:System.Runtime.InteropServices.LayoutKind value that specifies how the class or structure ...
Represents a particular manner of splitting an orderable data source into multiple partitions.
EnumerablePartitionerOptions
Specifies options to control the buffering behavior of a partitioner
static int CompareExchange(ref int location1, int value, int comparand)
Compares two 32-bit signed integers for equality and, if they are equal, replaces the first value.
static int Increment(ref int location)
Increments a specified variable and stores the result, as an atomic operation.
Definition: Interlocked.cs:18
virtual IEnumerable< TSource > GetDynamicPartitions()
Creates an object that can partition the underlying collection into a variable number of partitions.
Definition: Partitioner.cs:36
static OrderablePartitioner< Tuple< long, long > > Create(long fromInclusive, long toExclusive, long rangeSize)
Creates a partitioner that chunks the user-specified range.
Definition: Partitioner.cs:949
Provides a collection of methods for allocating unmanaged memory, copying unmanaged memory blocks,...
Definition: Marshal.cs:15
Contains methods for performing volatile memory operations.
Definition: Volatile.cs:8
new T Current
Gets the element in the collection at the current position of the enumerator.
Definition: IEnumerator.cs:12
virtual bool SupportsDynamicPartitions
Gets whether additional partitions can be created dynamically.
Definition: Partitioner.cs:18
static OrderablePartitioner< Tuple< int, int > > Create(int fromInclusive, int toExclusive)
Creates a partitioner that chunks the user-specified range.
Definition: Partitioner.cs:996
static bool Read(ref bool location)
Reads the value of the specified field. On systems that require it, inserts a memory barrier that pre...
Definition: Volatile.cs:15
Represents a collection of objects that can be individually accessed by index.
Definition: IList.cs:9
static OrderablePartitioner< TSource > Create< TSource >(IList< TSource > list, bool loadBalance)
Creates an orderable partitioner from an T:System.Collections.Generic.IList`1 instance.
Definition: Partitioner.cs:859
int Count
Gets the number of elements contained in the T:System.Collections.Generic.ICollection`1.
Definition: ICollection.cs:15
void SpinOnce()
Performs a single spin.
Definition: SpinWait.cs:48
static OrderablePartitioner< Tuple< int, int > > Create(int fromInclusive, int toExclusive, int rangeSize)
Creates a partitioner that chunks the user-specified range.
static int Decrement(ref int location)
Decrements a specified variable and stores the result, as an atomic operation.
Definition: Interlocked.cs:40
The exception that is thrown when an invoked method is not supported, or when there is an attempt to ...
static int Add(ref int location1, int value)
Adds two 32-bit integers and replaces the first integer with the sum, as an atomic operation.
Definition: Interlocked.cs:247
Provides atomic operations for variables that are shared by multiple threads.
Definition: Interlocked.cs:10
Represents a particular manner of splitting a data source into multiple partitions.
Definition: Partitioner.cs:12
Supports a simple iteration over a non-generic collection.
Definition: IEnumerator.cs:9
static OrderablePartitioner< Tuple< long, long > > Create(long fromInclusive, long toExclusive)
Creates a partitioner that chunks the user-specified range.
Definition: Partitioner.cs:927
abstract IList< IEnumerator< TSource > > GetPartitions(int partitionCount)
Partitions the underlying collection into the given number of partitions.