) { if (!isHistogram(this)) throw new ERR_INVALID_THIS('Histogram'); return this[kHandle]?.exceeds(); } /** * @readonly * @type {bigint} */ get exceedsBigInt() { if (!isHistogram(this)) throw new ERR_INVALID_THIS('Histogram'); return this[kHandle]?.exceedsBigInt(); } /** * @readonly * @type {number} */ get stddev() { if (!isHistogram(this)) throw new ERR_INVALID_THIS('Histogram'); return this[kHandle]?.stddev(); } /** * @param {number} percentile * @returns {number} */ percentile(percentile) { if (!isHistogram(this)) throw new ERR_INVALID_THIS('Histogram'); validateNumber(percentile, 'percentile'); if (NumberIsNaN(percentile) || percentile <= 0 || percentile > 100) throw new ERR_OUT_OF_RANGE('percentile', '> 0 && <= 100', percentile); return this[kHandle]?.percentile(percentile); } /** * @param {number} percentile * @returns {bigint} */ percentileBigInt(percentile) { if (!isHistogram(this)) throw new ERR_INVALID_THIS('Histogram'); validateNumber(percentile, 'percentile'); if (NumberIsNaN(percentile) || percentile <= 0 || percentile > 100) throw new ERR_OUT_OF_RANGE('percentile', '> 0 && <= 100', percentile); return this[kHandle]?.percentileBigInt(percentile); } /** * @readonly * @type {Map} */ get percentiles() { if (!isHistogram(this)) throw new ERR_INVALID_THIS('Histogram'); this[kMap].clear(); this[kHandle]?.percentiles(this[kMap]); return this[kMap]; } /** * @readonly * @type {Map} */ get percentilesBigInt() { if (!isHistogram(this)) throw new ERR_INVALID_THIS('Histogram'); this[kMap].clear(); this[kHandle]?.percentilesBigInt(this[kMap]); return this[kMap]; } /** * @returns {void} */ reset() { if (!isHistogram(this)) throw new ERR_INVALID_THIS('Histogram'); this[kHandle]?.reset(); } [kClone]() { const handle = this[kHandle]; return { data: { handle }, deserializeInfo: 'internal/histogram:ClonedHistogram', }; } [kDeserialize]({ handle }) { this[kHandle] = handle; } toJSON() { return { count: this.count, min: this.min, max: this.max, mean: this.mean, exceeds: this.exceeds, stddev: this.stddev, percentiles: ObjectFromEntries(MapPrototypeEntries(this.percentiles)), }; } } class RecordableHistogram extends Histogram { constructor(skipThrowSymbol = undefined) { if (skipThrowSymbol !== kSkipThrow) { throw new ERR_ILLEGAL_CONSTRUCTOR(); } super(skipThrowSymbol); } /** * @param {number|bigint} val * @returns {void} */ record(val) { if (this[kRecordable] === undefined) throw new ERR_INVALID_THIS('RecordableHistogram'); if (typeof val === 'bigint') { this[kHandle]?.record(val); return; } validateInteger(val, 'val', 1); this[kHandle]?.record(val); } /** * @returns {void} */ recordDelta() { if (this[kRecordable] === undefined) throw new ERR_INVALID_THIS('RecordableHistogram'); this[kHandle]?.recordDelta(); } /** * @param {RecordableHistogram} other */ add(other) { if (this[kRecordable] === undefined) throw new ERR_INVALID_THIS('RecordableHistogram'); if (other[kRecordable] === undefined) throw new ERR_INVALID_ARG_TYPE('other', 'RecordableHistogram', other); this[kHandle]?.add(other[kHandle]); } [kClone]() { const handle = this[kHandle]; return { data: { handle }, deserializeInfo: 'internal/histogram:ClonedRecordableHistogram', }; } [kDeserialize]({ handle }) { this[kHandle] = handle; } } function ClonedHistogram(handle) { return ReflectConstruct( function() { markTransferMode(this, true, false); this[kHandle] = handle; this[kMap] = new SafeMap(); }, [], Histogram); } ClonedHistogram.prototype[kDeserialize] = () => { }; function ClonedRecordableHistogram(handle) { const histogram = new RecordableHistogram(kSkipThrow); markTransferMode(histogram, true, false); histogram[kRecordable] = true; histogram[kMap] = new SafeMap(); histogram[kHandle] = handle; histogram.constructor = RecordableHistogram; return histogram; } ClonedRecordableHistogram.prototype[kDeserialize] = () => { }; function createRecordableHistogram(handle) { return new ClonedRecordableHistogram(handle); } /** * @param {{ * lowest? : number, * highest? : number, * figures? : number * }} [options] * @returns {RecordableHistogram} */ function createHistogram(options = kEmptyObject) { validateObject(options, 'options'); const { lowest = 1, highest = NumberMAX_SAFE_INTEGER, figures = 3, } = options; if (typeof lowest !== 'bigint') validateInteger(lowest, 'options.lowest', 1, NumberMAX_SAFE_INTEGER); if (typeof highest !== 'bigint') { validateInteger(highest, 'options.highest', 2 * lowest, NumberMAX_SAFE_INTEGER); } else if (highest < 2n * lowest) { throw new ERR_INVALID_ARG_VALUE.RangeError('options.highest', highest); } validateInteger(figures, 'options.figures', 1, 5); return createRecordableHistogram(new _Histogram(lowest, highest, figures)); } module.exports = { Histogram, RecordableHistogram, ClonedHistogram, ClonedRecordableHistogram, isHistogram, kDestroy, kHandle, kMap, createHistogram, };