@amritk/nish 0.12.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -47,10 +47,10 @@
47
47
  * what the 24-bit index field holds as an index plus one. Node's own `Map` and
48
48
  * `Set` hold one more, 2^24, and throw on the next insert.
49
49
  */
50
- const INDEX_CAP: i32 = 16777215;
50
+ const INDEX_CAP: i32 = 16777215
51
51
 
52
52
  /** The first bucket count. A power of two, as every bucket count is. */
53
- const INITIAL_SLOTS: i32 = 8;
53
+ const INITIAL_SLOTS: i32 = 8
54
54
 
55
55
  /**
56
56
  * The key's hash, never 0: FNV-1a over a string's bytes, murmur3's `fmix32`
@@ -60,11 +60,11 @@ const INITIAL_SLOTS: i32 = 8;
60
60
  * constants are public domain.
61
61
  *
62
62
  * The body is never emitted. Every call is lowered in place, per key type, by
63
- * `self/emit_map.ts`; the constant is what the checker and the whole-program
63
+ * `src/emit-map.ts`; the constant is what the checker and the whole-program
64
64
  * facts see, and the facts of the function that calls it are what decide its
65
65
  * attributes, because every call is inside a probe that reads the table.
66
66
  */
67
- const hashKey = <K>(key: K): u32 => 1;
67
+ const hashKey = <K>(_key: K): u32 => 1
68
68
 
69
69
  /**
70
70
  * JavaScript's key equality, SameValueZero: `===`, except that NaN equals NaN.
@@ -72,19 +72,19 @@ const hashKey = <K>(key: K): u32 => 1;
72
72
  * `icmp` for an integer, a boolean, an enum and a class instance, and for a
73
73
  * float `a == b` or both unordered.
74
74
  */
75
- const sameKey = <K>(a: K, b: K): boolean => a === b;
75
+ const sameKey = <K>(a: K, b: K): boolean => a === b
76
76
 
77
77
  /** The first bucket for `h`: its low bits, folded with the high half. */
78
- const homeBucket = (h: u32, mask: i32): i32 => toI32(h ^ (h >>> 16)) & mask;
78
+ const homeBucket = (h: u32, mask: i32): i32 => toI32(h ^ (h >>> 16)) & mask
79
79
 
80
80
  /** The bucket word for entry `index` of hash `h`. */
81
- const slotWord = (h: u32, index: i32): u32 => ((h >>> 24) << 24) | toU32(index + 1);
81
+ const slotWord = (h: u32, index: i32): u32 => ((h >>> 24) << 24) | toU32(index + 1)
82
82
 
83
83
  /** A probe that found entry `index`, pointed at by `bucket`. Never negative. */
84
- const foundAt = (bucket: i32, index: i32): i64 => (toI64(bucket) << 32) | toI64(index);
84
+ const foundAt = (bucket: i32, index: i32): i64 => (toI64(bucket) << 32) | toI64(index)
85
85
 
86
86
  /** A probe that stopped at the empty `bucket` for hash `h`. Always negative. */
87
- const absentAt = (bucket: i32, h: u32): i64 => toI64(-1) - ((toI64(bucket) << 32) | toI64(h));
87
+ const absentAt = (bucket: i32, h: u32): i64 => toI64(-1) - ((toI64(bucket) << 32) | toI64(h))
88
88
 
89
89
  /**
90
90
  * The one probe, for both classes: linear probing from `h`'s home bucket to
@@ -94,26 +94,32 @@ const absentAt = (bucket: i32, h: u32): i64 => toI64(-1) - ((toI64(bucket) << 32
94
94
  * empty, so the walk ends.
95
95
  */
