PageRenderTime 54ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/src/System.Collections.Concurrent/src/System/Collections/Concurrent/OrderablePartitioner.cs

https://gitlab.com/0072016/0072016-corefx-
C# | 276 lines | 98 code | 15 blank | 163 comment | 5 complexity | aa1a09b877466466d73f732bc7d4790d MD5 | raw file
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the MIT license.
  3. // See the LICENSE file in the project root for more information.
  4. // =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
  5. //
  6. // OrderablePartitioner.cs
  7. //
  8. //
  9. //
  10. //
  11. // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  12. using System.Collections.Generic;
  13. namespace System.Collections.Concurrent
  14. {
  15. /// <summary>
  16. /// Represents a particular manner of splitting an orderable data source into multiple partitions.
  17. /// </summary>
  18. /// <typeparam name="TSource">Type of the elements in the collection.</typeparam>
  19. /// <remarks>
  20. /// <para>
  21. /// Each element in each partition has an integer index associated with it, which determines the relative
  22. /// order of that element against elements in other partitions.
  23. /// </para>
  24. /// <para>
  25. /// Inheritors of <see cref="OrderablePartitioner{TSource}"/> must adhere to the following rules:
  26. /// <ol>
  27. /// <li>All indices must be unique, such that there may not be duplicate indices. If all indices are not
  28. /// unique, the output ordering may be scrambled.</li>
  29. /// <li>All indices must be non-negative. If any indices are negative, consumers of the implementation
  30. /// may throw exceptions.</li>
  31. /// <li><see cref="GetPartitions"/> and <see cref="GetOrderablePartitions"/> should throw a
  32. /// <see cref="T:System.ArgumentOutOfRangeException"/> if the requested partition count is less than or
  33. /// equal to zero.</li>
  34. /// <li><see cref="GetPartitions"/> and <see cref="GetOrderablePartitions"/> should always return a number
  35. /// of enumerables equal to the requested partition count. If the partitioner runs out of data and cannot
  36. /// create as many partitions as requested, an empty enumerator should be returned for each of the
  37. /// remaining partitions. If this rule is not followed, consumers of the implementation may throw a <see
  38. /// cref="T:System.InvalidOperationException"/>.</li>
  39. /// <li><see cref="GetPartitions"/>, <see cref="GetOrderablePartitions"/>,
  40. /// <see cref="GetDynamicPartitions"/>, and <see cref="GetOrderableDynamicPartitions"/>
  41. /// should never return null. If null is returned, a consumer of the implementation may throw a
  42. /// <see cref="T:System.InvalidOperationException"/>.</li>
  43. /// <li><see cref="GetPartitions"/>, <see cref="GetOrderablePartitions"/>,
  44. /// <see cref="GetDynamicPartitions"/>, and <see cref="GetOrderableDynamicPartitions"/>
  45. /// should always return partitions that can fully and uniquely enumerate the input data source. All of
  46. /// the data and only the data contained in the input source should be enumerated, with no duplication
  47. /// that was not already in the input, unless specifically required by the particular partitioner's
  48. /// design. If this is not followed, the output ordering may be scrambled.</li>
  49. /// <li>If <see cref="KeysOrderedInEachPartition"/> returns true, each partition must return elements
  50. /// with increasing key indices.</li>
  51. /// <li>If <see cref="KeysOrderedAcrossPartitions"/> returns true, all the keys in partition numbered N
  52. /// must be larger than all the keys in partition numbered N-1.</li>
  53. /// <li>If <see cref="KeysNormalized"/> returns true, all indices must be monotonically increasing from
  54. /// 0, though not necessarily within a single partition.</li>
  55. /// </ol>
  56. /// </para>
  57. /// </remarks>
  58. public abstract class OrderablePartitioner<TSource> : Partitioner<TSource>
  59. {
  60. /// <summary>
  61. /// Initializes a new instance of the <see cref="OrderablePartitioner{TSource}"/> class with the
  62. /// specified constraints on the index keys.
  63. /// </summary>
  64. /// <param name="keysOrderedInEachPartition">
  65. /// Indicates whether the elements in each partition are yielded in the order of
  66. /// increasing keys.
  67. /// </param>
  68. /// <param name="keysOrderedAcrossPartitions">
  69. /// Indicates whether elements in an earlier partition always come before
  70. /// elements in a later partition. If true, each element in partition 0 has a smaller order key than
  71. /// any element in partition 1, each element in partition 1 has a smaller order key than any element
  72. /// in partition 2, and so on.
  73. /// </param>
  74. /// <param name="keysNormalized">
  75. /// Indicates whether keys are normalized. If true, all order keys are distinct
  76. /// integers in the range [0 .. numberOfElements-1]. If false, order keys must still be distinct, but
  77. /// only their relative order is considered, not their absolute values.
  78. /// </param>
  79. protected OrderablePartitioner(bool keysOrderedInEachPartition, bool keysOrderedAcrossPartitions, bool keysNormalized)
  80. {
  81. KeysOrderedInEachPartition = keysOrderedInEachPartition;
  82. KeysOrderedAcrossPartitions = keysOrderedAcrossPartitions;
  83. KeysNormalized = keysNormalized;
  84. }
  85. /// <summary>
  86. /// Partitions the underlying collection into the specified number of orderable partitions.
  87. /// </summary>
  88. /// <remarks>
  89. /// Each partition is represented as an enumerator over key-value pairs.
  90. /// The value of the pair is the element itself, and the key is an integer which determines
  91. /// the relative ordering of this element against other elements in the data source.
  92. /// </remarks>
  93. /// <param name="partitionCount">The number of partitions to create.</param>
  94. /// <returns>A list containing <paramref name="partitionCount"/> enumerators.</returns>
  95. public abstract IList<IEnumerator<KeyValuePair<long, TSource>>> GetOrderablePartitions(int partitionCount);
  96. /// <summary>
  97. /// Creates an object that can partition the underlying collection into a variable number of
  98. /// partitions.
  99. /// </summary>
  100. /// <remarks>
  101. /// <para>
  102. /// The returned object implements the <see
  103. /// cref="T:System.Collections.Generic.IEnumerable{TSource}"/> interface. Calling <see
  104. /// cref="System.Collections.Generic.IEnumerable{TSource}.GetEnumerator">GetEnumerator</see> on the
  105. /// object creates another partition over the sequence.
  106. /// </para>
  107. /// <para>
  108. /// Each partition is represented as an enumerator over key-value pairs. The value in the pair is the element
  109. /// itself, and the key is an integer which determines the relative ordering of this element against
  110. /// other elements.
  111. /// </para>
  112. /// <para>
  113. /// The <see cref="GetOrderableDynamicPartitions"/> method is only supported if the <see
  114. /// cref="System.Collections.Concurrent.Partitioner{TSource}.SupportsDynamicPartitions">SupportsDynamicPartitions</see>
  115. /// property returns true.
  116. /// </para>
  117. /// </remarks>
  118. /// <returns>An object that can create partitions over the underlying data source.</returns>
  119. /// <exception cref="NotSupportedException">Dynamic partitioning is not supported by this
  120. /// partitioner.</exception>
  121. public virtual IEnumerable<KeyValuePair<long, TSource>> GetOrderableDynamicPartitions()
  122. {
  123. throw new NotSupportedException(SR.Partitioner_DynamicPartitionsNotSupported);
  124. }
  125. /// <summary>
  126. /// Gets whether elements in each partition are yielded in the order of increasing keys.
  127. /// </summary>
  128. public bool KeysOrderedInEachPartition { get; private set; }
  129. /// <summary>
  130. /// Gets whether elements in an earlier partition always come before elements in a later partition.
  131. /// </summary>
  132. /// <remarks>
  133. /// If <see cref="KeysOrderedAcrossPartitions"/> returns true, each element in partition 0 has a
  134. /// smaller order key than any element in partition 1, each element in partition 1 has a smaller
  135. /// order key than any element in partition 2, and so on.
  136. /// </remarks>
  137. public bool KeysOrderedAcrossPartitions { get; private set; }
  138. /// <summary>
  139. /// Gets whether order keys are normalized.
  140. /// </summary>
  141. /// <remarks>
  142. /// If <see cref="KeysNormalized"/> returns true, all order keys are distinct integers in the range
  143. /// [0 .. numberOfElements-1]. If the property returns false, order keys must still be distinct, but
  144. /// only their relative order is considered, not their absolute values.
  145. /// </remarks>
  146. public bool KeysNormalized { get; private set; }
  147. /// <summary>
  148. /// Partitions the underlying collection into the given number of ordered partitions.
  149. /// </summary>
  150. /// <remarks>
  151. /// The default implementation provides the same behavior as <see cref="GetOrderablePartitions"/> except
  152. /// that the returned set of partitions does not provide the keys for the elements.
  153. /// </remarks>
  154. /// <param name="partitionCount">The number of partitions to create.</param>
  155. /// <returns>A list containing <paramref name="partitionCount"/> enumerators.</returns>
  156. public override IList<IEnumerator<TSource>> GetPartitions(int partitionCount)
  157. {
  158. IList<IEnumerator<KeyValuePair<long, TSource>>> orderablePartitions = GetOrderablePartitions(partitionCount);
  159. if (orderablePartitions.Count != partitionCount)
  160. {
  161. throw new InvalidOperationException("OrderablePartitioner_GetPartitions_WrongNumberOfPartitions");
  162. }
  163. IEnumerator<TSource>[] partitions = new IEnumerator<TSource>[partitionCount];
  164. for (int i = 0; i < partitionCount; i++)
  165. {
  166. partitions[i] = new EnumeratorDropIndices(orderablePartitions[i]);
  167. }
  168. return partitions;
  169. }
  170. /// <summary>
  171. /// Creates an object that can partition the underlying collection into a variable number of
  172. /// partitions.
  173. /// </summary>
  174. /// <remarks>
  175. /// <para>
  176. /// The returned object implements the <see
  177. /// cref="T:System.Collections.Generic.IEnumerable{TSource}"/> interface. Calling <see
  178. /// cref="System.Collections.Generic.IEnumerable{TSource}.GetEnumerator">GetEnumerator</see> on the
  179. /// object creates another partition over the sequence.
  180. /// </para>
  181. /// <para>
  182. /// The default implementation provides the same behavior as <see cref="GetOrderableDynamicPartitions"/> except
  183. /// that the returned set of partitions does not provide the keys for the elements.
  184. /// </para>
  185. /// <para>
  186. /// The <see cref="GetDynamicPartitions"/> method is only supported if the <see
  187. /// cref="System.Collections.Concurrent.Partitioner{TSource}.SupportsDynamicPartitions"/>
  188. /// property returns true.
  189. /// </para>
  190. /// </remarks>
  191. /// <returns>An object that can create partitions over the underlying data source.</returns>
  192. /// <exception cref="NotSupportedException">Dynamic partitioning is not supported by this
  193. /// partitioner.</exception>
  194. public override IEnumerable<TSource> GetDynamicPartitions()
  195. {
  196. IEnumerable<KeyValuePair<long, TSource>> orderablePartitions = GetOrderableDynamicPartitions();
  197. return new EnumerableDropIndices(orderablePartitions);
  198. }
  199. /// <summary>
  200. /// Converts an enumerable over key-value pairs to an enumerable over values.
  201. /// </summary>
  202. private class EnumerableDropIndices : IEnumerable<TSource>, IDisposable
  203. {
  204. private readonly IEnumerable<KeyValuePair<long, TSource>> _source;
  205. public EnumerableDropIndices(IEnumerable<KeyValuePair<long, TSource>> source)
  206. {
  207. _source = source;
  208. }
  209. public IEnumerator<TSource> GetEnumerator()
  210. {
  211. return new EnumeratorDropIndices(_source.GetEnumerator());
  212. }
  213. IEnumerator IEnumerable.GetEnumerator()
  214. {
  215. return ((EnumerableDropIndices)this).GetEnumerator();
  216. }
  217. public void Dispose()
  218. {
  219. IDisposable d = _source as IDisposable;
  220. if (d != null)
  221. {
  222. d.Dispose();
  223. }
  224. }
  225. }
  226. private class EnumeratorDropIndices : IEnumerator<TSource>
  227. {
  228. private readonly IEnumerator<KeyValuePair<long, TSource>> _source;
  229. public EnumeratorDropIndices(IEnumerator<KeyValuePair<long, TSource>> source)
  230. {
  231. _source = source;
  232. }
  233. public bool MoveNext()
  234. {
  235. return _source.MoveNext();
  236. }
  237. public TSource Current
  238. {
  239. get
  240. {
  241. return _source.Current.Value;
  242. }
  243. }
  244. Object IEnumerator.Current
  245. {
  246. get
  247. {
  248. return ((EnumeratorDropIndices)this).Current;
  249. }
  250. }
  251. public void Dispose()
  252. {
  253. _source.Dispose();
  254. }
  255. public void Reset()
  256. {
  257. _source.Reset();
  258. }
  259. }
  260. }
  261. }