@the-w1zard/dx 1.0.12 → 1.0.13

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.
package/src/map.ts ADDED
@@ -0,0 +1,513 @@
1
+ export const rv = <T>(v: UF<T>): T => typeof v === "function" ? (v as () => T)() : v;
2
+ export const sameValue = (a: A, b: A): B => Object.is(a, b) || (a instanceof Date && b instanceof Date && +a === +b);
3
+
4
+
5
+ export class M2I<H = A, T = A> extends Map<H, T> implements M2<H, T> {
6
+ // public g = this.get;
7
+ // public h = this.has;
8
+ // public d = this.delete;
9
+ // public c = this.clear
10
+ public f = this.forEach;// [FOR EACH]
11
+
12
+ #subs?: Set<Sub<H, T>>;
13
+ #hist?: AR<M2Event<H, T>>;
14
+ #histLimit = 0;
15
+ #strict = false;
16
+ #iterating = 0;
17
+ #batching = 0;
18
+ #pending?: M2I<H, M2Event<H, T>>;
19
+ #derived?: M2I<H, Derived<H, T>>;
20
+ #dependents?: M2I<H, Set<H>>;
21
+ #emit(e: M2Event<H, T>): V {
22
+ if (this.#batching > 0) {
23
+ // coalesce: last write per key wins, keep prev from first event
24
+ const pending = this.#pending!.get(e.k);
25
+ this.#pending!.set(
26
+ e.k,
27
+ pending ? { ...e, prev: pending.prev, batch: true } : { ...e, batch: true },
28
+ );
29
+ return;
30
+ }
31
+
32
+ this.#record(e);
33
+ this.#subs?.forEach((sub) => {
34
+ try { sub(e); } catch (err: A) { process.emitWarning(err); }
35
+ });
36
+ }
37
+ #record(e: M2Event<H, T>): V {
38
+ if (!this.#hist) return;
39
+
40
+ this.#hist.push(e);
41
+
42
+ if (this.#hist.length > this.#histLimit) {
43
+ this.#hist.splice(0, this.#hist.length - this.#histLimit);
44
+ }
45
+ }
46
+ #invalidate(k: H): V {
47
+ const deps = this.#dependents?.get(k);
48
+ if (!deps) return;
49
+
50
+ for (const dk of deps) {
51
+ const d = this.#derived?.get(dk);
52
+ if (!d || d.dirty) continue;
53
+
54
+ d.dirty = true;
55
+ this.#emit({ op: "dirty", k: dk, has: d.has });
56
+ }
57
+ }
58
+ #computeDerived(k: H, d: Derived<H, T>): T {
59
+ const vals = d.deps.map((dep) => this.g(dep) as T);
60
+ const next = d.fn(...vals);
61
+
62
+ const had = d.has;
63
+ const prev = d.value;
64
+
65
+ d.value = next;
66
+ d.has = true;
67
+ d.dirty = false;
68
+
69
+ if (!had || !sameValue(prev, next)) {
70
+ this.#emit({
71
+ op: had ? "upd" : "set",
72
+ k,
73
+ v: next,
74
+ prev: prev as T,
75
+ has: true,
76
+ });
77
+ }
78
+
79
+ return next;
80
+ }
81
+ #assertNotIterating(op: S): V {
82
+ if (this.#strict && this.#iterating > 0) {
83
+ throw new Error(`M2.${op}() during iteration. Use filterKV(), collect keys first, or disable $strict().`);
84
+ }
85
+ }
86
+ public [Symbol.iterator](): MapIterator<[H, T]> {return this.entries(); }
87
+ public on(fn: Sub<H, T>): () => V {// [ON]
88
+ (this.#subs ??= new Set()).add(fn);
89
+ return () => this.off(fn);
90
+ }
91
+ public off(fn: Sub<H, T>): V {// [OFF]
92
+ this.#subs?.delete(fn);
93
+ }
94
+ public batch(fn: () => V): this {// [BATCH]
95
+ this.#batching++;
96
+ this.#pending ??= new M2I<H, M2Event<H, T>>();
97
+
98
+ try {
99
+ fn();
100
+ } finally {
101
+ this.#batching--;
102
+
103
+ if (this.#batching === 0) {
104
+ const events = [...this.#pending.values()];
105
+ this.#pending = undefined;
106
+
107
+ for (const e of events) {
108
+ this.#record(e);
109
+ this.#subs?.forEach(sub => sub(e));
110
+ }
111
+ }
112
+ }
113
+
114
+ return this;
115
+ }
116
+ public s(v: UF<T>, k: H): this {// [SET]
117
+ this.#assertNotIterating("s");
118
+
119
+ const next = rv(v);
120
+ const has = this.h(k);
121
+ const prev = has ? this.g(k) : undefined;
122
+
123
+ super.set(k, next);
124
+
125
+ this.#invalidate(k);
126
+ this.#emit({
127
+ op: "set",
128
+ k,
129
+ v: next,
130
+ prev: prev as T,
131
+ has,
132
+ });
133
+
134
+ return this;
135
+ }
136
+ public mutate(k: H, fn: (old: T, has: true) => T): T | UD {// [MUTATE]
137
+ this.#assertNotIterating("mutate");
138
+
139
+ if (!this.h(k)) return undefined;
140
+
141
+ const old = this.g(k) as T;
142
+ const next = fn(old, true);
143
+
144
+ this.s(next, k);
145
+ return next;
146
+ }
147
+ public d(k: H): B {// [DELETE]
148
+ this.#assertNotIterating("delete");
149
+
150
+ if (!this.h(k)) return false;
151
+
152
+ const prev = this.g(k) as T;
153
+ const out = super.delete(k);
154
+
155
+ this.#invalidate(k);
156
+ this.#emit({
157
+ op: "del",
158
+ k,
159
+ prev,
160
+ has: false,
161
+ });
162
+
163
+ return out;
164
+ }
165
+ public c(): V {// [CLEAR]
166
+
167
+ this.#assertNotIterating("clear");
168
+
169
+ const entries = [...this.entries()];
170
+ super.clear();
171
+
172
+ for (const [k, prev] of entries) {
173
+ this.#invalidate(k);
174
+ this.#emit({ op: "del", k, prev, has: false });
175
+ }
176
+ }
177
+ public dv(k: H, deps: AR<H>, fn: (...vals: AR<T>) => T): this {// [DERRIVED]
178
+
179
+ (this.#derived ??= new M2I<H, Derived<H, T>>())
180
+ .set(k, {
181
+ deps,
182
+ fn,
183
+ dirty: true,
184
+ has: false,
185
+ });
186
+
187
+ for (const dep of deps) {
188
+ (this.#dependents ??= new M2I<H, Set<H>>())
189
+ .getOrM(() => new Set(), dep)
190
+ .add(k);
191
+ }
192
+
193
+ return this;
194
+ }
195
+ public dirty(...keys: AR<H>): this {// [DIRTY]
196
+
197
+ for (const k of keys) {
198
+ const d = this.#derived?.get(k);
199
+
200
+ if (d && !d.dirty) {
201
+ d.dirty = true;
202
+ this.#emit({ op: "dirty", k, has: d.has });
203
+ }
204
+ }
205
+
206
+ return this;
207
+ }
208
+ public g(k: H): T | UD {// [GET]
209
+
210
+ const d = this.#derived?.get(k);
211
+
212
+ if (d) {
213
+ if (d.dirty || !d.has) return this.#computeDerived(k, d);
214
+ return d.value;
215
+ }
216
+
217
+ return super.get(k);
218
+ }
219
+ public h(k: H): B {// [HAS]
220
+
221
+ const d = this.#derived?.get(k);
222
+
223
+ if (d) {
224
+ if (d.dirty || !d.has) this.#computeDerived(k, d);
225
+ return true;
226
+ }
227
+
228
+ return super.has(k);
229
+ }
230
+ public $debug(limit: N = 256): this {// [$DEBUG]
231
+ this.#hist ??= [];
232
+ this.#histLimit = limit;
233
+ return this;
234
+ }
235
+ public $strict(): this {// [$STRICT]
236
+ this.#strict = true;
237
+ return this;
238
+ }
239
+ public $history(): AR<M2Event<H, T>> {// [$HISTORY]
240
+ return this.#hist ? [...this.#hist] : [];
241
+ }
242
+ public $why(k: H): M2Event<H, T> | UD {// [$WHY]
243
+ if (!this.#hist) return undefined;
244
+
245
+ for (let i = this.#hist.length - 1; i >= 0; i--) {
246
+ if (Object.is(this.#hist[i].k, k)) return this.#hist[i];
247
+ }
248
+
249
+ return undefined;
250
+ }
251
+ public $diff(other: M2I<H, T>) {// [$DIFF]
252
+ const add: AR<[H, T]> = [];
253
+ const del: AR<H> = [];
254
+ const chg: AR<[H, T, T]> = [];
255
+
256
+ for (const [k, v] of this) {
257
+ if (!other.has(k)) {
258
+ add.push([k, v]);
259
+ } else if (!Object.is(other.get(k), v)) {
260
+ chg.push([k, v, other.get(k) as T]);
261
+ }
262
+ }
263
+
264
+ for (const k of other.keys()) {
265
+ if (!this.has(k)) del.push(k);
266
+ }
267
+
268
+ return { add, del, chg };
269
+ }
270
+ public *entries(): MapIterator<[H, T]> {// [*ENTRIES]
271
+ this.#iterating++;
272
+
273
+ try {
274
+ for (const entry of super.entries()) yield entry;
275
+ } finally {
276
+ this.#iterating--;
277
+ }
278
+ }
279
+ public *keys(): MapIterator<H> {// [*KEYS]
280
+ this.#iterating++;
281
+
282
+ try {
283
+ for (const k of super.keys()) yield k;
284
+ } finally {
285
+ this.#iterating--;
286
+ }
287
+ }
288
+ public *values(): MapIterator<T> {// [*VALUES]
289
+ this.#iterating++;
290
+
291
+ try {
292
+ for (const v of super.values()) yield v;
293
+ } finally {
294
+ this.#iterating--;
295
+ }
296
+ }
297
+ public swap(value: UF<T>, key: H): T | UD {// [SWAP]
298
+ const next = rv(value);
299
+ const previous = this.has(key) ? this.get(key) : next;
300
+ this.s(next, key);
301
+ return previous as T | UD;
302
+ }
303
+ public take(k: H): T | UD {// [TAKE]
304
+ const value = this.g(k);
305
+ this.d(k);
306
+ return value;
307
+ }
308
+ public peek(k: H): T | false {// [PEEK]
309
+ return this.h(k) ? (this.g(k) as T) : false;
310
+ }
311
+ public getOrI(value:UF<T>, k: H): T {// [GETORI]
312
+ if (this.h(k)) return this.g(k) as T;
313
+ const next = rv(value);
314
+ this.s(next, k);
315
+ return next;
316
+ }
317
+ public getOrM(make: () => T, k: H): T {// [GETORM]
318
+ if (this.h(k)) return this.g(k) as T;
319
+ const value = make();
320
+ this.s(value, k);
321
+ return value;
322
+ }
323
+ public update(k: H, fn: (old: T, has: B) => T, initial?: UF<T>): T {// [UPDATE]
324
+ const has = this.h(k);
325
+
326
+ const old = has
327
+ ? (this.g(k) as T)
328
+ : initial === undefined
329
+ ? undefined as T
330
+ : rv(initial);
331
+
332
+ const next = rv(fn(old, has));
333
+
334
+ this.s(next, k);
335
+ return next;
336
+ }
337
+ public setIfAbsent(value: UF<T>, k: H): B {// [SETIFABSENT]
338
+ if (this.h(k)) return false;
339
+ const next = rv(value);
340
+ this.s(next, k);
341
+ return true;
342
+ }
343
+ public setIfPresent(value: UF<T>, k: H): B {// [SETIFPRESENT]
344
+ if (!this.h(k)) return false;
345
+ const next = rv(value);
346
+ this.s(next, k);
347
+ return true;
348
+ }
349
+ public replace(value: UF<T>, k: H): B {// [REPLACE]
350
+ const next = rv(value);
351
+ return this.setIfPresent(next, k);
352
+ }
353
+ public inc(key: H, by: N = 1): N {// [INC]
354
+ return this.update(key, (old) => (((old ?? 0) as N) + by) as unknown as T, 0 as unknown as T) as N;
355
+ }
356
+ public touch(k: H): B {// [SWTOUCHAP]
357
+ return this.setIfAbsent(undefined as unknown as T, k);
358
+ }
359
+ public mapValues<G>(fn: (v: T, k: H) => G): M2<H, G> {// [MAPVALUES]
360
+ const out = new M2I<H, G>();
361
+ for (const [k, v] of this) out.s(fn(v, k), k);
362
+ return out;
363
+ }
364
+ public mapKeys<G>(fn: (v: T, k: H) => G): M2<G, T> {// [MAPKEYS]
365
+ const out = new M2I<G, T>();
366
+ for (const [k, v] of this) out.s(v, fn(v, k));
367
+ return out;
368
+ }
369
+ public filterKV(pred: (v: T, k: H) => B): this {// [FILTERKV]
370
+ for (const [k, v] of this) {
371
+ if (!pred(v, k)) this.d(k);
372
+ }
373
+ return this;
374
+ }
375
+ public filterKeys(pred: (v: T, k: H) => B): this {// [FILTERKEYS]
376
+ return this.filterKV(pred);
377
+ }
378
+ public partition(pred: (v: T, k: H) => B): [M2<H, T>, M2<H, T>] {// [PARTITION]
379
+ const yes = new M2I<H, T>();
380
+ const no = new M2I<H, T>();
381
+
382
+ for (const [k, v] of this) {
383
+ (pred(v, k) ? yes : no).s(v, k);
384
+ }
385
+
386
+ return [yes, no];
387
+ }
388
+ public find(pred: (v: T, k: H) => B): [H, T] | UD {// [FIND]
389
+ for (const [k, v] of this) {
390
+ if (pred(v, k)) return [k, v];
391
+ }
392
+ return undefined;
393
+ }
394
+ public findKey(pred: (v: T, k: H) => B): H | UD {// [FINDKEY]
395
+ for (const [k, v] of this) {
396
+ if (pred(v, k)) return k;
397
+ }
398
+ return undefined;
399
+ }
400
+ public findValue(pred: (v: T, k: H) => B): T | UD {// [FINDVALUE]
401
+ for (const [k, v] of this) {
402
+ if (pred(v, k)) return v;
403
+ }
404
+ return undefined;
405
+ }
406
+ public some(pred: (v: T, k: H) => B): B {// [SOME]
407
+ for (const [k, v] of this) {
408
+ if (pred(v, k)) return true;
409
+ }
410
+ return false;
411
+ }
412
+ public every(pred: (v: T, k: H) => B): B {// [EVERY]
413
+ for (const [k, v] of this) {
414
+ if (!pred(v, k)) return false;
415
+ }
416
+ return true;
417
+ }
418
+ public reduce<G>(fn: (acc: G, v: T, k: H) => G, initial: G): G {// [REDUCE]
419
+ let acc = initial;
420
+ for (const [k, v] of this) acc = fn(acc, v, k);
421
+ return acc;
422
+ }
423
+ public forEachKV(fn: (v: T, k: H, map: this) => void): void {// [FOREACH]
424
+ for (const [k, v] of this) fn(v, k, this);
425
+ }
426
+ public invert(): M2<T, H> {// [INVERT]
427
+ const out = new M2I<T, H>();
428
+ for (const [k, v] of this) out.s(k, v);
429
+ return out;
430
+ }
431
+ public unique<G>(fn?: (v: T, k: H) => G): M2<G, T> {// [UNIQUE]
432
+ const out = new M2I<G, T>();
433
+ for (const [k, v] of this) {
434
+ const key = (fn ? fn(v, k) : v) as unknown as G;
435
+ if (!out.h(key)) out.s(v, key);
436
+ }
437
+ return out;
438
+ }
439
+ public pick(keys: Iterable<H>): M2<H, T> {// [PICK]
440
+ const out = new M2I<H, T>();
441
+ for (const k of keys) {
442
+ if (this.h(k)) out.s(this.g(k) as T, k);
443
+ }
444
+ return out;
445
+ }
446
+ public omit(keys: Iterable<H>): M2<H, T> {// [EMIT]
447
+ const omitted = new Set(keys);
448
+ const out = new M2I<H, T>();
449
+ for (const [k, v] of this) {
450
+ if (!omitted.has(k)) out.s(v, k);
451
+ }
452
+ return out;
453
+ }
454
+ public merge(other: Iterable<readonly [H, T]>): this {// [MERGE]
455
+ for (const [k, v] of other){
456
+ const n = rv(v);
457
+ this.s(n, k);
458
+ }
459
+ return this;
460
+ }
461
+ public clearAndSet(entries: Iterable<readonly [H, T]>): this {// [CLEARANDSET]
462
+ return this.batch(() => {
463
+ this.clear();
464
+
465
+ for (const [k, v] of entries) {
466
+ const n = rv(v);
467
+ this.s(n, k);
468
+ }
469
+ });
470
+ }
471
+ public toObject(): OB<T> {// [TOPOBJECT]
472
+ const out = {} as OB<T>;
473
+ for (const [k, v] of this) out[k as S] = v;
474
+ return out;
475
+ }
476
+ public toValues(): A2I<T> { return A2.from(this.values()); }// [TOVALUES]
477
+ public toKeys(): A2I<H> { return A2.from(this.keys()); }// [TOKEYS]
478
+ public toArray(): A2I<[H, T]> { return A2.from(this.entries()); }// [TOARRAY]
479
+ public group<G>(fn: (v: T, k: H) => G): M2<G, A2<T>> {// [GROUP]
480
+ const out = new M2I<G, A2<T>>();
481
+ for (const [k, v] of this) out.getOrM(() => new A2<T>(), fn(v, k)).push(v);
482
+ return out;
483
+ }
484
+ public clone(): this {// [CLONE]
485
+ return new M2I(this) as this;
486
+ }
487
+ public equals(other: M2I<H, T>): B {// [EQUALS]
488
+ if (other === this) return true;
489
+ if (this.size !== other.size) return false;
490
+
491
+ for (const [k, v] of this) {
492
+ if (!other.has(k) || !sameValue(other.get(k), v)) return false;
493
+ }
494
+
495
+ return true;
496
+ }
497
+ static fromObject<X extends Record<S, A>>(obj: X): M2I<S, X[keyof X]> {// [FROMOBBJ]
498
+ return new M2I(Object.entries(obj) as AR<[S, X[keyof X]]>);
499
+ }
500
+ static fromEntries<H, T>(entries: I<readonly [H, T]>): M2I<H, T> {// [FROMENTIRES]
501
+ return new M2I(entries);
502
+ }
503
+ static from<H, T>(map: RM<H, T>): M2I<H, T> {// [FROM]
504
+ return new M2I(map);
505
+ }
506
+ }
507
+
508
+ globalThis.M2 = M2I;
509
+
510
+ /* ====================================================================================================
511
+
512
+ ============================================================= ⇦✦──⇦✦──✦──✦──← 'pew pew' 🧙 [STORE] */
513
+
package/src/map_bin.ts ADDED
@@ -0,0 +1,179 @@
1
+
2
+
3
+
4
+ type Key = number | string | symbol | object;
5
+ type Simd = Float64Array | Float32Array | number[];
6
+
7
+ export class M2BINI<K = N, V = N> {
8
+ #vals: F64;
9
+ #pidToSlot: I32;
10
+ #slotToPid: I32;
11
+ #size = 0;
12
+ #odd: M<Key, V> | null = null;
13
+
14
+ constructor(capacity = 1024) {
15
+ const cap = Math.max(1, capacity | 0);
16
+ this.#pidToSlot = new Int32Array(cap).fill(-1);
17
+ this.#slotToPid = new Int32Array(cap).fill(-1);
18
+ this.#vals = new Float64Array(cap);
19
+ }
20
+
21
+ get size(): number {
22
+ return this.#size + (this.#odd === null ? 0 : this.#odd.size);
23
+ }
24
+ get capacity(): number {
25
+ return this.#vals.length;
26
+ }
27
+ /** live backing buffer: floating-point value of slot i is buffer[i] */
28
+ get buffer(): Float64Array {
29
+ return this.#vals;
30
+ }
31
+
32
+ // ---- Map API ----------------------------------------------------------
33
+ get(k: K): V | undefined {
34
+ const p = this.#pidToSlot;
35
+ if (typeof k === "number" && k >= 0 && k < p.length) {
36
+ const i = p[k];
37
+ return (i < 0 ? undefined : this.#vals[i]) as V | undefined;
38
+ }
39
+ return this.#odd === null ? undefined : this.#odd.get(k as Key);
40
+ }
41
+
42
+ has(k: K): boolean {
43
+ if (typeof k === "number" && k >= 0) return k < this.#pidToSlot.length && this.#pidToSlot[k] !== -1;
44
+ return this.#odd !== null && this.#odd.has(k as Key);
45
+ }
46
+
47
+ set(k: K, v: V): this {
48
+ if (typeof v === "number" && typeof k === "number" && k >= 0) {
49
+ this.#vals[this.#open(k)] = v;
50
+ return this;
51
+ }
52
+ (this.#odd ??= new Map()).set(k as Key, v);
53
+ return this;
54
+ }
55
+
56
+ delete(k: K): boolean {
57
+ if (typeof k === "number" && k >= 0) {
58
+ if (k >= this.#pidToSlot.length) return false;
59
+ const i = this.#pidToSlot[k];
60
+ if (i < 0) return false;
61
+ const last = --this.#size;
62
+ const lastPid = this.#slotToPid[last];
63
+ if (i !== last) {
64
+ this.#vals[i] = this.#vals[last];
65
+ this.#slotToPid[i] = lastPid;
66
+ this.#pidToSlot[lastPid] = i;
67
+ }
68
+ this.#pidToSlot[k] = -1;
69
+ this.#slotToPid[last] = -1;
70
+ return true;
71
+ }
72
+ return this.#odd !== null && this.#odd.delete(k as Key);
73
+ }
74
+
75
+ clear(): void {
76
+ this.#pidToSlot.fill(-1);
77
+ this.#slotToPid.fill(-1);
78
+ this.#size = 0;
79
+ this.#odd?.clear();
80
+ }
81
+
82
+ *keys(): MapIterator<K> {
83
+ for (let i = 0; i < this.#size; i++) yield this.#slotToPid[i] as K;
84
+ if (this.#odd !== null) yield* this.#odd.keys() as MapIterator<K>;
85
+ }
86
+ *values(): MapIterator<V> {
87
+ for (let i = 0; i < this.#size; i++) yield this.#vals[i] as V;
88
+ if (this.#odd !== null) yield* this.#odd.values();
89
+ }
90
+ *entries(): MapIterator<[K, V]> {
91
+ for (let i = 0; i < this.#size; i++) yield [this.#slotToPid[i] as K, this.#vals[i] as V];
92
+ if (this.#odd !== null) yield* this.#odd.entries() as MapIterator<[K, V]>;
93
+ }
94
+ [Symbol.iterator](): MapIterator<[K, V]> {
95
+ return this.entries();
96
+ }
97
+
98
+ forEach(fn: (v: V, k: K, m: Map<K, V>) => void, thisArg?: unknown): void {
99
+ for (let i = 0; i < this.#size; i++) fn.call(thisArg, this.#vals[i] as V, this.#slotToPid[i] as K, this);
100
+ this.#odd?.forEach((v, k) => fn.call(thisArg, v, k as K, this));
101
+ }
102
+
103
+ // ---- binary lane: no Map ceremony, no boxing ---------------------------
104
+ /** read by pid */
105
+ g(pid: number): V | undefined {
106
+ const i = this.#pidToSlot[pid];
107
+ return (i < 0 ? undefined : this.#vals[i]) as V | undefined;
108
+ }
109
+ /** write by pid */
110
+ s(v: number, pid: number): this {
111
+ this.#vals[this.#open(pid)] = v;
112
+ return this;
113
+ }
114
+ /** read with fallback — the accumulator primitive */
115
+ getOr(pid: number, dflt = 0): number {
116
+ const i = this.#pidToSlot[pid];
117
+ return i < 0 ? dflt : this.#vals[i];
118
+ }
119
+ /** pid += delta, returns the new value */
120
+ add(pid: number, delta: number): number {
121
+ const i = this.#open(pid);
122
+ return (this.#vals[i] += delta);
123
+ }
124
+ in(pid: number): boolean {
125
+ return this.#pidToSlot[pid] !== -1;
126
+ }
127
+ d(pid: number): boolean {
128
+ return this.delete(pid as unknown as K);
129
+ }
130
+ /** walk (pid, slot) without allocating an iterator */
131
+ forEachRaw(fn: (pid: number, slot: number) => void): void {
132
+ for (let i = 0; i < this.#size; i++) fn(this.#slotToPid[i], i);
133
+ }
134
+ /** values for a list of pids, NaN where absent */
135
+ gather(pids: ArrayLike<number>, out = new Float64Array(pids.length)): Float64Array {
136
+ for (let i = 0; i < pids.length; i++) {
137
+ const s = this.#pidToSlot[pids[i]];
138
+ out[i] = s < 0 ? NaN : this.#vals[s];
139
+ }
140
+ return out;
141
+ }
142
+
143
+ #open(pid: number): number {
144
+ let p = this.#pidToSlot;
145
+ if (pid >= p.length) {
146
+ this.#grow(pid);
147
+ p = this.#pidToSlot;
148
+ }
149
+ let i = p[pid];
150
+ if (i < 0) {
151
+ if (this.#size === p.length) {
152
+ this.#grow(this.#size);
153
+ p = this.#pidToSlot;
154
+ }
155
+ i = this.#size++;
156
+ p[pid] = i;
157
+ this.#slotToPid[i] = pid;
158
+ }
159
+ return i;
160
+ }
161
+ #grow(need: number): void {
162
+ let cap = this.#pidToSlot.length;
163
+ while (cap <= need) cap *= 2;
164
+ const p2s = new Int32Array(cap).fill(-1);
165
+ p2s.set(this.#pidToSlot);
166
+ this.#pidToSlot = p2s;
167
+ const s2p = new Int32Array(cap).fill(-1);
168
+ s2p.set(this.#slotToPid);
169
+ this.#slotToPid = s2p;
170
+ const v = new Float64Array(cap);
171
+ v.set(this.#vals);
172
+ this.#vals = v;
173
+ }
174
+ }
175
+
176
+ export interface M2BIN<K, V> extends M2BINI {}
177
+ Object.setPrototypeOf(M2BINI.prototype, Map.prototype);
178
+
179
+ globalThis.M2BIN = M2BINI;