source: trip-planner-front/node_modules/hdr-histogram-js/src/packedarray/PackedArray.ts@ 8d391a1

Last change on this file since 8d391a1 was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 7.0 KB
RevLine 
[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 */
8import {
9 PackedArrayContext,
10 MINIMUM_INITIAL_PACKED_ARRAY_CAPACITY
11} from "./PackedArrayContext";
12
13const NUMBER_OF_SETS = 8;
14const { pow, floor } = Math;
15
16/**
17 * A Packed array of signed 64 bit values, and supports {@link #get get()}, {@link #set set()},
18 * {@link #add add()} and {@link #increment increment()} operations on the logical contents of the array.
19 *
20 * An {@link PackedLongArray} Uses {@link PackedArrayContext} to track
21 * the array's logical contents. Contexts may be switched when a context requires resizing
22 * to complete logical array operations (get, set, add, increment). Contexts are
23 * established and used within critical sections in order to facilitate concurrent
24 * implementors.
25 *
26 */
27export class PackedArray {
28 private arrayContext: PackedArrayContext;
29
30 constructor(
31 virtualLength: number,
32 initialPhysicalLength: number = MINIMUM_INITIAL_PACKED_ARRAY_CAPACITY
33 ) {
34 this.arrayContext = new PackedArrayContext(
35 virtualLength,
36 initialPhysicalLength
37 );
38 }
39
40 public setVirtualLength(newVirtualArrayLength: number) {
41 if (newVirtualArrayLength < this.length()) {
42 throw new Error(
43 "Cannot set virtual length, as requested length " +
44 newVirtualArrayLength +
45 " is smaller than the current virtual length " +
46 this.length()
47 );
48 }
49 const currentArrayContext = this.arrayContext;
50 if (
51 currentArrayContext.isPacked &&
52 currentArrayContext.determineTopLevelShiftForVirtualLength(
53 newVirtualArrayLength
54 ) == currentArrayContext.getTopLevelShift()
55 ) {
56 // No changes to the array context contents is needed. Just change the virtual length.
57 currentArrayContext.setVirtualLength(newVirtualArrayLength);
58 return;
59 }
60 this.arrayContext = currentArrayContext.copyAndIncreaseSize(
61 this.getPhysicalLength(),
62 newVirtualArrayLength
63 );
64 }
65
66 /**
67 * Get value at virtual index in the array
68 * @param index the virtual array index
69 * @return the array value at the virtual index given
70 */
71 get(index: number) {
72 let value = 0;
73 for (let byteNum = 0; byteNum < NUMBER_OF_SETS; byteNum++) {
74 let byteValueAtPackedIndex = 0;
75
76 // Deal with unpacked context:
77 if (!this.arrayContext.isPacked) {
78 return this.arrayContext.getAtUnpackedIndex(index);
79 }
80 // Context is packed:
81 const packedIndex = this.arrayContext.getPackedIndex(
82 byteNum,
83 index,
84 false
85 );
86 if (packedIndex < 0) {
87 return value;
88 }
89 byteValueAtPackedIndex =
90 this.arrayContext.getAtByteIndex(packedIndex) * pow(2, byteNum << 3);
91 value += byteValueAtPackedIndex;
92 }
93 return value;
94 }
95
96 /**
97 * Increment value at a virrual index in the array
98 * @param index virtual index of value to increment
99 */
100 public increment(index: number) {
101 this.add(index, 1);
102 }
103
104 private safeGetPackedIndexgetPackedIndex(
105 setNumber: number,
106 virtualIndex: number
107 ) {
108 //do {
109 //try {
110 return this.arrayContext.getPackedIndex(setNumber, virtualIndex, true);
111 /*} catch (ex) {
112 if (ex instanceof ResizeError) {
113 this.arrayContext.resizeArray(ex.newSize);
114 } else {
115 throw ex;
116 }
117 }*/
118 //} while (true);
119 }
120
121 /**
122 * Add to a value at a virtual index in the array
123 * @param index the virtual index of the value to be added to
124 * @param value the value to add
125 */
126 public add(index: number, value: number) {
127 let remainingValueToAdd = value;
128
129 for (
130 let byteNum = 0, byteShift = 0;
131 byteNum < NUMBER_OF_SETS;
132 byteNum++, byteShift += 8
133 ) {
134 // Deal with unpacked context:
135 if (!this.arrayContext.isPacked) {
136 this.arrayContext.addAndGetAtUnpackedIndex(index, value);
137 return;
138 }
139 // Context is packed:
140 const packedIndex = this.safeGetPackedIndexgetPackedIndex(byteNum, index);
141
142 const byteToAdd = remainingValueToAdd & 0xff;
143
144 const afterAddByteValue = this.arrayContext.addAtByteIndex(
145 packedIndex,
146 byteToAdd
147 );
148
149 // Reduce remaining value to add by amount just added:
150 remainingValueToAdd -= byteToAdd;
151
152 remainingValueToAdd = remainingValueToAdd / pow(2, 8);
153 // Account for carry:
154 remainingValueToAdd += floor(afterAddByteValue / pow(2, 8));
155
156 if (remainingValueToAdd == 0) {
157 return; // nothing to add to higher magnitudes
158 }
159 }
160 }
161
162 /**
163 * Set the value at a virtual index in the array
164 * @param index the virtual index of the value to set
165 * @param value the value to set
166 */
167 set(index: number, value: number) {
168 let bytesAlreadySet = 0;
169 let valueForNextLevels = value;
170 for (let byteNum = 0; byteNum < NUMBER_OF_SETS; byteNum++) {
171 // Establish context within: critical section
172
173 // Deal with unpacked context:
174 if (!this.arrayContext.isPacked) {
175 this.arrayContext.setAtUnpackedIndex(index, value);
176 return;
177 }
178 // Context is packed:
179 if (valueForNextLevels == 0) {
180 // Special-case zeros to avoid inflating packed array for no reason
181 const packedIndex = this.arrayContext.getPackedIndex(
182 byteNum,
183 index,
184 false
185 );
186 if (packedIndex < 0) {
187 return; // no need to create entries for zero values if they don't already exist
188 }
189 }
190 // Make sure byte is populated:
191 const packedIndex = this.arrayContext.getPackedIndex(
192 byteNum,
193 index,
194 true
195 );
196
197 // Determine value to write, and prepare for next levels
198 const byteToWrite = valueForNextLevels & 0xff;
199 valueForNextLevels = floor(valueForNextLevels / pow(2, 8));
200
201 if (byteNum < bytesAlreadySet) {
202 // We want to avoid writing to the same byte twice when not doing so for the
203 // entire 64 bit value atomically, as doing so opens a race with e.g. concurrent
204 // adders. So dobn't actually write the byte if has been written before.
205 continue;
206 }
207 this.arrayContext.setAtByteIndex(packedIndex, byteToWrite);
208 bytesAlreadySet++;
209 }
210 }
211
212 /**
213 * Get the current physical length (in longs) of the array's backing storage
214 * @return the current physical length (in longs) of the array's current backing storage
215 */
216 getPhysicalLength() {
217 return this.arrayContext.physicalLength;
218 }
219
220 /**
221 * Get the (virtual) length of the array
222 * @return the (virtual) length of the array
223 */
224 length() {
225 return this.arrayContext.getVirtualLength();
226 }
227
228 /**
229 * Clear the array contents
230 */
231 public clear() {
232 this.arrayContext.clear();
233 }
234
235 public toString() {
236 let output = "PackedArray:\n";
237 output += this.arrayContext.toString();
238 return output;
239 }
240}
Note: See TracBrowser for help on using the repository browser.