3 // Copyright (c) Microsoft Corporation. All rights reserved.
6 // =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
10 // <OWNER>[....]</OWNER>
12 // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
14 using System.Collections.Generic;
15 using System.Diagnostics.Contracts;
17 namespace System.Linq.Parallel
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.
23 /// <typeparam name="TResult"></typeparam>
24 internal class RepeatEnumerable<TResult> : ParallelQuery<TResult>, IParallelPartitionable<TResult>
27 private TResult m_element; // Element value to repeat.
28 private int m_count; // Count of element values.
30 //-----------------------------------------------------------------------------------
31 // Constructs a new repeat enumerable object for the repeat operation.
34 internal RepeatEnumerable(TResult element, int count)
35 : base(QuerySettings.Empty)
37 Contract.Assert(count >= 0, "count not within range (must be >= 0)");
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.
47 public QueryOperatorEnumerator<TResult, int>[] GetPartitions(int partitionCount)
49 // Calculate a stride size.
50 int stride = (m_count + partitionCount - 1) / partitionCount;
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)
58 if ((offset + stride) > m_count)
60 partitions[i] = new RepeatEnumerator(m_element, offset < m_count ? m_count - offset : 0, offset);
64 partitions[i] = new RepeatEnumerator(m_element, stride, offset);
71 //-----------------------------------------------------------------------------------
72 // Basic IEnumerator<T> method implementations.
75 public override IEnumerator<TResult> GetEnumerator()
77 return new RepeatEnumerator(m_element, m_count, 0).AsClassicEnumerator();
80 //-----------------------------------------------------------------------------------
81 // The actual enumerator that produces a set of repeated elements.
84 class RepeatEnumerator : QueryOperatorEnumerator<TResult, int>
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]
92 //-----------------------------------------------------------------------------------
93 // Creates a new enumerator.
96 internal RepeatEnumerator(TResult element, int count, int indexOffset)
100 m_indexOffset = indexOffset;
103 //-----------------------------------------------------------------------------------
104 // Basic IEnumerator<T> methods. These produce the repeating sequence..
107 internal override bool MoveNext(ref TResult currentElement, ref int currentKey)
109 if( m_currentIndex == null)
110 m_currentIndex = new Shared<int>(-1);
112 if (m_currentIndex.Value < (m_count - 1))
114 ++m_currentIndex.Value;
115 currentElement = m_element;
116 currentKey = m_currentIndex.Value + m_indexOffset;
123 internal override void Reset()
125 m_currentIndex = null;