-
Notifications
You must be signed in to change notification settings - Fork 30
/
AbstractHistogramEnumerator.cs
180 lines (161 loc) · 6.84 KB
/
AbstractHistogramEnumerator.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
/*
* This is a .NET port of the original Java version, which was written by
* Gil Tene as described in
* https://github.com/HdrHistogram/HdrHistogram
* and released to the public domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
*/
using System;
using System.Collections;
using System.Collections.Generic;
namespace HdrHistogram.Iteration
{
/// <summary>
/// Provide functionality for enumerating over histogram counts.
/// </summary>
internal abstract class AbstractHistogramEnumerator : IEnumerator<HistogramIterationValue>
{
private readonly long _savedHistogramTotalRawCount;
private readonly HistogramIterationValue _currentIterationValue;
private int _nextBucketIndex;
private int _nextSubBucketIndex;
private long _prevValueIteratedTo;
private long _totalCountToPrevIndex;
private long _totalValueToCurrentIndex;
private bool _freshSubBucket;
private long _currentValueAtIndex;
private long _nextValueAtIndex;
protected HistogramBase SourceHistogram { get; }
protected long ArrayTotalCount { get; }
protected int CurrentBucketIndex { get; private set; }
protected int CurrentSubBucketIndex { get; private set; }
protected long TotalCountToCurrentIndex { get; private set; }
protected long CountAtThisValue { get; private set; }
public HistogramIterationValue Current { get; private set; }
protected AbstractHistogramEnumerator(HistogramBase histogram)
{
SourceHistogram = histogram;
_savedHistogramTotalRawCount = histogram.TotalCount;
ArrayTotalCount = histogram.TotalCount;
CurrentBucketIndex = 0;
CurrentSubBucketIndex = 0;
_currentValueAtIndex = 0;
_nextBucketIndex = 0;
_nextSubBucketIndex = 1;
_nextValueAtIndex = 1;
_prevValueIteratedTo = 0;
_totalCountToPrevIndex = 0;
TotalCountToCurrentIndex = 0;
_totalValueToCurrentIndex = 0;
CountAtThisValue = 0;
_freshSubBucket = true;
_currentIterationValue = new HistogramIterationValue();
}
/// <summary>
/// Returns <c>true</c> if the iteration has more elements. (In other words, returns true if next would return an element rather than throwing an exception.)
/// </summary>
/// <returns><c>true</c> if the iterator has more elements.</returns>
protected virtual bool HasNext()
{
if (SourceHistogram.TotalCount != _savedHistogramTotalRawCount)
{
throw new InvalidOperationException("Source has been modified during enumeration.");
}
return (TotalCountToCurrentIndex < ArrayTotalCount);
}
protected abstract void IncrementIterationLevel();
protected abstract bool ReachedIterationLevel();
protected virtual double GetPercentileIteratedTo()
{
return (100.0 * TotalCountToCurrentIndex) / ArrayTotalCount;
}
protected virtual long GetValueIteratedTo()
{
return SourceHistogram.HighestEquivalentValue(_currentValueAtIndex);
}
/// <summary>
/// Returns the next element in the iteration.
/// </summary>
/// <returns>the <see cref="HistogramIterationValue"/> associated with the next element in the iteration.</returns>
private HistogramIterationValue Next()
{
// Move through the sub buckets and buckets until we hit the next reporting level:
while (!ExhaustedSubBuckets())
{
CountAtThisValue = SourceHistogram.GetCountAt(CurrentBucketIndex, CurrentSubBucketIndex);
if (_freshSubBucket)
{
// Don't add unless we've incremented since last bucket...
TotalCountToCurrentIndex += CountAtThisValue;
_totalValueToCurrentIndex += CountAtThisValue * SourceHistogram.MedianEquivalentValue(_currentValueAtIndex);
_freshSubBucket = false;
}
if (ReachedIterationLevel())
{
var valueIteratedTo = GetValueIteratedTo();
_currentIterationValue.Set(
valueIteratedTo,
_prevValueIteratedTo,
CountAtThisValue,
(TotalCountToCurrentIndex - _totalCountToPrevIndex),
TotalCountToCurrentIndex,
_totalValueToCurrentIndex,
((100.0 * TotalCountToCurrentIndex) / ArrayTotalCount),
GetPercentileIteratedTo());
_prevValueIteratedTo = valueIteratedTo;
_totalCountToPrevIndex = TotalCountToCurrentIndex;
// move the next iteration level forward:
IncrementIterationLevel();
if (SourceHistogram.TotalCount != _savedHistogramTotalRawCount)
{
throw new InvalidOperationException("Source has been modified during enumeration.");
}
return _currentIterationValue;
}
IncrementSubBucket();
}
// Should not reach here. But possible for overflowed histograms under certain conditions
throw new ArgumentOutOfRangeException();
}
private bool ExhaustedSubBuckets()
{
return (CurrentBucketIndex >= SourceHistogram.BucketCount);
}
private void IncrementSubBucket()
{
_freshSubBucket = true;
// Take on the next index:
CurrentBucketIndex = _nextBucketIndex;
CurrentSubBucketIndex = _nextSubBucketIndex;
_currentValueAtIndex = _nextValueAtIndex;
// Figure out the next next index:
_nextSubBucketIndex++;
if (_nextSubBucketIndex >= SourceHistogram.SubBucketCount)
{
_nextSubBucketIndex = SourceHistogram.SubBucketHalfCount;
_nextBucketIndex++;
}
_nextValueAtIndex = SourceHistogram.ValueFromIndex(_nextBucketIndex, _nextSubBucketIndex);
}
#region IEnumerator explicit implementation
object IEnumerator.Current => Current;
bool IEnumerator.MoveNext()
{
var canMove = HasNext();
if (canMove)
{
Current = Next();
}
return canMove;
}
void IEnumerator.Reset()
{
//throw new NotImplementedException();
}
void IDisposable.Dispose()
{
//throw new NotImplementedException();
}
#endregion
}
}