96
96
  const probeTable = <K>(slots: u32[], mask: i32, hashes: u32[], keys: K[], key: K): i64 => {
97
- const h = hashKey(key);
98
- const fingerprint = h >>> 24;
99
- let bucket = homeBucket(h, mask);
97
+ const h = hashKey(key)
98
+ const fingerprint = h >>> 24
99
+ let bucket = homeBucket(h, mask)
100
100
  // The length is read in the condition rather than once: the key compare is
101
101
  // a call, and a call ends every length fact the bounds proof holds.
102
102
  while (bucket >= 0 && bucket < toI32(slots.length)) {
103
- const word = slots[bucket];
103
+ const word = slots[bucket]
104
104
  if (word === 0) {
105
- return absentAt(bucket, h);
105
+ return absentAt(bucket, h)
106
106
  }
107
107
  if (word >>> 24 === fingerprint) {
108
- const at = toI32(word & 16777215) - 1;
109
- if (at >= 0 && at < toI32(hashes.length) && hashes[at] === h && at < toI32(keys.length) && sameKey(keys[at], key)) {
110
- return foundAt(bucket, at);
108
+ const at = toI32(word & 16777215) - 1
109
+ if (
110
+ at >= 0 &&
111
+ at < toI32(hashes.length) &&
112
+ hashes[at] === h &&
113
+ at < toI32(keys.length) &&
114
+ sameKey(keys[at], key)
115
+ ) {
116
+ return foundAt(bucket, at)
111
117
  }
112
118
  }
113
- bucket = (bucket + 1) & mask;
119
+ bucket = (bucket + 1) & mask
114
120
  }
115
- panic("collections: a probe ran out of buckets");
116
- };
121
+ panic("collections: a probe ran out of buckets")
122
+ }
117
123
 
118
124
  /**
119
125
  * Point the first empty bucket from `h`'s home at entry `index`. A rebuild's
@@ -121,47 +127,47 @@ const probeTable = <K>(slots: u32[], mask: i32, hashes: u32[], keys: K[], key: K
121
127
  * compared, and the stored hash is all it needs.
122
128
  */
123
129
  const fileEntry = (slots: u32[], mask: i32, h: u32, index: i32): void => {
124
- const word = slotWord(h, index);
125
- let bucket = homeBucket(h, mask);
130
+ const word = slotWord(h, index)
131
+ let bucket = homeBucket(h, mask)
126
132
  while (bucket >= 0 && bucket < toI32(slots.length)) {
127
133
  if (slots[bucket] === 0) {
128
- slots[bucket] = word;
129
- return;
134
+ slots[bucket] = word
135
+ return
130
136
  }
131
- bucket = (bucket + 1) & mask;
137
+ bucket = (bucket + 1) & mask
132
138
  }
133
- };
139
+ }
134
140
 
135
141
  /** Slide the live entries of `items` down over the dead ones, in order, and drop the tail. */
136
142
  const compactEntries = <T>(items: T[], hashes: u32[]): void => {
137
- const used = toI32(items.length);
138
- let to: i32 = 0;
143
+ const used = toI32(items.length)
144
+ let to: i32 = 0
139
145
  for (let from: i32 = 0; from < used && from < toI32(hashes.length); from++) {
140
146
  if (hashes[from] !== 0 && to >= 0 && to < used && from < toI32(items.length)) {
141
- items[to] = items[from];
142
- to++;
147
+ items[to] = items[from]
148
+ to++
143
149
  }
144
150
  }
145
151
  while (toI32(items.length) > to) {
146
- items.pop();
152
+ items.pop()
147
153
  }
148
- };
154
+ }
149
155
 
150
156
  /** The stored hashes compacted the same way, last, since the two above read them. */
151
157
  const compactHashes = (hashes: u32[]): void => {
152
- const used = toI32(hashes.length);
153
- let to: i32 = 0;
158
+ const used = toI32(hashes.length)
159
+ let to: i32 = 0
154
160
  for (let from: i32 = 0; from < used; from++) {
155
- const h = hashes[from];
161
+ const h = hashes[from]
156
162
  if (h !== 0 && to >= 0 && to < used) {
157
- hashes[to] = h;
158
- to++;
163
+ hashes[to] = h
164
+ to++
159
165
  }
160
166
  }
161
167
  while (toI32(hashes.length) > to) {
162
- hashes.pop();
168
+ hashes.pop()
163
169
  }
164
- };
170
+ }
165
171
 
166
172
  /**
167
173
  * The bucket table after a rebuild of `live` entries out of `used`. More than
@@ -171,13 +177,13 @@ const compactHashes = (hashes: u32[]): void => {
171
177
  * the table never shrinks.
172
178
  */
173
179
  const rebuiltSlots = (slots: u32[], live: i32, used: i32): u32[] => {
174
- const n = toI32(slots.length);
180
+ const n = toI32(slots.length)
175
181
  if (live * 2 < used) {
176
- clearSlots(slots);
177
- return slots;
182
+ clearSlots(slots)
183
+ return slots
178
184
  }
179
- return new Array<u32>(n * 2);
180
- };
185
+ return new Array<u32>(n * 2)
186
+ }
181
187
 
