1 | /*
|
---|
2 | * This is a TypeScript port of the original Java version, which was written by
|
---|
3 | * Gil Tene as described in
|
---|
4 | * https://github.com/HdrHistogram/HdrHistogram
|
---|
5 | * and released to the public domain, as explained at
|
---|
6 | * http://creativecommons.org/publicdomain/zero/1.0/
|
---|
7 | */
|
---|
8 | import JsHistogram from "./JsHistogram";
|
---|
9 | import HistogramIterationValue from "./HistogramIterationValue";
|
---|
10 |
|
---|
11 | /**
|
---|
12 | * Used for iterating through histogram values.
|
---|
13 | */
|
---|
14 | abstract class JsHistogramIterator /* implements Iterator<HistogramIterationValue> */ {
|
---|
15 | histogram: JsHistogram;
|
---|
16 | savedHistogramTotalRawCount: number;
|
---|
17 | currentIndex: number;
|
---|
18 | currentValueAtIndex: number;
|
---|
19 | nextValueAtIndex: number;
|
---|
20 | prevValueIteratedTo: number;
|
---|
21 | totalCountToPrevIndex: number;
|
---|
22 | totalCountToCurrentIndex: number;
|
---|
23 | totalValueToCurrentIndex: number;
|
---|
24 | arrayTotalCount: number;
|
---|
25 | countAtThisValue: number;
|
---|
26 |
|
---|
27 | private freshSubBucket: boolean;
|
---|
28 |
|
---|
29 | currentIterationValue: HistogramIterationValue = new HistogramIterationValue();
|
---|
30 |
|
---|
31 | resetIterator(histogram: JsHistogram) {
|
---|
32 | this.histogram = histogram;
|
---|
33 | this.savedHistogramTotalRawCount = histogram.totalCount;
|
---|
34 | this.arrayTotalCount = histogram.totalCount;
|
---|
35 | this.currentIndex = 0;
|
---|
36 | this.currentValueAtIndex = 0;
|
---|
37 | this.nextValueAtIndex = Math.pow(2, histogram.unitMagnitude);
|
---|
38 | this.prevValueIteratedTo = 0;
|
---|
39 | this.totalCountToPrevIndex = 0;
|
---|
40 | this.totalCountToCurrentIndex = 0;
|
---|
41 | this.totalValueToCurrentIndex = 0;
|
---|
42 | this.countAtThisValue = 0;
|
---|
43 | this.freshSubBucket = true;
|
---|
44 | this.currentIterationValue.reset();
|
---|
45 | }
|
---|
46 |
|
---|
47 | /**
|
---|
48 | * Returns true if the iteration has more elements. (In other words, returns true if next would return an
|
---|
49 | * element rather than throwing an exception.)
|
---|
50 | *
|
---|
51 | * @return true if the iterator has more elements.
|
---|
52 | */
|
---|
53 | public hasNext(): boolean {
|
---|
54 | if (this.histogram.totalCount !== this.savedHistogramTotalRawCount) {
|
---|
55 | throw "Concurrent Modification Exception";
|
---|
56 | }
|
---|
57 | return this.totalCountToCurrentIndex < this.arrayTotalCount;
|
---|
58 | }
|
---|
59 |
|
---|
60 | /**
|
---|
61 | * Returns the next element in the iteration.
|
---|
62 | *
|
---|
63 | * @return the {@link HistogramIterationValue} associated with the next element in the iteration.
|
---|
64 | */
|
---|
65 | public next(): HistogramIterationValue {
|
---|
66 | // Move through the sub buckets and buckets until we hit the next reporting level:
|
---|
67 | while (!this.exhaustedSubBuckets()) {
|
---|
68 | this.countAtThisValue = this.histogram.getCountAtIndex(this.currentIndex);
|
---|
69 | if (this.freshSubBucket) {
|
---|
70 | // Don't add unless we've incremented since last bucket...
|
---|
71 | this.totalCountToCurrentIndex += this.countAtThisValue;
|
---|
72 | this.totalValueToCurrentIndex +=
|
---|
73 | this.countAtThisValue *
|
---|
74 | this.histogram.highestEquivalentValue(this.currentValueAtIndex);
|
---|
75 | this.freshSubBucket = false;
|
---|
76 | }
|
---|
77 | if (this.reachedIterationLevel()) {
|
---|
78 | const valueIteratedTo = this.getValueIteratedTo();
|
---|
79 |
|
---|
80 | Object.assign(this.currentIterationValue, {
|
---|
81 | valueIteratedTo,
|
---|
82 | valueIteratedFrom: this.prevValueIteratedTo,
|
---|
83 | countAtValueIteratedTo: this.countAtThisValue,
|
---|
84 | countAddedInThisIterationStep:
|
---|
85 | this.totalCountToCurrentIndex - this.totalCountToPrevIndex,
|
---|
86 | totalCountToThisValue: this.totalCountToCurrentIndex,
|
---|
87 | totalValueToThisValue: this.totalValueToCurrentIndex,
|
---|
88 | percentile:
|
---|
89 | (100 * this.totalCountToCurrentIndex) / this.arrayTotalCount,
|
---|
90 | percentileLevelIteratedTo: this.getPercentileIteratedTo(),
|
---|
91 | });
|
---|
92 |
|
---|
93 | this.prevValueIteratedTo = valueIteratedTo;
|
---|
94 | this.totalCountToPrevIndex = this.totalCountToCurrentIndex;
|
---|
95 | this.incrementIterationLevel();
|
---|
96 | if (this.histogram.totalCount !== this.savedHistogramTotalRawCount) {
|
---|
97 | throw new Error("Concurrent Modification Exception");
|
---|
98 | }
|
---|
99 | return this.currentIterationValue;
|
---|
100 | }
|
---|
101 | this.incrementSubBucket();
|
---|
102 | }
|
---|
103 | throw new Error("Index Out Of Bounds Exception");
|
---|
104 | }
|
---|
105 |
|
---|
106 | abstract incrementIterationLevel(): void;
|
---|
107 |
|
---|
108 | /**
|
---|
109 | * @return true if the current position's data should be emitted by the iterator
|
---|
110 | */
|
---|
111 | abstract reachedIterationLevel(): boolean;
|
---|
112 |
|
---|
113 | getPercentileIteratedTo(): number {
|
---|
114 | return (100 * this.totalCountToCurrentIndex) / this.arrayTotalCount;
|
---|
115 | }
|
---|
116 |
|
---|
117 | getPercentileIteratedFrom(): number {
|
---|
118 | return (100 * this.totalCountToPrevIndex) / this.arrayTotalCount;
|
---|
119 | }
|
---|
120 |
|
---|
121 | getValueIteratedTo(): number {
|
---|
122 | return this.histogram.highestEquivalentValue(this.currentValueAtIndex);
|
---|
123 | }
|
---|
124 |
|
---|
125 | private exhaustedSubBuckets(): boolean {
|
---|
126 | return this.currentIndex >= this.histogram.countsArrayLength;
|
---|
127 | }
|
---|
128 |
|
---|
129 | incrementSubBucket() {
|
---|
130 | this.freshSubBucket = true;
|
---|
131 | this.currentIndex++;
|
---|
132 | this.currentValueAtIndex = this.histogram.valueFromIndex(this.currentIndex);
|
---|
133 | this.nextValueAtIndex = this.histogram.valueFromIndex(
|
---|
134 | this.currentIndex + 1
|
---|
135 | );
|
---|
136 | }
|
---|
137 | }
|
---|
138 |
|
---|
139 | export default JsHistogramIterator;
|
---|