[6a3a178] | 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;
|
---|