182
188
  /**
183
189
  * Re-file every live entry from its stored hash. After a compaction none is
@@ -185,14 +191,14 @@ const rebuiltSlots = (slots: u32[], live: i32, used: i32): u32[] => {
185
191
  * keeps its place and takes no bucket, since no probe can find it.
186
192
  */
187
193
  const refile = (slots: u32[], hashes: u32[]): void => {
188
- const mask = toI32(slots.length) - 1;
194
+ const mask = toI32(slots.length) - 1
189
195
  for (let i: i32 = 0; i < toI32(hashes.length); i++) {
190
- const h = hashes[i];
196
+ const h = hashes[i]
191
197
  if (h !== 0) {
192
- fileEntry(slots, mask, h, i);
198
+ fileEntry(slots, mask, h, i)
193
199
  }
194
200
  }
195
- };
201
+ }
196
202
 
197
203
  /**
198
204
  * `delete`'s write through a found probe result: the bucket becomes a
@@ -200,15 +206,15 @@ const refile = (slots: u32[], hashes: u32[]): void => {
200
206
  * until a rebuild compacts them away (§6.1).
201
207
  */
202
208
  const killEntry = (slots: u32[], hashes: u32[], found: i64): void => {
203
- const at = toI32(found);
204
- const bucket = toI32(found >> 32);
209
+ const at = toI32(found)
210
+ const bucket = toI32(found >> 32)
205
211
  if (bucket >= 0 && bucket < toI32(slots.length)) {
206
- slots[bucket] = 16777216;
212
+ slots[bucket] = 16777216
207
213
  }
208
214
  if (at >= 0 && at < toI32(hashes.length)) {
209
- hashes[at] = 0;
215
+ hashes[at] = 0
210
216
  }
211
- };
217
+ }
212
218
 
213
219
  /**
214
220
  * Zero every element in place: the buckets, which emptying a table and
@@ -217,9 +223,9 @@ const killEntry = (slots: u32[], hashes: u32[], found: i64): void => {
217
223
  */
218
224
  const clearSlots = (slots: u32[]): void => {
219
225
  for (let i: i32 = 0; i < toI32(slots.length); i++) {
220
- slots[i] = 0;
226
+ slots[i] = 0
221
227
  }
222
- };
228
+ }
223
229
 
224
230
  /**
225
231
  * The index of the first live entry at `from` or after it, or -1 when there is
@@ -231,18 +237,18 @@ const clearSlots = (slots: u32[]): void => {
231
237
  const nextLive = (hashes: u32[], from: i32): i32 => {
232
238
  for (let i: i32 = from; i >= 0 && i < toI32(hashes.length); i++) {
233
239
  if (hashes[i] !== 0) {
234
- return i;
240
+ return i
235
241
  }
236
242
  }
237
- return -1;
238
- };
243
+ return -1
244
+ }
239
245
 
240
246
  /** Drop every element of `items`, keeping its capacity. */
241
247
  const truncate = <T>(items: T[]): void => {
242
248
  while (toI32(items.length) > 0) {
243
- items.pop();
249
+ items.pop()
244
250
  }
245
- };
251
+ }
246
252
 
247
253
  /**
248
254
  * Point bucket `bucket`, the empty one an absent probe stopped at, at the entry
@@ -251,11 +257,11 @@ const truncate = <T>(items: T[]): void => {
251
257
  */
252
258
  const fileAppended = (slots: u32[], mask: i32, bucket: i32, h: u32, used: i32): void => {
253
259
  if (bucket >= 0 && bucket < toI32(slots.length)) {
254
- slots[bucket] = slotWord(h, used - 1);
260
+ slots[bucket] = slotWord(h, used - 1)
255
261
  } else {
256
- fileEntry(slots, mask, h, used - 1);
262
+ fileEntry(slots, mask, h, used - 1)
257
263
  }
258
- };
264
+ }
259
265
 
260
266
  /**
261
267
  * A key-value table in insertion order, with JavaScript's semantics: keys are
@@ -265,60 +271,60 @@ const fileAppended = (slots: u32[], mask: i32, bucket: i32, h: u32, used: i32):
265
271
  // biome-ignore lint/suspicious/noShadowRestrictedNames: this is the global `Map`, which the compiler loads for a program that names it
266
272
  export class Map<K, V> {
267
273
  /** How many entries are live. The one field a program may read, and it may not write it. */
