Update Reference Sources to .NET Framework 4.6.1
[mono.git] / mcs / class / referencesource / System.Core / System / Linq / Parallel / Enumerables / RepeatEnumerable.cs
1 // ==++==
2 //
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 // 
5 // ==--==
6 // =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
7 //
8 // RepeatEnumerable.cs
9 //
10 // <OWNER>[....]</OWNER>
11 //
12 // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
13
14 using System.Collections.Generic;
15 using System.Diagnostics.Contracts;
16
17 namespace System.Linq.Parallel
18 {
19     /// <summary>
20     /// A simple enumerable type that implements the repeat algorithm. It also supports
21     /// partitioning of the count space by implementing an interface that PLINQ recognizes.
22     /// </summary>
23     /// <typeparam name="TResult"></typeparam>
24     internal class RepeatEnumerable<TResult> : ParallelQuery<TResult>, IParallelPartitionable<TResult>
25     {
26
27         private TResult m_element; // Element value to repeat.
28         private int m_count; // Count of element values.
29
30         //-----------------------------------------------------------------------------------
31         // Constructs a new repeat enumerable object for the repeat operation.
32         //
33
34         internal RepeatEnumerable(TResult element, int count)
35             : base(QuerySettings.Empty)
36         {
37             Contract.Assert(count >= 0, "count not within range (must be >= 0)");
38             m_element = element;
39             m_count = count;
40         }
41
42         //-----------------------------------------------------------------------------------
43         // Retrieves 'count' partitions, dividing the total count by the partition count,
44         // and having each partition produce a certain number of repeated elements.
45         //
46
47         public QueryOperatorEnumerator<TResult, int>[] GetPartitions(int partitionCount)
48         {
49             // Calculate a stride size.
50             int stride = (m_count + partitionCount - 1) / partitionCount;
51
52             // Now generate the actual enumerators. Each produces 'stride' elements, except
53             // for the last partition which may produce fewer (if 'm_count' isn't evenly
54             // divisible by 'partitionCount').
55             QueryOperatorEnumerator<TResult, int>[] partitions = new QueryOperatorEnumerator<TResult, int>[partitionCount];
56             for (int i = 0, offset = 0; i < partitionCount; i++, offset += stride)
57             {
58                 if ((offset + stride) > m_count)
59                 {
60                     partitions[i] = new RepeatEnumerator(m_element, offset < m_count ? m_count - offset : 0, offset);
61                 }
62                 else
63                 {
64                     partitions[i] = new RepeatEnumerator(m_element, stride, offset);
65                 }
66             }
67
68             return partitions;
69         }
70
71         //-----------------------------------------------------------------------------------
72         // Basic IEnumerator<T> method implementations.
73         //
74
75         public override IEnumerator<TResult> GetEnumerator()
76         {
77             return new RepeatEnumerator(m_element, m_count, 0).AsClassicEnumerator();
78         }
79
80         //-----------------------------------------------------------------------------------
81         // The actual enumerator that produces a set of repeated elements.
82         //
83
84         class RepeatEnumerator : QueryOperatorEnumerator<TResult, int>
85         {
86
87             private readonly TResult m_element; // The element to repeat.
88             private readonly int m_count; // The number of times to repeat it.
89             private readonly int m_indexOffset; // Our index offset.
90             private Shared<int> m_currentIndex; // The number of times we have already repeated it. [allocate in moveNext to avoid false-sharing]
91
92             //-----------------------------------------------------------------------------------
93             // Creates a new enumerator.
94             //
95
96             internal RepeatEnumerator(TResult element, int count, int indexOffset)
97             {
98                 m_element = element;
99                 m_count = count;
100                 m_indexOffset = indexOffset;
101             }
102
103             //-----------------------------------------------------------------------------------
104             // Basic IEnumerator<T> methods. These produce the repeating sequence..
105             //
106
107             internal override bool MoveNext(ref TResult currentElement, ref int currentKey)
108             {
109                 if( m_currentIndex == null)
110                     m_currentIndex = new Shared<int>(-1);
111                 
112                 if (m_currentIndex.Value < (m_count - 1))
113                 {
114                     ++m_currentIndex.Value;
115                     currentElement = m_element;
116                     currentKey = m_currentIndex.Value + m_indexOffset;
117                     return true;
118                 }
119
120                 return false;
121             }
122
123             internal override void Reset()
124             {
125                 m_currentIndex = null;
126             }
127         }
128     }
129 }