| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181 |
- "use strict";
- Object.defineProperty(exports, "__esModule", { value: true });
- exports.PackedArray = void 0;
- /*
- * This is a TypeScript 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/
- */
- const PackedArrayContext_1 = require("./PackedArrayContext");
- const NUMBER_OF_SETS = 8;
- const { pow, floor } = Math;
- /**
- * A Packed array of signed 64 bit values, and supports {@link #get get()}, {@link #set set()},
- * {@link #add add()} and {@link #increment increment()} operations on the logical contents of the array.
- *
- * An {@link PackedLongArray} Uses {@link PackedArrayContext} to track
- * the array's logical contents. Contexts may be switched when a context requires resizing
- * to complete logical array operations (get, set, add, increment). Contexts are
- * established and used within critical sections in order to facilitate concurrent
- * implementors.
- *
- */
- class PackedArray {
- constructor(virtualLength, initialPhysicalLength = PackedArrayContext_1.MINIMUM_INITIAL_PACKED_ARRAY_CAPACITY) {
- this.arrayContext = new PackedArrayContext_1.PackedArrayContext(virtualLength, initialPhysicalLength);
- }
- setVirtualLength(newVirtualArrayLength) {
- if (newVirtualArrayLength < this.length()) {
- throw new Error("Cannot set virtual length, as requested length " +
- newVirtualArrayLength +
- " is smaller than the current virtual length " +
- this.length());
- }
- const currentArrayContext = this.arrayContext;
- if (currentArrayContext.isPacked &&
- currentArrayContext.determineTopLevelShiftForVirtualLength(newVirtualArrayLength) == currentArrayContext.getTopLevelShift()) {
- // No changes to the array context contents is needed. Just change the virtual length.
- currentArrayContext.setVirtualLength(newVirtualArrayLength);
- return;
- }
- this.arrayContext = currentArrayContext.copyAndIncreaseSize(this.getPhysicalLength(), newVirtualArrayLength);
- }
- /**
- * Get value at virtual index in the array
- * @param index the virtual array index
- * @return the array value at the virtual index given
- */
- get(index) {
- let value = 0;
- for (let byteNum = 0; byteNum < NUMBER_OF_SETS; byteNum++) {
- let byteValueAtPackedIndex = 0;
- // Deal with unpacked context:
- if (!this.arrayContext.isPacked) {
- return this.arrayContext.getAtUnpackedIndex(index);
- }
- // Context is packed:
- const packedIndex = this.arrayContext.getPackedIndex(byteNum, index, false);
- if (packedIndex < 0) {
- return value;
- }
- byteValueAtPackedIndex =
- this.arrayContext.getAtByteIndex(packedIndex) * pow(2, byteNum << 3);
- value += byteValueAtPackedIndex;
- }
- return value;
- }
- /**
- * Increment value at a virrual index in the array
- * @param index virtual index of value to increment
- */
- increment(index) {
- this.add(index, 1);
- }
- safeGetPackedIndexgetPackedIndex(setNumber, virtualIndex) {
- //do {
- //try {
- return this.arrayContext.getPackedIndex(setNumber, virtualIndex, true);
- /*} catch (ex) {
- if (ex instanceof ResizeError) {
- this.arrayContext.resizeArray(ex.newSize);
- } else {
- throw ex;
- }
- }*/
- //} while (true);
- }
- /**
- * Add to a value at a virtual index in the array
- * @param index the virtual index of the value to be added to
- * @param value the value to add
- */
- add(index, value) {
- let remainingValueToAdd = value;
- for (let byteNum = 0, byteShift = 0; byteNum < NUMBER_OF_SETS; byteNum++, byteShift += 8) {
- // Deal with unpacked context:
- if (!this.arrayContext.isPacked) {
- this.arrayContext.addAndGetAtUnpackedIndex(index, value);
- return;
- }
- // Context is packed:
- const packedIndex = this.safeGetPackedIndexgetPackedIndex(byteNum, index);
- const byteToAdd = remainingValueToAdd & 0xff;
- const afterAddByteValue = this.arrayContext.addAtByteIndex(packedIndex, byteToAdd);
- // Reduce remaining value to add by amount just added:
- remainingValueToAdd -= byteToAdd;
- remainingValueToAdd = remainingValueToAdd / pow(2, 8);
- // Account for carry:
- remainingValueToAdd += floor(afterAddByteValue / pow(2, 8));
- if (remainingValueToAdd == 0) {
- return; // nothing to add to higher magnitudes
- }
- }
- }
- /**
- * Set the value at a virtual index in the array
- * @param index the virtual index of the value to set
- * @param value the value to set
- */
- set(index, value) {
- let bytesAlreadySet = 0;
- let valueForNextLevels = value;
- for (let byteNum = 0; byteNum < NUMBER_OF_SETS; byteNum++) {
- // Establish context within: critical section
- // Deal with unpacked context:
- if (!this.arrayContext.isPacked) {
- this.arrayContext.setAtUnpackedIndex(index, value);
- return;
- }
- // Context is packed:
- if (valueForNextLevels == 0) {
- // Special-case zeros to avoid inflating packed array for no reason
- const packedIndex = this.arrayContext.getPackedIndex(byteNum, index, false);
- if (packedIndex < 0) {
- return; // no need to create entries for zero values if they don't already exist
- }
- }
- // Make sure byte is populated:
- const packedIndex = this.arrayContext.getPackedIndex(byteNum, index, true);
- // Determine value to write, and prepare for next levels
- const byteToWrite = valueForNextLevels & 0xff;
- valueForNextLevels = floor(valueForNextLevels / pow(2, 8));
- if (byteNum < bytesAlreadySet) {
- // We want to avoid writing to the same byte twice when not doing so for the
- // entire 64 bit value atomically, as doing so opens a race with e.g. concurrent
- // adders. So dobn't actually write the byte if has been written before.
- continue;
- }
- this.arrayContext.setAtByteIndex(packedIndex, byteToWrite);
- bytesAlreadySet++;
- }
- }
- /**
- * Get the current physical length (in longs) of the array's backing storage
- * @return the current physical length (in longs) of the array's current backing storage
- */
- getPhysicalLength() {
- return this.arrayContext.physicalLength;
- }
- /**
- * Get the (virtual) length of the array
- * @return the (virtual) length of the array
- */
- length() {
- return this.arrayContext.getVirtualLength();
- }
- /**
- * Clear the array contents
- */
- clear() {
- this.arrayContext.clear();
- }
- toString() {
- let output = "PackedArray:\n";
- output += this.arrayContext.toString();
- return output;
- }
- }
- exports.PackedArray = PackedArray;
- //# sourceMappingURL=PackedArray.js.map
|