268
- size: number = 0;
274
+ size: number = 0
269
275
  /** Bucket -> fingerprint and entry index plus one; see the header. */
270
- slots: u32[];
276
+ slots: u32[]
271
277
  /** `slots.length - 1`: the table is a power of two. */
272
- mask: i32 = 7;
278
+ mask: i32 = 7
273
279
  /** Live entries, as an `i32` for the load and compaction arithmetic. */
274
- live: i32 = 0;
275
- entryKeys: K[];
276
- entryValues: V[];
280
+ live: i32 = 0
281
+ entryKeys: K[]
282
+ entryValues: V[]
277
283
  /** The full hash of each entry; 0 once the entry is deleted. */
278
- entryHashes: u32[];
284
+ entryHashes: u32[]
279
285
  /**
280
286
  * How many `for...of` loops are walking the table now. While it is above 0
281
287
  * a rebuild doubles rather than compacts, and `clear` marks entries dead
282
288
  * rather than truncating, so no entry moves under a walk's cursor (§6.2).
283
289
  */
284
- walks: i32 = 0;
290
+ walks: i32 = 0
285
291
 
286
292
  constructor() {
287
- this.slots = new Array<u32>(INITIAL_SLOTS);
288
- this.entryKeys = [];
289
- this.entryValues = [];
290
- this.entryHashes = [];
293
+ this.slots = new Array<u32>(INITIAL_SLOTS)
294
+ this.entryKeys = []
295
+ this.entryValues = []
296
+ this.entryHashes = []
291
297
  }
292
298
 
293
299
  /** The packed probe result for `key`: see `probeTable`, `foundAt` and `absentAt`. */
294
300
  probe(key: K): i64 {
295
- return probeTable(this.slots, this.mask, this.entryHashes, this.entryKeys, key);
301
+ return probeTable(this.slots, this.mask, this.entryHashes, this.entryKeys, key)
296
302
  }
297
303
 
298
304
  has(key: K): boolean {
299
- return this.probe(key) >= 0;
305
+ return this.probe(key) >= 0
300
306
  }
301
307
 
302
308
  /** Set `key` to `value`, in place when it is there and at the end when it is not: one probe. */
303
309
  set(key: K, value: V): Map<K, V> {
304
- const found = this.probe(key);
310
+ const found = this.probe(key)
305
311
  if (found >= 0) {
306
- this.setValueAt(toI32(found), value);
312
+ this.setValueAt(toI32(found), value)
307
313
  } else {
308
- this.insertAt(found, key, value);
314
+ this.insertAt(found, key, value)
309
315
  }
310
- return this;
316
+ return this
311
317
  }
312
318
 
313
319
  delete(key: K): boolean {
314
- const found = this.probe(key);
320
+ const found = this.probe(key)
315
321
  if (found < 0) {
316
- return false;
322
+ return false
317
323
  }
318
- killEntry(this.slots, this.entryHashes, found);
319
- this.live = this.live - 1;
320
- this.size = this.size - 1;
321
- return true;
324
+ killEntry(this.slots, this.entryHashes, found)
325
+ this.live = this.live - 1
326
+ this.size = this.size - 1
327
+ return true
322
328
  }
323
329
 
324
330
  /**
@@ -326,16 +332,16 @@ export class Map<K, V> {
326
332
  * truncated, or, while a loop walks the table, marked dead and kept (§6.1).
327
333
  */
328
334
  clear(): void {
329
- clearSlots(this.slots);
335
+ clearSlots(this.slots)
330
336
  if (this.walks > 0) {
331
- clearSlots(this.entryHashes); // every entry dead, and the count kept
337
+ clearSlots(this.entryHashes) // every entry dead, and the count kept
332
338
  } else {
333
- truncate(this.entryKeys);
334
- truncate(this.entryValues);
335
- truncate(this.entryHashes);
339
+ truncate(this.entryKeys)
340
+ truncate(this.entryValues)
341
+ truncate(this.entryHashes)
336
342
  }
337
- this.live = 0;
338
- this.size = 0;
343
+ this.live = 0
344
+ this.size = 0
339
345
  }
340
346
 
341
347
  /**
@@ -346,66 +352,66 @@ export class Map<K, V> {
346
352
  * that leaves the loop. Two stores a loop, and none per entry.
347
353
  */
