3 // Copyright (c) Microsoft Corporation. All rights reserved.
6 // =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
8 // NullableFloatMinMaxAggregationOperator.cs
10 // <OWNER>Microsoft</OWNER>
12 // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
14 using System
.Collections
.Generic
;
15 using System
.Diagnostics
.Contracts
;
16 using System
.Threading
;
18 namespace System
.Linq
.Parallel
21 /// An inlined min/max aggregation and its enumerator, for Nullable floats.
24 /// Note that normally float.NaN < anything is false, as is anything < NaN. This would
25 /// lead to some strangeness in Min and Max, e.g. Min({ NaN, 5.0 } == NaN, yet
26 /// Min({ 5.0, NaN }) == 5.0! We impose a total ordering so that NaN is smaller than
27 /// everything, including -infinity, which is consistent with Comparer_T.
29 internal sealed class NullableFloatMinMaxAggregationOperator
: InlinedAggregationOperator
<float?, float?, float?>
31 private readonly int m_sign
; // The sign (-1 for min, 1 for max).
33 //---------------------------------------------------------------------------------------
34 // Constructs a new instance of a min/max associative operator.
37 internal NullableFloatMinMaxAggregationOperator(IEnumerable
<float?> child
, int sign
) : base(child
)
39 Contract
.Assert(sign
== -1 || sign
== 1, "invalid sign");
43 //---------------------------------------------------------------------------------------
44 // Executes the entire query tree, and aggregates the intermediate results into the
45 // final result based on the binary operators and final reduction.
48 // The single result of aggregation.
51 protected override float? InternalAggregate(ref Exception singularExceptionToThrow
)
53 // Because the final reduction is typically much cheaper than the intermediate
54 // reductions over the individual partitions, and because each parallel partition
55 // will do a lot of work to produce a single output element, we prefer to turn off
56 // pipelining, and process the final reductions serially.
57 using (IEnumerator
<float?> enumerator
= GetEnumerator(ParallelMergeOptions
.FullyBuffered
, true))
59 // Just return null right away for empty results.
60 if (!enumerator
.MoveNext())
65 float? best
= enumerator
.Current
;
67 // Based on the sign, do either a min or max reduction.
70 while (enumerator
.MoveNext())
72 float? current
= enumerator
.Current
;
73 if (current
== null) continue;
74 if (best
== null || current
< best
|| float.IsNaN(current
.GetValueOrDefault()))
82 while (enumerator
.MoveNext())
84 float? current
= enumerator
.Current
;
85 if (current
== null) continue;
86 if (best
== null || current
> best
|| float.IsNaN(best
.GetValueOrDefault()))
97 //---------------------------------------------------------------------------------------
98 // Creates an enumerator that is used internally for the final aggregation step.
101 protected override QueryOperatorEnumerator
<float?, int> CreateEnumerator
<TKey
>(
102 int index
, int count
, QueryOperatorEnumerator
<float?, TKey
> source
, object sharedData
, CancellationToken cancellationToken
)
104 return new NullableFloatMinMaxAggregationOperatorEnumerator
<TKey
>(source
, index
, m_sign
, cancellationToken
);
107 //---------------------------------------------------------------------------------------
108 // This enumerator type encapsulates the intermediary aggregation over the underlying
109 // (possibly partitioned) data source.
112 private class NullableFloatMinMaxAggregationOperatorEnumerator
<TKey
> : InlinedAggregationOperatorEnumerator
<float?>
114 private QueryOperatorEnumerator
<float?, TKey
> m_source
; // The source data.
115 private int m_sign
; // The sign for comparisons (-1 means min, 1 means max).
117 //---------------------------------------------------------------------------------------
118 // Instantiates a new aggregation operator.
121 internal NullableFloatMinMaxAggregationOperatorEnumerator(QueryOperatorEnumerator
<float?, TKey
> source
, int partitionIndex
, int sign
,
122 CancellationToken cancellationToken
) :
123 base(partitionIndex
, cancellationToken
)
125 Contract
.Assert(source
!= null);
130 //---------------------------------------------------------------------------------------
131 // Tallies up the min/max of the underlying data source, walking the entire thing the first
132 // time MoveNext is called on this object.
135 protected override bool MoveNextCore(ref float? currentElement
)
137 // Based on the sign, do either a min or max reduction.
138 QueryOperatorEnumerator
<float?, TKey
> source
= m_source
;
139 TKey keyUnused
= default(TKey
);
141 if (source
.MoveNext(ref currentElement
, ref keyUnused
))
144 // We just scroll through the enumerator and find the min or max.
147 float? elem
= default(float?);
148 while (source
.MoveNext(ref elem
, ref keyUnused
))
150 if ((i
++ & CancellationState
.POLL_INTERVAL
) == 0)
151 CancellationState
.ThrowIfCanceled(m_cancellationToken
);
153 if (elem
== null) continue;
154 if (currentElement
== null || elem
< currentElement
|| float.IsNaN(elem
.GetValueOrDefault()))
156 currentElement
= elem
;
162 float? elem
= default(float?);
163 while (source
.MoveNext(ref elem
, ref keyUnused
))
165 if ((i
++ & CancellationState
.POLL_INTERVAL
) == 0)
166 CancellationState
.ThrowIfCanceled(m_cancellationToken
);
168 if (elem
== null) continue;
169 if (currentElement
== null || elem
> currentElement
|| float.IsNaN(currentElement
.GetValueOrDefault()))
171 currentElement
= elem
;
176 // The sum has been calculated. Now just return.
183 //---------------------------------------------------------------------------------------
184 // Dispose of resources associated with the underlying enumerator.
187 protected override void Dispose(bool disposing
)
189 Contract
.Assert(m_source
!= null);