348
354
  walkOpen(): void {
349
- this.walks = this.walks + 1;
355
+ this.walks = this.walks + 1
350
356
  }
351
357
 
352
358
  walkNext(from: i32): i32 {
353
- return nextLive(this.entryHashes, from);
359
+ return nextLive(this.entryHashes, from)
354
360
  }
355
361
 
356
362
  walkClose(): void {
357
- this.walks = this.walks - 1;
363
+ this.walks = this.walks - 1
358
364
  }
359
365
 
360
366
  /** The key of entry `index`, which `walkNext` answered. */
361
367
  keyAt(index: i32): K {
362
368
  if (index < 0 || index >= toI32(this.entryKeys.length)) {
363
- panic("Map: no entry at this index");
369
+ panic("Map: no entry at this index")
364
370
  }
365
- return this.entryKeys[index];
371
+ return this.entryKeys[index]
366
372
  }
367
373
 
368
374
  /** The value of the entry a probe found, or a walk reached. */
369
375
  valueAt(index: i32): V {
370
376
  if (index < 0 || index >= toI32(this.entryValues.length)) {
371
- panic("Map: no entry at this index");
377
+ panic("Map: no entry at this index")
372
378
  }
373
- return this.entryValues[index];
379
+ return this.entryValues[index]
374
380
  }
375
381
 
376
382
  /** Overwrite the value of the entry a probe found; it keeps its place. */
377
383
  setValueAt(index: i32, value: V): void {
378
384
  if (index >= 0 && index < toI32(this.entryValues.length)) {
379
- this.entryValues[index] = value;
385
+ this.entryValues[index] = value
380
386
  }
381
387
  }
382
388
 
383
389
  /** Append an entry for `key` at the empty bucket an absent probe result names, reusing its hash. */
384
390
  insertAt(absent: i64, key: K, value: V): void {
385
- const packed = -1 - absent;
386
- let bucket = toI32(packed >> 32);
387
- const h = toU32(packed);
391
+ const packed = -1 - absent
392
+ let bucket = toI32(packed >> 32)
393
+ const h = toU32(packed)
388
394
  if (toI32(this.entryKeys.length) >= INDEX_CAP) {
389
395
  // Dead entries hold the cap: compact them away, then find the bucket
390
396
  // again. A walk defers compaction, so under one the cap is full.
391
397
  if (this.live >= INDEX_CAP || this.walks > 0) {
392
- panic("Map maximum size exceeded");
398
+ panic("Map maximum size exceeded")
393
399
  }
394
- this.rebuild();
395
- bucket = -1;
400
+ this.rebuild()
401
+ bucket = -1
396
402
  }
397
- this.entryKeys.push(storedKey(key));
398
- this.entryValues.push(value);
399
- this.entryHashes.push(h);
400
- this.live = this.live + 1;
401
- this.size = this.size + 1;
403
+ this.entryKeys.push(storedKey(key))
404
+ this.entryValues.push(value)
405
+ this.entryHashes.push(h)
406
+ this.live = this.live + 1
407
+ this.size = this.size + 1
402
408
  // Every entry takes a bucket, live or dead, until a rebuild, which files
403
409
  // the new entry with the rest; otherwise it takes the bucket the probe found.
404
- const used = toI32(this.entryKeys.length);
410
+ const used = toI32(this.entryKeys.length)
405
411
  if (used * 4 > toI32(this.slots.length) * 3) {
406
- this.rebuild();
412
+ this.rebuild()
407
413
  } else {
408
- fileAppended(this.slots, this.mask, bucket, h, used);
414
+ fileAppended(this.slots, this.mask, bucket, h, used)
409
415
  }
410
416
  }
411
417
 
@@ -415,17 +421,17 @@ export class Map<K, V> {
415
421
  * first rebuild after the walk compacts (§6.2).
416
422
  */
417
423
  rebuild(): void {
418
- const used = toI32(this.entryKeys.length);
419
- const walking = this.walks > 0;
420
- const slots = rebuiltSlots(this.slots, walking ? used : this.live, used);
424
+ const used = toI32(this.entryKeys.length)
425
+ const walking = this.walks > 0
426
+ const slots = rebuiltSlots(this.slots, walking ? used : this.live, used)
421
427
  if (!walking && this.live < used) {
422
- compactEntries(this.entryKeys, this.entryHashes);
423
- compactEntries(this.entryValues, this.entryHashes);
424
- compactHashes(this.entryHashes);
428
+ compactEntries(this.entryKeys, this.entryHashes)
429
+ compactEntries(this.entryValues, this.entryHashes)
430
+ compactHashes(this.entryHashes)
425
431
  }
426
- this.slots = slots;
427
- this.mask = toI32(slots.length) - 1;
428
- refile(slots, this.entryHashes);
432
+ this.slots = slots
433
+ this.mask = toI32(slots.length) - 1
434
+ refile(slots, this.entryHashes)
429
435
  }
430
436
 
431
437
  /**
@@ -439,19 +445,19 @@ export class Map<K, V> {
439
445
  */
440
446
  reserveSlots(n: number): void {
441
447
  if (!(n > 0)) {
442
- return;
448
+ return
443
449
  }
444
- const want: i32 = n >= 16777215 ? INDEX_CAP : toI32(n);
445
- const have = toI32(this.slots.length);
446
- let size = have;
450
+ const want: i32 = n >= 16777215 ? INDEX_CAP : toI32(n)
451
+ const have = toI32(this.slots.length)
452
+ let size = have
447
453
  while (want * 4 > size * 3) {
448
- size = size * 2;
454
+ size = size * 2
449
455
  }
450
456
  if (size > have) {
451
- const slots = new Array<u32>(size);
452
- this.slots = slots;
453
- this.mask = size - 1;
454
- refile(slots, this.entryHashes);
457
+ const slots = new Array<u32>(size)
458
+ this.slots = slots
459
+ this.mask = size - 1
460
+ refile(slots, this.entryHashes)
455
461
  }
456
462
  }
457
463
  }
@@ -460,117 +466,117 @@ export class Map<K, V> {
460
466
  // biome-ignore lint/suspicious/noShadowRestrictedNames: this is the global `Set`, which the compiler loads for a program that names it
461
467
  export class Set<T> {
462
468
  /** How many elements are live. The one field a program may read, and it may not write it. */
463
- size: number = 0;
464
- slots: u32[];
465
- mask: i32 = 7;
466
- live: i32 = 0;
467
- entryKeys: T[];
468
- entryHashes: u32[];
469
+ size: number = 0
470
+ slots: u32[]
471
+ mask: i32 = 7
472
+ live: i32 = 0
473
+ entryKeys: T[]
474
+ entryHashes: u32[]
469
475
  /** `Map`'s walk count: how many `for...of` loops are walking the table now. */
470
- walks: i32 = 0;
476
+ walks: i32 = 0
471
477
 
472
478
  constructor() {
473
- this.slots = new Array<u32>(INITIAL_SLOTS);
474
- this.entryKeys = [];
475
- this.entryHashes = [];
479
+ this.slots = new Array<u32>(INITIAL_SLOTS)
480
+ this.entryKeys = []
481
+ this.entryHashes = []
476
482
  }
477
483
 
478
484
  probe(key: T): i64 {
479
- return probeTable(this.slots, this.mask, this.entryHashes, this.entryKeys, key);
485
+ return probeTable(this.slots, this.mask, this.entryHashes, this.entryKeys, key)
480
486
  }
481
487
 
482
488
  has(key: T): boolean {
483
- return this.probe(key) >= 0;
489
+ return this.probe(key) >= 0
484
490
  }
485
491
 
486
492
  /** Add `key` at the end when it is not there already: one probe. */
487
493
  add(key: T): Set<T> {
488
- const found = this.probe(key);
494
+ const found = this.probe(key)
489
495
  if (found < 0) {
490
- this.insertAt(found, key);
496
+ this.insertAt(found, key)
491
497
  }
492
- return this;
498
+ return this
493
499
  }
494
500
 
495
501
  delete(key: T): boolean {
496
- const found = this.probe(key);
502
+ const found = this.probe(key)
497
503
  if (found < 0) {
498
- return false;
504
+ return false
499
505
  }
500
- killEntry(this.slots, this.entryHashes, found);
501
- this.live = this.live - 1;
502
- this.size = this.size - 1;
503
- return true;
506
+ killEntry(this.slots, this.entryHashes, found)
507
+ this.live = this.live - 1
508
+ this.size = this.size - 1
509
+ return true
504
510
  }
505
511
 
506
512
  clear(): void {
507
- clearSlots(this.slots);
513
+ clearSlots(this.slots)
508
514
  if (this.walks > 0) {
509
- clearSlots(this.entryHashes); // every entry dead, and the count kept
515
+ clearSlots(this.entryHashes) // every entry dead, and the count kept
510
516
  } else {
511
- truncate(this.entryKeys);
512
- truncate(this.entryHashes);
517
+ truncate(this.entryKeys)
518
+ truncate(this.entryHashes)
513
519
  }
514
- this.live = 0;
515
- this.size = 0;
520
+ this.live = 0
521
+ this.size = 0
516
522
  }
517
523
 
518
524
  /** `Map`'s walk: `for (const x of s)`, `s.keys()` and `s.values()` are all this one. */
519
525
  walkOpen(): void {
520
- this.walks = this.walks + 1;
526
+ this.walks = this.walks + 1
521
527
  }
522
528
 
523
529
  walkNext(from: i32): i32 {
524
- return nextLive(this.entryHashes, from);
530
+ return nextLive(this.entryHashes, from)
525
531
  }
526
532
 
527
533
  walkClose(): void {
528
- this.walks = this.walks - 1;
534
+ this.walks = this.walks - 1
529
535
  }
530
536
 
531
537
  keyAt(index: i32): T {
532
538
  if (index < 0 || index >= toI32(this.entryKeys.length)) {
533
- panic("Set: no entry at this index");
539
+ panic("Set: no entry at this index")
534
540
  }
535
- return this.entryKeys[index];
541
+ return this.entryKeys[index]
536
542
  }
537
543
 
538
544
  insertAt(absent: i64, key: T): void {
539
- const packed = -1 - absent;
540
- let bucket = toI32(packed >> 32);
541
- const h = toU32(packed);
545
+ const packed = -1 - absent
546
+ let bucket = toI32(packed >> 32)
547
+ const h = toU32(packed)
542
548
  if (toI32(this.entryKeys.length) >= INDEX_CAP) {
543
549
  if (this.live >= INDEX_CAP || this.walks > 0) {
544
- panic("Set maximum size exceeded");
550
+ panic("Set maximum size exceeded")
545
551
  }
546
- this.rebuild();
547
- bucket = -1;
552
+ this.rebuild()
553
+ bucket = -1
548
554
  }
549
- this.entryKeys.push(storedKey(key));
550
- this.entryHashes.push(h);
551
- this.live = this.live + 1;
552
- this.size = this.size + 1;
555
+ this.entryKeys.push(storedKey(key))
556
+ this.entryHashes.push(h)
557
+ this.live = this.live + 1
558
+ this.size = this.size + 1
553
559
  // Every entry takes a bucket, live or dead, until a rebuild, which files
554
560
  // the new entry with the rest; otherwise it takes the bucket the probe found.
555
- const used = toI32(this.entryKeys.length);
561
+ const used = toI32(this.entryKeys.length)
556
562
  if (used * 4 > toI32(this.slots.length) * 3) {
557
- this.rebuild();
563
+ this.rebuild()
558
564
  } else {
559
- fileAppended(this.slots, this.mask, bucket, h, used);
565
+ fileAppended(this.slots, this.mask, bucket, h, used)
560
566
  }
561
567
  }
562
568
 
563
569
  rebuild(): void {
564
- const used = toI32(this.entryKeys.length);
565
- const walking = this.walks > 0;
566
- const slots = rebuiltSlots(this.slots, walking ? used : this.live, used);
570
+ const used = toI32(this.entryKeys.length)
571
+ const walking = this.walks > 0
572
+ const slots = rebuiltSlots(this.slots, walking ? used : this.live, used)
567
573
  if (!walking && this.live < used) {
568
- compactEntries(this.entryKeys, this.entryHashes);
569
- compactHashes(this.entryHashes);
574
+ compactEntries(this.entryKeys, this.entryHashes)
575
+ compactHashes(this.entryHashes)
570
576
  }
571
- this.slots = slots;
572
- this.mask = toI32(slots.length) - 1;
573
- refile(slots, this.entryHashes);
577
+ this.slots = slots
578
+ this.mask = toI32(slots.length) - 1
579
+ refile(slots, this.entryHashes)
574
580
  }
575
581
  }
576
582
 
@@ -582,4 +588,4 @@ export class Set<T> {
582
588
  * key. It sits last in the file so that adding it moved no line a `-g` build
583
589
  * of an earlier function records.
584
590
  */
585
- const storedKey = <K>(key: K): K => key;
591
+ const storedKey = <K>(key: K): K => key