@cloudbitmaps/roaring 0.23.0 → 0.24.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.
- package/NOTICE +2 -2
- package/PRIVACY.md +1 -1
- package/README.md +16 -8
- package/dist/bin/export-segments.js +1611 -248
- package/dist/bin/export-segments.js.map +4 -4
- package/dist/index.d.ts +4 -3
- package/dist/index.js +1609 -221
- package/dist/index.js.map +4 -4
- package/dist/roaring-codec.d.ts +22 -92
- package/package.json +2 -4
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
MAX_LEASE_MS,
|
|
27
27
|
NotFoundError,
|
|
28
28
|
UnsupportedError as UnsupportedError2,
|
|
29
|
-
ValidationError as
|
|
29
|
+
ValidationError as ValidationError6,
|
|
30
30
|
errorKind,
|
|
31
31
|
WriteConflictError,
|
|
32
32
|
checkBudget,
|
|
@@ -130,8 +130,10 @@ function refuseReservedNamespace(namespace) {
|
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
// src/roaring-codec.ts
|
|
133
|
-
import
|
|
134
|
-
|
|
133
|
+
import { ValidationError as ValidationError3, decodeSerialized } from "@cloudbitmaps/core";
|
|
134
|
+
|
|
135
|
+
// src/ts-roaring/bitmap.ts
|
|
136
|
+
import { IntegrityError as IntegrityError3, ValidationError as ValidationError2 } from "@cloudbitmaps/core";
|
|
135
137
|
|
|
136
138
|
// src/portable/layout.ts
|
|
137
139
|
import { IntegrityError } from "@cloudbitmaps/core";
|
|
@@ -149,45 +151,10 @@ function overrun(bytes, offset, length, what) {
|
|
|
149
151
|
`portable roaring: ${what} needs bytes [${offset}, ${offset + length}) of a ${bytes.byteLength}-byte buffer`
|
|
150
152
|
);
|
|
151
153
|
}
|
|
152
|
-
function
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
var SINGLE_RUN_HEADER_BYTES = 9;
|
|
157
|
-
function* containerPayloads(bytes) {
|
|
158
|
-
if (bytes.byteLength === 0) return;
|
|
159
|
-
const { view, count, runFlagsAt, descriptiveAt, bodiesAt } = header(bytes);
|
|
160
|
-
let pos = bodiesAt;
|
|
161
|
-
let previousKey = -1;
|
|
162
|
-
for (let i = 0; i < count; i++) {
|
|
163
|
-
const key = view.getUint16(descriptiveAt + i * 4, true);
|
|
164
|
-
if (key <= previousKey) {
|
|
165
|
-
throw new IntegrityError(
|
|
166
|
-
`portable roaring: container keys are not strictly ascending (${previousKey} then ${key} at index ${i})`
|
|
167
|
-
);
|
|
168
|
-
}
|
|
169
|
-
previousKey = key;
|
|
170
|
-
const cardinality = view.getUint16(descriptiveAt + i * 4 + 2, true) + 1;
|
|
171
|
-
const isRun = runFlagsAt >= 0 && (bytes[runFlagsAt + (i >>> 3)] & 1 << (i & 7)) !== 0;
|
|
172
|
-
const kind = isRun ? RUN : cardinality > ARRAY_MAX_CARDINALITY ? BITMAP : ARRAY;
|
|
173
|
-
const size = checkContainer(bytes, view, pos, kind, cardinality, i);
|
|
174
|
-
const headerBytes = isRun ? SINGLE_RUN_HEADER_BYTES : SINGLE_HEADER_BYTES;
|
|
175
|
-
const payload = new Uint8Array(headerBytes + size);
|
|
176
|
-
const out = new DataView(payload.buffer);
|
|
177
|
-
if (isRun) {
|
|
178
|
-
out.setUint32(0, SERIAL_COOKIE, true);
|
|
179
|
-
payload[4] = 1;
|
|
180
|
-
out.setUint16(7, cardinality - 1, true);
|
|
181
|
-
} else {
|
|
182
|
-
out.setUint32(0, SERIAL_COOKIE_NO_RUNCONTAINER, true);
|
|
183
|
-
out.setUint32(4, 1, true);
|
|
184
|
-
out.setUint16(10, cardinality - 1, true);
|
|
185
|
-
out.setUint32(12, SINGLE_HEADER_BYTES, true);
|
|
186
|
-
}
|
|
187
|
-
payload.set(bytes.subarray(pos, pos + size), headerBytes);
|
|
188
|
-
pos += size;
|
|
189
|
-
yield { chunkKey: key, payload, cardinality };
|
|
190
|
-
}
|
|
154
|
+
function parsePortableLayout(bytes) {
|
|
155
|
+
const containers = [];
|
|
156
|
+
walk(bytes, containers);
|
|
157
|
+
return containers;
|
|
191
158
|
}
|
|
192
159
|
function header(bytes) {
|
|
193
160
|
const length = bytes.byteLength;
|
|
@@ -338,184 +305,1579 @@ function popcount(view, at) {
|
|
|
338
305
|
return bits;
|
|
339
306
|
}
|
|
340
307
|
|
|
341
|
-
// src/roaring
|
|
342
|
-
var
|
|
343
|
-
var
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
308
|
+
// src/ts-roaring/containers.ts
|
|
309
|
+
var ARRAY2 = 0;
|
|
310
|
+
var BITSET = 1;
|
|
311
|
+
var RUN2 = 2;
|
|
312
|
+
var WORDS = 2048;
|
|
313
|
+
var BITSET_BYTES = 8192;
|
|
314
|
+
var GALLOP_SKEW = 16;
|
|
315
|
+
var LITTLE_ENDIAN = new Uint8Array(Uint16Array.of(1).buffer)[0] === 1;
|
|
316
|
+
var Container = class {
|
|
317
|
+
constructor(kind, data, off, len, card, shared) {
|
|
318
|
+
this.kind = kind;
|
|
319
|
+
this.data = data;
|
|
320
|
+
this.off = off;
|
|
321
|
+
this.len = len;
|
|
322
|
+
this.card = card;
|
|
323
|
+
this.shared = shared;
|
|
324
|
+
}
|
|
325
|
+
kind;
|
|
326
|
+
data;
|
|
327
|
+
off;
|
|
328
|
+
len;
|
|
329
|
+
card;
|
|
330
|
+
shared;
|
|
331
|
+
};
|
|
332
|
+
function lows16(c) {
|
|
333
|
+
return c.data;
|
|
334
|
+
}
|
|
335
|
+
function words32(c) {
|
|
336
|
+
return c.data;
|
|
337
|
+
}
|
|
338
|
+
function arrayContainer(values, card) {
|
|
339
|
+
return new Container(ARRAY2, values, 0, card, card, false);
|
|
340
|
+
}
|
|
341
|
+
function bitsetContainer(words, card) {
|
|
342
|
+
return new Container(BITSET, words, 0, 0, card, false);
|
|
343
|
+
}
|
|
344
|
+
function runContainer(pairs, runs, card) {
|
|
345
|
+
return new Container(RUN2, pairs, 0, runs, card, false);
|
|
346
|
+
}
|
|
347
|
+
var valueScratch = new Uint16Array(8192);
|
|
348
|
+
var pairScratch = new Uint16Array(8192);
|
|
349
|
+
var SCRATCH_KEEP = 65536;
|
|
350
|
+
function values16(n) {
|
|
351
|
+
if (valueScratch.length >= n) return valueScratch;
|
|
352
|
+
if (n > SCRATCH_KEEP) return new Uint16Array(n);
|
|
353
|
+
valueScratch = new Uint16Array(Math.max(n, Math.min(2 * valueScratch.length, SCRATCH_KEEP)));
|
|
354
|
+
return valueScratch;
|
|
355
|
+
}
|
|
356
|
+
function pairs16(n) {
|
|
357
|
+
if (pairScratch.length >= n) return pairScratch;
|
|
358
|
+
if (n > SCRATCH_KEEP) return new Uint16Array(n);
|
|
359
|
+
pairScratch = new Uint16Array(Math.max(n, Math.min(2 * pairScratch.length, SCRATCH_KEEP)));
|
|
360
|
+
return pairScratch;
|
|
361
|
+
}
|
|
362
|
+
function arrayOfScratch(scratch, n) {
|
|
363
|
+
return n === 0 ? null : arrayContainer(scratch.slice(0, n), n);
|
|
364
|
+
}
|
|
365
|
+
function popcount32(word) {
|
|
366
|
+
let w = word - (word >>> 1 & 1431655765);
|
|
367
|
+
w = (w & 858993459) + (w >>> 2 & 858993459);
|
|
368
|
+
return Math.imul(w + (w >>> 4) & 252645135, 16843009) >>> 24;
|
|
369
|
+
}
|
|
370
|
+
function popcountWords(d) {
|
|
371
|
+
let total = 0;
|
|
372
|
+
let ones = 0;
|
|
373
|
+
let twos = 0;
|
|
374
|
+
let fours = 0;
|
|
375
|
+
let eights = 0;
|
|
376
|
+
for (let i = 0; i < WORDS; i += 16) {
|
|
377
|
+
let u;
|
|
378
|
+
let twosA;
|
|
379
|
+
let twosB;
|
|
380
|
+
let foursA;
|
|
381
|
+
let foursB;
|
|
382
|
+
let x = d[i];
|
|
383
|
+
let y = d[i + 1];
|
|
384
|
+
u = ones ^ x;
|
|
385
|
+
twosA = ones & x | u & y;
|
|
386
|
+
ones = u ^ y;
|
|
387
|
+
x = d[i + 2];
|
|
388
|
+
y = d[i + 3];
|
|
389
|
+
u = ones ^ x;
|
|
390
|
+
twosB = ones & x | u & y;
|
|
391
|
+
ones = u ^ y;
|
|
392
|
+
u = twos ^ twosA;
|
|
393
|
+
foursA = twos & twosA | u & twosB;
|
|
394
|
+
twos = u ^ twosB;
|
|
395
|
+
x = d[i + 4];
|
|
396
|
+
y = d[i + 5];
|
|
397
|
+
u = ones ^ x;
|
|
398
|
+
twosA = ones & x | u & y;
|
|
399
|
+
ones = u ^ y;
|
|
400
|
+
x = d[i + 6];
|
|
401
|
+
y = d[i + 7];
|
|
402
|
+
u = ones ^ x;
|
|
403
|
+
twosB = ones & x | u & y;
|
|
404
|
+
ones = u ^ y;
|
|
405
|
+
u = twos ^ twosA;
|
|
406
|
+
foursB = twos & twosA | u & twosB;
|
|
407
|
+
twos = u ^ twosB;
|
|
408
|
+
u = fours ^ foursA;
|
|
409
|
+
const eightsA = fours & foursA | u & foursB;
|
|
410
|
+
fours = u ^ foursB;
|
|
411
|
+
x = d[i + 8];
|
|
412
|
+
y = d[i + 9];
|
|
413
|
+
u = ones ^ x;
|
|
414
|
+
twosA = ones & x | u & y;
|
|
415
|
+
ones = u ^ y;
|
|
416
|
+
x = d[i + 10];
|
|
417
|
+
y = d[i + 11];
|
|
418
|
+
u = ones ^ x;
|
|
419
|
+
twosB = ones & x | u & y;
|
|
420
|
+
ones = u ^ y;
|
|
421
|
+
u = twos ^ twosA;
|
|
422
|
+
foursA = twos & twosA | u & twosB;
|
|
423
|
+
twos = u ^ twosB;
|
|
424
|
+
x = d[i + 12];
|
|
425
|
+
y = d[i + 13];
|
|
426
|
+
u = ones ^ x;
|
|
427
|
+
twosA = ones & x | u & y;
|
|
428
|
+
ones = u ^ y;
|
|
429
|
+
x = d[i + 14];
|
|
430
|
+
y = d[i + 15];
|
|
431
|
+
u = ones ^ x;
|
|
432
|
+
twosB = ones & x | u & y;
|
|
433
|
+
ones = u ^ y;
|
|
434
|
+
u = twos ^ twosA;
|
|
435
|
+
foursB = twos & twosA | u & twosB;
|
|
436
|
+
twos = u ^ twosB;
|
|
437
|
+
u = fours ^ foursA;
|
|
438
|
+
const eightsB = fours & foursA | u & foursB;
|
|
439
|
+
fours = u ^ foursB;
|
|
440
|
+
u = eights ^ eightsA;
|
|
441
|
+
const sixteens = eights & eightsA | u & eightsB;
|
|
442
|
+
eights = u ^ eightsB;
|
|
443
|
+
total += popcount32(sixteens);
|
|
444
|
+
}
|
|
445
|
+
return 16 * total + 8 * popcount32(eights) + 4 * popcount32(fours) + 2 * popcount32(twos) + popcount32(ones);
|
|
446
|
+
}
|
|
447
|
+
function setRange(words, start, end) {
|
|
448
|
+
const first = start >>> 5;
|
|
449
|
+
const last = end >>> 5;
|
|
450
|
+
const head = 4294967295 << (start & 31) >>> 0;
|
|
451
|
+
const tail = 4294967295 >>> 31 - (end & 31);
|
|
452
|
+
if (first === last) {
|
|
453
|
+
words[first] = words[first] | head & tail;
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
words[first] = words[first] | head;
|
|
457
|
+
for (let i = first + 1; i < last; i++) words[i] = 4294967295;
|
|
458
|
+
words[last] = words[last] | tail;
|
|
459
|
+
}
|
|
460
|
+
function clearRange(words, start, end) {
|
|
461
|
+
const first = start >>> 5;
|
|
462
|
+
const last = end >>> 5;
|
|
463
|
+
const head = 4294967295 << (start & 31) >>> 0;
|
|
464
|
+
const tail = 4294967295 >>> 31 - (end & 31);
|
|
465
|
+
if (first === last) {
|
|
466
|
+
words[first] = words[first] & ~(head & tail);
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
words[first] = words[first] & ~head;
|
|
470
|
+
for (let i = first + 1; i < last; i++) words[i] = 0;
|
|
471
|
+
words[last] = words[last] & ~tail;
|
|
472
|
+
}
|
|
473
|
+
function fromSortedIds(ids, from, to) {
|
|
474
|
+
const n = to - from;
|
|
475
|
+
if (n <= ARRAY_MAX_CARDINALITY) {
|
|
476
|
+
const lows = new Uint16Array(n);
|
|
477
|
+
let count = 0;
|
|
478
|
+
let previous = -1;
|
|
479
|
+
for (let i = from; i < to; i++) {
|
|
480
|
+
const low = ids[i] & 65535;
|
|
481
|
+
if (low !== previous) lows[count++] = low;
|
|
482
|
+
previous = low;
|
|
483
|
+
}
|
|
484
|
+
return arrayContainer(count === n ? lows : lows.slice(0, count), count);
|
|
485
|
+
}
|
|
486
|
+
const words = new Uint32Array(WORDS);
|
|
487
|
+
for (let i = from; i < to; i++) {
|
|
488
|
+
const v = ids[i] & 65535;
|
|
489
|
+
words[v >>> 5] = words[v >>> 5] | 1 << (v & 31);
|
|
490
|
+
}
|
|
491
|
+
return fromWordsCard(words, popcountWords(words));
|
|
492
|
+
}
|
|
493
|
+
function fromWordsCard(words, card) {
|
|
494
|
+
if (card === 0) return null;
|
|
495
|
+
if (card > ARRAY_MAX_CARDINALITY) return bitsetContainer(words, card);
|
|
496
|
+
const out = new Uint16Array(card);
|
|
497
|
+
wordsToLows(words, out);
|
|
498
|
+
return arrayContainer(out, card);
|
|
499
|
+
}
|
|
500
|
+
function wordsToLows(words, out) {
|
|
501
|
+
let k = 0;
|
|
502
|
+
for (let i = 0; i < WORDS; i++) {
|
|
503
|
+
let w = words[i];
|
|
504
|
+
const base = i * 32 + 31;
|
|
505
|
+
while (w !== 0) {
|
|
506
|
+
const lowest = w & -w;
|
|
507
|
+
out[k++] = base - Math.clz32(lowest);
|
|
508
|
+
w ^= lowest;
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
return k;
|
|
512
|
+
}
|
|
513
|
+
function writeLows(c, out) {
|
|
514
|
+
if (c.kind === ARRAY2) {
|
|
515
|
+
out.set(lows16(c).subarray(c.off, c.off + c.len));
|
|
516
|
+
} else if (c.kind === BITSET) {
|
|
517
|
+
wordsToLows(words32(c), out);
|
|
518
|
+
} else {
|
|
519
|
+
const u16 = lows16(c);
|
|
520
|
+
let k = 0;
|
|
521
|
+
for (let r = 0; r < c.len; r++) {
|
|
522
|
+
const start = u16[c.off + 2 * r];
|
|
523
|
+
const end = start + u16[c.off + 2 * r + 1];
|
|
524
|
+
for (let v = start; v <= end; v++) out[k++] = v;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
function appendIds(c, out, at, base) {
|
|
529
|
+
if (c.kind === ARRAY2) {
|
|
530
|
+
const u162 = lows16(c);
|
|
531
|
+
const end = c.off + c.len;
|
|
532
|
+
if (base === 0) {
|
|
533
|
+
out.set(u162.subarray(c.off, end), at);
|
|
534
|
+
return at + c.len;
|
|
535
|
+
}
|
|
536
|
+
for (let i = c.off; i < end; i++) out[at++] = base + u162[i];
|
|
537
|
+
return at;
|
|
538
|
+
}
|
|
539
|
+
if (c.kind === BITSET) {
|
|
540
|
+
const words = words32(c);
|
|
541
|
+
for (let i = 0; i < WORDS; i++) {
|
|
542
|
+
let w = words[i];
|
|
543
|
+
const top = base + i * 32 + 31;
|
|
544
|
+
while (w !== 0) {
|
|
545
|
+
const lowest = w & -w;
|
|
546
|
+
out[at++] = top - Math.clz32(lowest);
|
|
547
|
+
w ^= lowest;
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
return at;
|
|
551
|
+
}
|
|
552
|
+
const u16 = lows16(c);
|
|
553
|
+
for (let r = 0; r < c.len; r++) {
|
|
554
|
+
const start = u16[c.off + 2 * r];
|
|
555
|
+
const last = start + u16[c.off + 2 * r + 1];
|
|
556
|
+
if (last - start < LONG_RUN) {
|
|
557
|
+
for (let v = base + start; v <= base + last; v++) out[at++] = v;
|
|
558
|
+
continue;
|
|
559
|
+
}
|
|
560
|
+
const from = at;
|
|
561
|
+
out.set(iota().subarray(start, last + 1), at);
|
|
562
|
+
at += last - start + 1;
|
|
563
|
+
if (base !== 0) for (let i = from; i < at; i++) out[i] = out[i] + base;
|
|
564
|
+
}
|
|
565
|
+
return at;
|
|
566
|
+
}
|
|
567
|
+
var LONG_RUN = 48;
|
|
568
|
+
var iotaTable;
|
|
569
|
+
function iota() {
|
|
570
|
+
if (iotaTable === void 0) {
|
|
571
|
+
iotaTable = new Uint16Array(65536);
|
|
572
|
+
for (let i = 0; i < 65536; i++) iotaTable[i] = i;
|
|
573
|
+
}
|
|
574
|
+
return iotaTable;
|
|
575
|
+
}
|
|
576
|
+
function toWords(c) {
|
|
577
|
+
if (c.kind === BITSET) return words32(c);
|
|
578
|
+
const words = new Uint32Array(WORDS);
|
|
579
|
+
const u16 = lows16(c);
|
|
580
|
+
if (c.kind === ARRAY2) {
|
|
581
|
+
for (let i = c.off; i < c.off + c.len; i++) {
|
|
582
|
+
const v = u16[i];
|
|
583
|
+
words[v >>> 5] = words[v >>> 5] | 1 << (v & 31);
|
|
584
|
+
}
|
|
585
|
+
} else {
|
|
586
|
+
for (let r = 0; r < c.len; r++) {
|
|
587
|
+
const start = u16[c.off + 2 * r];
|
|
588
|
+
setRange(words, start, start + u16[c.off + 2 * r + 1]);
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
return words;
|
|
592
|
+
}
|
|
593
|
+
function demote(c) {
|
|
594
|
+
if (c.kind !== RUN2) return c;
|
|
595
|
+
if (c.card > ARRAY_MAX_CARDINALITY) return bitsetContainer(toWords(c), c.card);
|
|
596
|
+
const out = new Uint16Array(c.card);
|
|
597
|
+
writeLows(c, out);
|
|
598
|
+
return arrayContainer(out, c.card);
|
|
599
|
+
}
|
|
600
|
+
function cloneContainer(c) {
|
|
601
|
+
if (c.kind === BITSET) return bitsetContainer(words32(c).slice(), c.card);
|
|
602
|
+
const copy = lows16(c).slice(c.off, c.off + (c.kind === ARRAY2 ? c.len : 2 * c.len));
|
|
603
|
+
return new Container(c.kind, copy, 0, c.len, c.card, false);
|
|
604
|
+
}
|
|
605
|
+
function writableWords(c) {
|
|
606
|
+
return c.shared ? words32(c).slice() : words32(c);
|
|
607
|
+
}
|
|
608
|
+
function lowerBound(data, off, len, low, stride) {
|
|
609
|
+
let lo = 0;
|
|
610
|
+
let hi = len;
|
|
611
|
+
while (lo < hi) {
|
|
612
|
+
const mid = lo + hi >>> 1;
|
|
613
|
+
if (data[off + mid * stride] < low) lo = mid + 1;
|
|
614
|
+
else hi = mid;
|
|
615
|
+
}
|
|
616
|
+
return lo;
|
|
617
|
+
}
|
|
618
|
+
function gallop(data, off, from, end, target) {
|
|
619
|
+
let step = 1;
|
|
620
|
+
let lo = from;
|
|
621
|
+
let hi = from;
|
|
622
|
+
while (hi < end && data[off + hi] < target) {
|
|
623
|
+
lo = hi + 1;
|
|
624
|
+
hi += step;
|
|
625
|
+
step *= 2;
|
|
626
|
+
}
|
|
627
|
+
if (hi > end) hi = end;
|
|
628
|
+
while (lo < hi) {
|
|
629
|
+
const mid = lo + hi >>> 1;
|
|
630
|
+
if (data[off + mid] < target) lo = mid + 1;
|
|
631
|
+
else hi = mid;
|
|
632
|
+
}
|
|
633
|
+
return lo;
|
|
634
|
+
}
|
|
635
|
+
function containerHas(c, low) {
|
|
636
|
+
if (c.kind === BITSET)
|
|
637
|
+
return (c.data[low >>> 5] >>> (low & 31) & 1) === 1;
|
|
638
|
+
const u16 = c.data;
|
|
639
|
+
if (c.kind === ARRAY2) {
|
|
640
|
+
const at = lowerBound(u16, c.off, c.len, low, 1);
|
|
641
|
+
return at < c.len && u16[c.off + at] === low;
|
|
642
|
+
}
|
|
643
|
+
const after = lowerBound(u16, c.off, c.len, low + 1, 2);
|
|
644
|
+
if (after === 0) return false;
|
|
645
|
+
const r = c.off + 2 * (after - 1);
|
|
646
|
+
return low <= u16[r] + u16[r + 1];
|
|
647
|
+
}
|
|
648
|
+
function containerAdd(c, low) {
|
|
649
|
+
if (containerHas(c, low)) return c;
|
|
650
|
+
const plain = demote(c);
|
|
651
|
+
if (plain.kind === BITSET) {
|
|
652
|
+
const words = writableWords(plain);
|
|
653
|
+
words[low >>> 5] = words[low >>> 5] | 1 << (low & 31);
|
|
654
|
+
return bitsetContainer(words, plain.card + 1);
|
|
655
|
+
}
|
|
656
|
+
if (plain.card === ARRAY_MAX_CARDINALITY) {
|
|
657
|
+
const words = toWords(plain);
|
|
658
|
+
words[low >>> 5] = words[low >>> 5] | 1 << (low & 31);
|
|
659
|
+
return bitsetContainer(words, plain.card + 1);
|
|
660
|
+
}
|
|
661
|
+
const old = lows16(plain);
|
|
662
|
+
const at = lowerBound(old, plain.off, plain.len, low, 1);
|
|
663
|
+
let u16 = old;
|
|
664
|
+
if (!plain.shared && plain.off === 0 && old.length > plain.len) {
|
|
665
|
+
u16.copyWithin(at + 1, at, plain.len);
|
|
666
|
+
} else {
|
|
667
|
+
u16 = new Uint16Array(Math.min(ARRAY_MAX_CARDINALITY, Math.max(8, plain.len * 2)));
|
|
668
|
+
u16.set(old.subarray(plain.off, plain.off + at));
|
|
669
|
+
u16.set(old.subarray(plain.off + at, plain.off + plain.len), at + 1);
|
|
670
|
+
}
|
|
671
|
+
u16[at] = low;
|
|
672
|
+
return arrayContainer(u16, plain.card + 1);
|
|
673
|
+
}
|
|
674
|
+
function containerRemove(c, low) {
|
|
675
|
+
if (!containerHas(c, low)) return c;
|
|
676
|
+
if (c.card === 1) return null;
|
|
677
|
+
const plain = demote(c);
|
|
678
|
+
if (plain.kind === BITSET) {
|
|
679
|
+
const words = writableWords(plain);
|
|
680
|
+
words[low >>> 5] = words[low >>> 5] & ~(1 << (low & 31));
|
|
681
|
+
return fromWordsCard(words, plain.card - 1);
|
|
682
|
+
}
|
|
683
|
+
const old = lows16(plain);
|
|
684
|
+
const at = lowerBound(old, plain.off, plain.len, low, 1);
|
|
685
|
+
if (!plain.shared && plain.off === 0) {
|
|
686
|
+
old.copyWithin(at, at + 1, plain.len);
|
|
687
|
+
return arrayContainer(old, plain.card - 1);
|
|
688
|
+
}
|
|
689
|
+
const u16 = new Uint16Array(plain.len - 1);
|
|
690
|
+
u16.set(old.subarray(plain.off, plain.off + at));
|
|
691
|
+
u16.set(old.subarray(plain.off + at + 1, plain.off + plain.len), at);
|
|
692
|
+
return arrayContainer(u16, plain.card - 1);
|
|
693
|
+
}
|
|
694
|
+
function containerMax(c) {
|
|
695
|
+
if (c.kind === ARRAY2) return c.data[c.off + c.len - 1];
|
|
696
|
+
if (c.kind === RUN2) {
|
|
697
|
+
const u16 = c.data;
|
|
698
|
+
return u16[c.off + 2 * c.len - 2] + u16[c.off + 2 * c.len - 1];
|
|
699
|
+
}
|
|
700
|
+
const words = words32(c);
|
|
701
|
+
for (let i = WORDS - 1; i >= 0; i--) {
|
|
702
|
+
const w = words[i];
|
|
703
|
+
if (w !== 0) return i * 32 + 31 - Math.clz32(w);
|
|
704
|
+
}
|
|
705
|
+
throw new RangeError("a bitset container holds no bits");
|
|
706
|
+
}
|
|
707
|
+
function runCount(c, stop) {
|
|
708
|
+
if (c.kind === RUN2) return c.len;
|
|
709
|
+
let runs = 0;
|
|
710
|
+
if (c.kind === ARRAY2) {
|
|
711
|
+
const u16 = lows16(c);
|
|
712
|
+
let previous = -2;
|
|
713
|
+
for (let i = c.off; i < c.off + c.len; i++) {
|
|
714
|
+
const v = u16[i];
|
|
715
|
+
if (v !== previous + 1 && ++runs >= stop) return runs;
|
|
716
|
+
previous = v;
|
|
717
|
+
}
|
|
718
|
+
return runs;
|
|
719
|
+
}
|
|
720
|
+
const words = words32(c);
|
|
721
|
+
let carry = 0;
|
|
722
|
+
for (let i = 0; i < WORDS; i++) {
|
|
723
|
+
const w = words[i];
|
|
724
|
+
const starts = w & ~(w << 1 | carry);
|
|
725
|
+
if (starts !== 0) {
|
|
726
|
+
runs += popcount32(starts >>> 0);
|
|
727
|
+
if (runs >= stop) return runs;
|
|
728
|
+
}
|
|
729
|
+
carry = w >>> 31;
|
|
730
|
+
}
|
|
731
|
+
return runs;
|
|
732
|
+
}
|
|
733
|
+
function toRun(c, runs) {
|
|
734
|
+
const pairs = new Uint16Array(2 * runs);
|
|
735
|
+
let r = 0;
|
|
736
|
+
if (c.kind === ARRAY2) {
|
|
737
|
+
const u16 = lows16(c);
|
|
738
|
+
const end = c.off + c.len;
|
|
739
|
+
let i = c.off;
|
|
740
|
+
while (i < end) {
|
|
741
|
+
let j = i;
|
|
742
|
+
while (j + 1 < end && u16[j + 1] === u16[j] + 1) j++;
|
|
743
|
+
pairs[2 * r] = u16[i];
|
|
744
|
+
pairs[2 * r + 1] = j - i;
|
|
745
|
+
r++;
|
|
746
|
+
i = j + 1;
|
|
747
|
+
}
|
|
748
|
+
return runContainer(pairs, runs, c.card);
|
|
749
|
+
}
|
|
750
|
+
const words = words32(c);
|
|
751
|
+
let start = 0;
|
|
752
|
+
let carry = 0;
|
|
753
|
+
for (let i = 0; i < WORDS; i++) {
|
|
754
|
+
const w = words[i];
|
|
755
|
+
const next = i + 1 < WORDS ? words[i + 1] : 0;
|
|
756
|
+
let starts = (w & ~(w << 1 | carry)) >>> 0;
|
|
757
|
+
let ends = (w & ~(w >>> 1 | next << 31)) >>> 0;
|
|
758
|
+
carry = w >>> 31;
|
|
759
|
+
let both = starts | ends;
|
|
760
|
+
while (both !== 0) {
|
|
761
|
+
const bit = both & -both;
|
|
762
|
+
both ^= bit;
|
|
763
|
+
const at = i * 32 + 31 - Math.clz32(bit);
|
|
764
|
+
if ((starts & bit) !== 0) {
|
|
765
|
+
starts ^= bit;
|
|
766
|
+
start = at;
|
|
767
|
+
}
|
|
768
|
+
if ((ends & bit) !== 0) {
|
|
769
|
+
ends ^= bit;
|
|
770
|
+
pairs[2 * r] = start;
|
|
771
|
+
pairs[2 * r + 1] = at - start;
|
|
772
|
+
r++;
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
return runContainer(pairs, runs, c.card);
|
|
777
|
+
}
|
|
778
|
+
function optimize(c) {
|
|
779
|
+
const plain = c.card <= ARRAY_MAX_CARDINALITY ? 2 * c.card : BITSET_BYTES;
|
|
780
|
+
const runs = runCount(c, (plain - 2) / 4);
|
|
781
|
+
if (2 + 4 * runs < plain) return c.kind === RUN2 ? c : toRun(c, runs);
|
|
782
|
+
return demote(c);
|
|
783
|
+
}
|
|
784
|
+
function skewed(shorter, longer) {
|
|
785
|
+
return longer >= GALLOP_SKEW * shorter;
|
|
786
|
+
}
|
|
787
|
+
var PROBE_MIN = 32;
|
|
788
|
+
var probeWords = new Uint32Array(WORDS);
|
|
789
|
+
function andArrays(a, b) {
|
|
790
|
+
const small = a.len <= b.len ? a : b;
|
|
791
|
+
const big = small === a ? b : a;
|
|
792
|
+
const s = lows16(small);
|
|
793
|
+
const l = lows16(big);
|
|
794
|
+
const out = values16(small.len);
|
|
795
|
+
let n = 0;
|
|
796
|
+
if (small.len >= PROBE_MIN && !skewed(small.len, big.len)) {
|
|
797
|
+
const se = small.off + small.len;
|
|
798
|
+
const first = s[small.off];
|
|
799
|
+
const last = s[se - 1];
|
|
800
|
+
const le = big.off + big.len;
|
|
801
|
+
if (last < l[big.off] || first > l[le - 1]) return null;
|
|
802
|
+
const from = gallop(l, 0, big.off, le, first);
|
|
803
|
+
const to = gallop(l, 0, from, le, last + 1);
|
|
804
|
+
const words = probeWords;
|
|
805
|
+
for (let i2 = small.off; i2 < se; i2++) {
|
|
806
|
+
const v = s[i2];
|
|
807
|
+
words[v >>> 5] = words[v >>> 5] | 1 << (v & 31);
|
|
808
|
+
}
|
|
809
|
+
for (let j2 = from; j2 < to; j2++) {
|
|
810
|
+
const v = l[j2];
|
|
811
|
+
out[n] = v;
|
|
812
|
+
n += words[v >>> 5] >>> (v & 31) & 1;
|
|
813
|
+
}
|
|
814
|
+
for (let i2 = small.off; i2 < se; i2++) words[s[i2] >>> 5] = 0;
|
|
815
|
+
return arrayOfScratch(out, n);
|
|
816
|
+
}
|
|
817
|
+
if (skewed(small.len, big.len)) {
|
|
818
|
+
let at = 0;
|
|
819
|
+
const end = big.off + big.len;
|
|
820
|
+
for (let i2 = small.off; i2 < small.off + small.len; i2++) {
|
|
821
|
+
const v = s[i2];
|
|
822
|
+
at = gallop(l, 0, Math.max(at, big.off), end, v);
|
|
823
|
+
if (at === end) break;
|
|
824
|
+
if (l[at] === v) out[n++] = v;
|
|
825
|
+
}
|
|
826
|
+
return arrayOfScratch(out, n);
|
|
827
|
+
}
|
|
828
|
+
let i = small.off;
|
|
829
|
+
let j = big.off;
|
|
830
|
+
const ie = small.off + small.len;
|
|
831
|
+
const je = big.off + big.len;
|
|
832
|
+
while (i < ie && j < je) {
|
|
833
|
+
const x = s[i];
|
|
834
|
+
const y = l[j];
|
|
835
|
+
out[n] = x;
|
|
836
|
+
n += x === y ? 1 : 0;
|
|
837
|
+
i += x <= y ? 1 : 0;
|
|
838
|
+
j += x >= y ? 1 : 0;
|
|
839
|
+
}
|
|
840
|
+
return arrayOfScratch(out, n);
|
|
841
|
+
}
|
|
842
|
+
function filterByBits(a, b, keep) {
|
|
843
|
+
const u16 = lows16(a);
|
|
844
|
+
const words = words32(b);
|
|
845
|
+
const out = values16(a.len);
|
|
846
|
+
const flip = keep ? 0 : 1;
|
|
847
|
+
let n = 0;
|
|
848
|
+
for (let i = a.off; i < a.off + a.len; i++) {
|
|
849
|
+
const v = u16[i];
|
|
850
|
+
out[n] = v;
|
|
851
|
+
n += words[v >>> 5] >>> (v & 31) & 1 ^ flip;
|
|
852
|
+
}
|
|
853
|
+
return arrayOfScratch(out, n);
|
|
854
|
+
}
|
|
855
|
+
function filterByRuns(a, b, keep) {
|
|
856
|
+
const u16 = lows16(a);
|
|
857
|
+
const pairs = lows16(b);
|
|
858
|
+
const out = values16(a.len);
|
|
859
|
+
let n = 0;
|
|
860
|
+
if (keep && a.len >= b.len) {
|
|
861
|
+
const ae = a.off + a.len;
|
|
862
|
+
let i = a.off;
|
|
863
|
+
for (let r2 = 0; r2 < b.len && i < ae; r2++) {
|
|
864
|
+
const start = pairs[b.off + 2 * r2];
|
|
865
|
+
const end = start + pairs[b.off + 2 * r2 + 1];
|
|
866
|
+
while (i < ae && u16[i] < start) i++;
|
|
867
|
+
while (i < ae && u16[i] <= end) out[n++] = u16[i++];
|
|
868
|
+
}
|
|
869
|
+
return arrayOfScratch(out, n);
|
|
870
|
+
}
|
|
871
|
+
let r = 0;
|
|
872
|
+
for (let i = a.off; i < a.off + a.len; i++) {
|
|
873
|
+
const v = u16[i];
|
|
874
|
+
while (r < b.len && pairs[b.off + 2 * r] + pairs[b.off + 2 * r + 1] < v) {
|
|
875
|
+
r++;
|
|
876
|
+
}
|
|
877
|
+
const inside = r < b.len && pairs[b.off + 2 * r] <= v;
|
|
878
|
+
if (inside === keep) out[n++] = v;
|
|
879
|
+
}
|
|
880
|
+
return arrayOfScratch(out, n);
|
|
881
|
+
}
|
|
882
|
+
function andNotArrays(a, b) {
|
|
883
|
+
const x = lows16(a);
|
|
884
|
+
const y = lows16(b);
|
|
885
|
+
const out = values16(a.len);
|
|
886
|
+
let n = 0;
|
|
887
|
+
const je = b.off + b.len;
|
|
888
|
+
if (skewed(a.len, b.len)) {
|
|
889
|
+
let at = b.off;
|
|
890
|
+
for (let i2 = a.off; i2 < a.off + a.len; i2++) {
|
|
891
|
+
const v = x[i2];
|
|
892
|
+
at = gallop(y, 0, at, je, v);
|
|
893
|
+
if (at === je || y[at] !== v) out[n++] = v;
|
|
894
|
+
}
|
|
895
|
+
return arrayOfScratch(out, n);
|
|
896
|
+
}
|
|
897
|
+
if (b.len >= PROBE_MIN) {
|
|
898
|
+
const ae = a.off + a.len;
|
|
899
|
+
const first = x[a.off];
|
|
900
|
+
const last = x[ae - 1];
|
|
901
|
+
const from = gallop(y, 0, b.off, je, first);
|
|
902
|
+
const to = gallop(y, 0, from, je, last + 1);
|
|
903
|
+
const words = probeWords;
|
|
904
|
+
for (let j2 = from; j2 < to; j2++) {
|
|
905
|
+
const v = y[j2];
|
|
906
|
+
words[v >>> 5] = words[v >>> 5] | 1 << (v & 31);
|
|
907
|
+
}
|
|
908
|
+
for (let i2 = a.off; i2 < ae; i2++) {
|
|
909
|
+
const v = x[i2];
|
|
910
|
+
out[n] = v;
|
|
911
|
+
n += words[v >>> 5] >>> (v & 31) & 1 ^ 1;
|
|
912
|
+
}
|
|
913
|
+
for (let j2 = from; j2 < to; j2++) words[y[j2] >>> 5] = 0;
|
|
914
|
+
return arrayOfScratch(out, n);
|
|
915
|
+
}
|
|
916
|
+
let i = a.off;
|
|
917
|
+
let j = b.off;
|
|
918
|
+
const ie = a.off + a.len;
|
|
919
|
+
while (i < ie && j < je) {
|
|
920
|
+
const p = x[i];
|
|
921
|
+
const q = y[j];
|
|
922
|
+
out[n] = p;
|
|
923
|
+
n += p < q ? 1 : 0;
|
|
924
|
+
i += p <= q ? 1 : 0;
|
|
925
|
+
j += p >= q ? 1 : 0;
|
|
926
|
+
}
|
|
927
|
+
while (i < ie) out[n++] = x[i++];
|
|
928
|
+
return arrayOfScratch(out, n);
|
|
929
|
+
}
|
|
930
|
+
function orArrays(a, b) {
|
|
931
|
+
const x = lows16(a);
|
|
932
|
+
const y = lows16(b);
|
|
933
|
+
const ie = a.off + a.len;
|
|
934
|
+
const je = b.off + b.len;
|
|
935
|
+
if (a.len + b.len > ARRAY_MAX_CARDINALITY) {
|
|
936
|
+
const words = new Uint32Array(WORDS);
|
|
937
|
+
for (let i2 = a.off; i2 < ie; i2++) {
|
|
938
|
+
const v = x[i2];
|
|
939
|
+
words[v >>> 5] = words[v >>> 5] | 1 << (v & 31);
|
|
940
|
+
}
|
|
941
|
+
for (let j2 = b.off; j2 < je; j2++) {
|
|
942
|
+
const v = y[j2];
|
|
943
|
+
words[v >>> 5] = words[v >>> 5] | 1 << (v & 31);
|
|
944
|
+
}
|
|
945
|
+
return fromWordsCard(words, popcountWords(words));
|
|
946
|
+
}
|
|
947
|
+
const out = values16(a.len + b.len);
|
|
948
|
+
let n = 0;
|
|
949
|
+
let i = a.off;
|
|
950
|
+
let j = b.off;
|
|
951
|
+
while (i < ie && j < je) {
|
|
952
|
+
const p = x[i];
|
|
953
|
+
const q = y[j];
|
|
954
|
+
out[n++] = p < q ? p : q;
|
|
955
|
+
i += p <= q ? 1 : 0;
|
|
956
|
+
j += p >= q ? 1 : 0;
|
|
957
|
+
}
|
|
958
|
+
while (i < ie) out[n++] = x[i++];
|
|
959
|
+
while (j < je) out[n++] = y[j++];
|
|
960
|
+
return arrayOfScratch(out, n);
|
|
961
|
+
}
|
|
962
|
+
function orIntoBitset(dest, other, inPlace) {
|
|
963
|
+
const words = inPlace ? words32(dest) : words32(dest).slice();
|
|
964
|
+
if (other.kind === ARRAY2) {
|
|
965
|
+
const u16 = lows16(other);
|
|
966
|
+
let card = dest.card;
|
|
967
|
+
for (let i = other.off; i < other.off + other.len; i++) {
|
|
968
|
+
const v = u16[i];
|
|
969
|
+
const w = words[v >>> 5];
|
|
970
|
+
const bit = 1 << (v & 31);
|
|
971
|
+
if ((w & bit) === 0) {
|
|
972
|
+
words[v >>> 5] = w | bit;
|
|
973
|
+
card++;
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
return bitsetContainer(words, card);
|
|
977
|
+
}
|
|
978
|
+
if (other.kind === BITSET) {
|
|
979
|
+
const o = words32(other);
|
|
980
|
+
for (let i = 0; i < WORDS; i++) words[i] = words[i] | o[i];
|
|
981
|
+
} else {
|
|
982
|
+
const pairs = lows16(other);
|
|
983
|
+
for (let r = 0; r < other.len; r++) {
|
|
984
|
+
const start = pairs[other.off + 2 * r];
|
|
985
|
+
setRange(words, start, start + pairs[other.off + 2 * r + 1]);
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
return bitsetContainer(words, popcountWords(words));
|
|
989
|
+
}
|
|
990
|
+
function fromRunPairs(pairs, runs, card) {
|
|
991
|
+
if (card === 0) return null;
|
|
992
|
+
if (card <= ARRAY_MAX_CARDINALITY) {
|
|
993
|
+
const out = new Uint16Array(card);
|
|
994
|
+
let k = 0;
|
|
995
|
+
for (let r = 0; r < runs; r++) {
|
|
996
|
+
const start = pairs[2 * r];
|
|
997
|
+
const end = start + pairs[2 * r + 1];
|
|
998
|
+
for (let v = start; v <= end; v++) out[k++] = v;
|
|
999
|
+
}
|
|
1000
|
+
return arrayContainer(out, card);
|
|
1001
|
+
}
|
|
1002
|
+
const words = new Uint32Array(WORDS);
|
|
1003
|
+
for (let r = 0; r < runs; r++) {
|
|
1004
|
+
const start = pairs[2 * r];
|
|
1005
|
+
setRange(words, start, start + pairs[2 * r + 1]);
|
|
1006
|
+
}
|
|
1007
|
+
return bitsetContainer(words, card);
|
|
1008
|
+
}
|
|
1009
|
+
function andRuns(a, b) {
|
|
1010
|
+
const x = lows16(a);
|
|
1011
|
+
const y = lows16(b);
|
|
1012
|
+
const out = pairs16(2 * (a.len + b.len));
|
|
1013
|
+
let runs = 0;
|
|
1014
|
+
let card = 0;
|
|
1015
|
+
let i = 0;
|
|
1016
|
+
let j = 0;
|
|
1017
|
+
while (i < a.len && j < b.len) {
|
|
1018
|
+
const as = x[a.off + 2 * i];
|
|
1019
|
+
const ae = as + x[a.off + 2 * i + 1];
|
|
1020
|
+
const bs = y[b.off + 2 * j];
|
|
1021
|
+
const be = bs + y[b.off + 2 * j + 1];
|
|
1022
|
+
const lo = as > bs ? as : bs;
|
|
1023
|
+
const hi = ae < be ? ae : be;
|
|
1024
|
+
if (lo <= hi) {
|
|
1025
|
+
out[2 * runs] = lo;
|
|
1026
|
+
out[2 * runs + 1] = hi - lo;
|
|
1027
|
+
runs++;
|
|
1028
|
+
card += hi - lo + 1;
|
|
1029
|
+
}
|
|
1030
|
+
if (ae < be) i++;
|
|
1031
|
+
else j++;
|
|
1032
|
+
}
|
|
1033
|
+
return fromRunPairs(out, runs, card);
|
|
1034
|
+
}
|
|
1035
|
+
function orRuns(a, b) {
|
|
1036
|
+
const x = lows16(a);
|
|
1037
|
+
const y = lows16(b);
|
|
1038
|
+
const out = pairs16(2 * (a.len + b.len));
|
|
1039
|
+
let runs = 0;
|
|
1040
|
+
let card = 0;
|
|
1041
|
+
let i = 0;
|
|
1042
|
+
let j = 0;
|
|
1043
|
+
let start = -1;
|
|
1044
|
+
let end = -1;
|
|
1045
|
+
const flush = () => {
|
|
1046
|
+
if (start < 0) return;
|
|
1047
|
+
out[2 * runs] = start;
|
|
1048
|
+
out[2 * runs + 1] = end - start;
|
|
1049
|
+
runs++;
|
|
1050
|
+
card += end - start + 1;
|
|
1051
|
+
};
|
|
1052
|
+
while (i < a.len || j < b.len) {
|
|
1053
|
+
let s;
|
|
1054
|
+
let e;
|
|
1055
|
+
if (j >= b.len || i < a.len && x[a.off + 2 * i] <= y[b.off + 2 * j]) {
|
|
1056
|
+
s = x[a.off + 2 * i];
|
|
1057
|
+
e = s + x[a.off + 2 * i + 1];
|
|
1058
|
+
i++;
|
|
1059
|
+
} else {
|
|
1060
|
+
s = y[b.off + 2 * j];
|
|
1061
|
+
e = s + y[b.off + 2 * j + 1];
|
|
1062
|
+
j++;
|
|
1063
|
+
}
|
|
1064
|
+
if (start >= 0 && s <= end + 1) {
|
|
1065
|
+
if (e > end) end = e;
|
|
1066
|
+
} else {
|
|
1067
|
+
flush();
|
|
1068
|
+
start = s;
|
|
1069
|
+
end = e;
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
flush();
|
|
1073
|
+
return fromRunPairs(out, runs, card);
|
|
1074
|
+
}
|
|
1075
|
+
function andNotRuns(a, b) {
|
|
1076
|
+
const x = lows16(a);
|
|
1077
|
+
const y = lows16(b);
|
|
1078
|
+
const out = pairs16(2 * (a.len + b.len + 1));
|
|
1079
|
+
let runs = 0;
|
|
1080
|
+
let card = 0;
|
|
1081
|
+
let j = 0;
|
|
1082
|
+
for (let i = 0; i < a.len; i++) {
|
|
1083
|
+
let s = x[a.off + 2 * i];
|
|
1084
|
+
const e = s + x[a.off + 2 * i + 1];
|
|
1085
|
+
while (j < b.len && y[b.off + 2 * j] + y[b.off + 2 * j + 1] < s) j++;
|
|
1086
|
+
let k = j;
|
|
1087
|
+
while (s <= e) {
|
|
1088
|
+
if (k >= b.len || y[b.off + 2 * k] > e) {
|
|
1089
|
+
out[2 * runs] = s;
|
|
1090
|
+
out[2 * runs + 1] = e - s;
|
|
1091
|
+
runs++;
|
|
1092
|
+
card += e - s + 1;
|
|
1093
|
+
break;
|
|
1094
|
+
}
|
|
1095
|
+
const bs = y[b.off + 2 * k];
|
|
1096
|
+
const be = bs + y[b.off + 2 * k + 1];
|
|
1097
|
+
if (bs > s) {
|
|
1098
|
+
out[2 * runs] = s;
|
|
1099
|
+
out[2 * runs + 1] = bs - 1 - s;
|
|
1100
|
+
runs++;
|
|
1101
|
+
card += bs - s;
|
|
1102
|
+
}
|
|
1103
|
+
s = be + 1;
|
|
1104
|
+
k++;
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
return fromRunPairs(out, runs, card);
|
|
1108
|
+
}
|
|
1109
|
+
function bitsetInRuns(a, b) {
|
|
1110
|
+
const words = words32(a);
|
|
1111
|
+
const pairs = lows16(b);
|
|
1112
|
+
if (b.card <= ARRAY_MAX_CARDINALITY) {
|
|
1113
|
+
const out2 = values16(b.card);
|
|
1114
|
+
let n = 0;
|
|
1115
|
+
for (let r = 0; r < b.len; r++) {
|
|
1116
|
+
const start = pairs[b.off + 2 * r];
|
|
1117
|
+
const end = start + pairs[b.off + 2 * r + 1];
|
|
1118
|
+
const first = start >>> 5;
|
|
1119
|
+
const last = end >>> 5;
|
|
1120
|
+
const head = 4294967295 << (start & 31) >>> 0;
|
|
1121
|
+
const tail = 4294967295 >>> 31 - (end & 31);
|
|
1122
|
+
for (let i = first; i <= last; i++) {
|
|
1123
|
+
let w = words[i];
|
|
1124
|
+
if (i === first) w &= head;
|
|
1125
|
+
if (i === last) w &= tail;
|
|
1126
|
+
const top = i * 32 + 31;
|
|
1127
|
+
while (w !== 0) {
|
|
1128
|
+
const lowest = w & -w;
|
|
1129
|
+
out2[n++] = top - Math.clz32(lowest);
|
|
1130
|
+
w ^= lowest;
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
return arrayOfScratch(out2, n);
|
|
1135
|
+
}
|
|
1136
|
+
const out = new Uint32Array(WORDS);
|
|
1137
|
+
for (let r = 0; r < b.len; r++) {
|
|
1138
|
+
const start = pairs[b.off + 2 * r];
|
|
1139
|
+
const end = start + pairs[b.off + 2 * r + 1];
|
|
1140
|
+
const first = start >>> 5;
|
|
1141
|
+
const last = end >>> 5;
|
|
1142
|
+
const head = 4294967295 << (start & 31) >>> 0;
|
|
1143
|
+
const tail = 4294967295 >>> 31 - (end & 31);
|
|
1144
|
+
if (first === last) {
|
|
1145
|
+
out[first] = out[first] | words[first] & head & tail;
|
|
1146
|
+
} else {
|
|
1147
|
+
out[first] = out[first] | words[first] & head;
|
|
1148
|
+
for (let i = first + 1; i < last; i++) out[i] = words[i];
|
|
1149
|
+
out[last] = out[last] | words[last] & tail;
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
return fromWordsCard(out, popcountWords(out));
|
|
1153
|
+
}
|
|
1154
|
+
function containerAnd(a, b, inPlace = false) {
|
|
1155
|
+
if (a.kind === BITSET && b.kind === BITSET) {
|
|
1156
|
+
const x = words32(a);
|
|
1157
|
+
const y = words32(b);
|
|
1158
|
+
const out = inPlace ? x : new Uint32Array(WORDS);
|
|
1159
|
+
for (let i = 0; i < WORDS; i++) out[i] = x[i] & y[i];
|
|
1160
|
+
return fromWordsCard(out, popcountWords(out));
|
|
1161
|
+
}
|
|
1162
|
+
if (a.kind > b.kind) return containerAnd(b, a);
|
|
1163
|
+
if (a.kind === ARRAY2) {
|
|
1164
|
+
if (b.kind === ARRAY2) return andArrays(a, b);
|
|
1165
|
+
return b.kind === BITSET ? filterByBits(a, b, true) : filterByRuns(a, b, true);
|
|
1166
|
+
}
|
|
1167
|
+
return b.kind === RUN2 && a.kind === RUN2 ? andRuns(a, b) : bitsetInRuns(a, b);
|
|
1168
|
+
}
|
|
1169
|
+
function containerOr(a, b, inPlace = false) {
|
|
1170
|
+
if (a.kind === BITSET) return orIntoBitset(a, b, inPlace);
|
|
1171
|
+
if (b.kind === BITSET) return orIntoBitset(b, a, false);
|
|
1172
|
+
if (a.kind === ARRAY2 && b.kind === ARRAY2) return orArrays(a, b);
|
|
1173
|
+
if (a.kind === RUN2 && b.kind === RUN2) return orRuns(a, b);
|
|
1174
|
+
const words = toWords(a.kind === RUN2 ? a : b);
|
|
1175
|
+
return orIntoBitsetWords(words, a.kind === RUN2 ? b : a);
|
|
1176
|
+
}
|
|
1177
|
+
function orIntoBitsetWords(words, array) {
|
|
1178
|
+
const u16 = lows16(array);
|
|
1179
|
+
for (let i = array.off; i < array.off + array.len; i++) {
|
|
1180
|
+
const v = u16[i];
|
|
1181
|
+
words[v >>> 5] = words[v >>> 5] | 1 << (v & 31);
|
|
1182
|
+
}
|
|
1183
|
+
return fromWordsCard(words, popcountWords(words));
|
|
1184
|
+
}
|
|
1185
|
+
function containerAndNot(a, b, inPlace = false) {
|
|
1186
|
+
if (a.kind === ARRAY2) {
|
|
1187
|
+
if (b.kind === ARRAY2) return andNotArrays(a, b);
|
|
1188
|
+
return b.kind === BITSET ? filterByBits(a, b, false) : filterByRuns(a, b, false);
|
|
1189
|
+
}
|
|
1190
|
+
if (a.kind === RUN2 && b.kind === RUN2) return andNotRuns(a, b);
|
|
1191
|
+
const words = a.kind === BITSET ? inPlace ? words32(a) : words32(a).slice() : toWords(a);
|
|
1192
|
+
if (b.kind === ARRAY2) {
|
|
1193
|
+
const u16 = lows16(b);
|
|
1194
|
+
for (let i = b.off; i < b.off + b.len; i++) {
|
|
1195
|
+
const v = u16[i];
|
|
1196
|
+
words[v >>> 5] = words[v >>> 5] & ~(1 << (v & 31));
|
|
1197
|
+
}
|
|
1198
|
+
} else if (b.kind === BITSET) {
|
|
1199
|
+
const y = words32(b);
|
|
1200
|
+
for (let i = 0; i < WORDS; i++) words[i] = words[i] & ~y[i];
|
|
1201
|
+
} else {
|
|
1202
|
+
const pairs = lows16(b);
|
|
1203
|
+
for (let r = 0; r < b.len; r++) {
|
|
1204
|
+
const start = pairs[b.off + 2 * r];
|
|
1205
|
+
clearRange(words, start, start + pairs[b.off + 2 * r + 1]);
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
return fromWordsCard(words, popcountWords(words));
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
// src/ts-roaring/iterator.ts
|
|
1212
|
+
var DONE = { done: true, value: void 0 };
|
|
1213
|
+
var BitmapIterator = class {
|
|
1214
|
+
#keys;
|
|
1215
|
+
#conts;
|
|
1216
|
+
/** The container being walked, as an index into `#conts`, and its kind, storage and offset. */
|
|
1217
|
+
#at = -1;
|
|
1218
|
+
#kind = ARRAY2;
|
|
1219
|
+
#u16 = new Uint16Array(0);
|
|
1220
|
+
#words = new Uint32Array(0);
|
|
1221
|
+
#off = 0;
|
|
1222
|
+
/** Added to every remainder: the container's key times 65,536. */
|
|
1223
|
+
#base = 0;
|
|
1224
|
+
/** An array: the next index and one past the last. A run container: the next run's index and the run count. A bitset: the word index. */
|
|
1225
|
+
#pos = 0;
|
|
1226
|
+
#end = 0;
|
|
1227
|
+
/** A run container: the next value and the last of the current run. A bitset: what is left of the current word. */
|
|
1228
|
+
#next = 0;
|
|
1229
|
+
#last = -1;
|
|
1230
|
+
constructor(keys, conts) {
|
|
1231
|
+
this.#keys = keys;
|
|
1232
|
+
this.#conts = conts;
|
|
1233
|
+
}
|
|
1234
|
+
[Symbol.iterator]() {
|
|
1235
|
+
return this;
|
|
1236
|
+
}
|
|
1237
|
+
next() {
|
|
1238
|
+
for (; ; ) {
|
|
1239
|
+
if (this.#kind === ARRAY2) {
|
|
1240
|
+
if (this.#pos < this.#end) {
|
|
1241
|
+
return { done: false, value: this.#base + this.#u16[this.#pos++] };
|
|
1242
|
+
}
|
|
1243
|
+
} else if (this.#kind === BITSET) {
|
|
1244
|
+
let w = this.#next;
|
|
1245
|
+
while (w === 0 && ++this.#pos < WORDS) w = this.#words[this.#pos];
|
|
1246
|
+
if (w !== 0) {
|
|
1247
|
+
const lowest = w & -w;
|
|
1248
|
+
this.#next = w ^ lowest;
|
|
1249
|
+
return {
|
|
1250
|
+
done: false,
|
|
1251
|
+
value: this.#base + this.#pos * 32 + 31 - Math.clz32(lowest)
|
|
1252
|
+
};
|
|
1253
|
+
}
|
|
1254
|
+
} else {
|
|
1255
|
+
if (this.#next <= this.#last) return { done: false, value: this.#base + this.#next++ };
|
|
1256
|
+
if (this.#pos < this.#end) {
|
|
1257
|
+
const r = this.#off + 2 * this.#pos++;
|
|
1258
|
+
this.#next = this.#u16[r];
|
|
1259
|
+
this.#last = this.#next + this.#u16[r + 1];
|
|
1260
|
+
continue;
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
if (!this.#advance()) return DONE;
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
/** Move to the next container; `false` when there is none. */
|
|
1267
|
+
#advance() {
|
|
1268
|
+
if (++this.#at >= this.#conts.length) {
|
|
1269
|
+
this.#at = this.#conts.length;
|
|
1270
|
+
this.#kind = ARRAY2;
|
|
1271
|
+
this.#pos = 0;
|
|
1272
|
+
this.#end = 0;
|
|
1273
|
+
return false;
|
|
1274
|
+
}
|
|
1275
|
+
const c = this.#conts[this.#at];
|
|
1276
|
+
this.#kind = c.kind;
|
|
1277
|
+
this.#base = this.#keys[this.#at] * 65536;
|
|
1278
|
+
this.#off = c.off;
|
|
1279
|
+
if (c.kind === ARRAY2) {
|
|
1280
|
+
this.#u16 = c.data;
|
|
1281
|
+
this.#pos = c.off;
|
|
1282
|
+
this.#end = c.off + c.len;
|
|
1283
|
+
} else if (c.kind === BITSET) {
|
|
1284
|
+
this.#words = c.data;
|
|
1285
|
+
this.#pos = 0;
|
|
1286
|
+
this.#next = this.#words[0];
|
|
1287
|
+
} else {
|
|
1288
|
+
this.#u16 = c.data;
|
|
1289
|
+
this.#pos = 0;
|
|
1290
|
+
this.#end = c.len;
|
|
1291
|
+
this.#next = 0;
|
|
1292
|
+
this.#last = -1;
|
|
1293
|
+
}
|
|
1294
|
+
return true;
|
|
1295
|
+
}
|
|
1296
|
+
};
|
|
1297
|
+
|
|
1298
|
+
// src/ts-roaring/wire.ts
|
|
1299
|
+
import { IntegrityError as IntegrityError2 } from "@cloudbitmaps/core";
|
|
1300
|
+
function bodySize(c) {
|
|
1301
|
+
if (c.kind === ARRAY2) return 2 * c.len;
|
|
1302
|
+
if (c.kind === BITSET) return BITSET_BYTES;
|
|
1303
|
+
return 2 + 4 * c.len;
|
|
1304
|
+
}
|
|
1305
|
+
function putU16s(out, at, src, from, count) {
|
|
1306
|
+
if (LITTLE_ENDIAN) {
|
|
1307
|
+
out.set(new Uint8Array(src.buffer, src.byteOffset + 2 * from, 2 * count), at);
|
|
1308
|
+
return;
|
|
1309
|
+
}
|
|
1310
|
+
const view = new DataView(out.buffer, out.byteOffset, out.byteLength);
|
|
1311
|
+
for (let i = 0; i < count; i++) view.setUint16(at + 2 * i, src[from + i], true);
|
|
1312
|
+
}
|
|
1313
|
+
function writeBody(c, out, view, at) {
|
|
1314
|
+
if (c.kind === ARRAY2) {
|
|
1315
|
+
putU16s(out, at, c.data, c.off, c.len);
|
|
1316
|
+
} else if (c.kind === BITSET) {
|
|
1317
|
+
const words = c.data;
|
|
1318
|
+
if (LITTLE_ENDIAN) out.set(new Uint8Array(words.buffer, words.byteOffset, BITSET_BYTES), at);
|
|
1319
|
+
else for (let i = 0; i < WORDS; i++) view.setUint32(at + 4 * i, words[i], true);
|
|
1320
|
+
} else {
|
|
1321
|
+
view.setUint16(at, c.len, true);
|
|
1322
|
+
putU16s(out, at + 2, c.data, c.off, 2 * c.len);
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1325
|
+
function serializeContainers(keys, conts) {
|
|
1326
|
+
const n = conts.length;
|
|
1327
|
+
let hasRun = false;
|
|
1328
|
+
for (let i = 0; i < n; i++) if (conts[i].kind === RUN2) hasRun = true;
|
|
1329
|
+
const offsets = !hasRun || n >= NO_OFFSET_THRESHOLD;
|
|
1330
|
+
let at = hasRun ? 4 + (n + 7 >>> 3) : 8;
|
|
1331
|
+
const describeAt = at;
|
|
1332
|
+
at += 4 * n;
|
|
1333
|
+
const offsetsAt = at;
|
|
1334
|
+
if (offsets) at += 4 * n;
|
|
1335
|
+
let total = at;
|
|
1336
|
+
for (let i = 0; i < n; i++) total += bodySize(conts[i]);
|
|
1337
|
+
const out = new Uint8Array(total);
|
|
1338
|
+
const view = new DataView(out.buffer);
|
|
1339
|
+
if (hasRun) {
|
|
1340
|
+
view.setUint32(0, SERIAL_COOKIE | n - 1 << 16, true);
|
|
1341
|
+
for (let i = 0; i < n; i++) {
|
|
1342
|
+
if (conts[i].kind === RUN2) {
|
|
1343
|
+
out[4 + (i >>> 3)] = out[4 + (i >>> 3)] | 1 << (i & 7);
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
} else {
|
|
1347
|
+
view.setUint32(0, SERIAL_COOKIE_NO_RUNCONTAINER, true);
|
|
1348
|
+
view.setUint32(4, n, true);
|
|
1349
|
+
}
|
|
1350
|
+
for (let i = 0; i < n; i++) {
|
|
1351
|
+
const c = conts[i];
|
|
1352
|
+
view.setUint16(describeAt + 4 * i, keys[i], true);
|
|
1353
|
+
view.setUint16(describeAt + 4 * i + 2, c.card - 1, true);
|
|
1354
|
+
if (offsets) view.setUint32(offsetsAt + 4 * i, at, true);
|
|
1355
|
+
writeBody(c, out, view, at);
|
|
1356
|
+
at += bodySize(c);
|
|
1357
|
+
}
|
|
1358
|
+
return out;
|
|
1359
|
+
}
|
|
1360
|
+
function decodeContainers(input) {
|
|
1361
|
+
const bytes = Uint8Array.prototype.slice.call(input);
|
|
1362
|
+
const layout = parsePortableLayout(bytes);
|
|
1363
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
1364
|
+
const keys = new Array(layout.length);
|
|
1365
|
+
const conts = new Array(layout.length);
|
|
1366
|
+
let n = 0;
|
|
1367
|
+
let end = bytes.byteLength === 0 ? 0 : 8;
|
|
1368
|
+
let slabLength = 0;
|
|
1369
|
+
let small = 0;
|
|
1370
|
+
for (const { cardinality, kind, offset } of layout) {
|
|
1371
|
+
if (kind === ARRAY) {
|
|
1372
|
+
slabLength += cardinality;
|
|
1373
|
+
small++;
|
|
1374
|
+
} else if (kind !== BITMAP) {
|
|
1375
|
+
slabLength += 2 * view.getUint16(offset, true);
|
|
1376
|
+
small++;
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
const own = LITTLE_ENDIAN && bytes.byteOffset === 0 && bytes.buffer instanceof ArrayBuffer && bytes.buffer.byteLength === bytes.byteLength;
|
|
1380
|
+
const alias = own && small === 1;
|
|
1381
|
+
const slab = alias ? NO_U16 : new Uint16Array(slabLength);
|
|
1382
|
+
let used = 0;
|
|
1383
|
+
for (const { key, cardinality, kind, offset } of layout) {
|
|
1384
|
+
keys[n] = key;
|
|
1385
|
+
if (kind === ARRAY) {
|
|
1386
|
+
if (alias && offset % 2 === 0) {
|
|
1387
|
+
const values = new Uint16Array(bytes.buffer, offset, cardinality);
|
|
1388
|
+
conts[n++] = new Container(ARRAY2, values, 0, cardinality, cardinality, false);
|
|
1389
|
+
} else {
|
|
1390
|
+
const into = alias ? new Uint16Array(cardinality) : slab;
|
|
1391
|
+
getU16s(bytes, view, offset, into, alias ? 0 : used, cardinality);
|
|
1392
|
+
conts[n++] = new Container(
|
|
1393
|
+
ARRAY2,
|
|
1394
|
+
into,
|
|
1395
|
+
alias ? 0 : used,
|
|
1396
|
+
cardinality,
|
|
1397
|
+
cardinality,
|
|
1398
|
+
small > 1
|
|
1399
|
+
);
|
|
1400
|
+
used += cardinality;
|
|
1401
|
+
}
|
|
1402
|
+
end = offset + 2 * cardinality;
|
|
1403
|
+
} else if (kind === BITMAP) {
|
|
1404
|
+
let words;
|
|
1405
|
+
if (own && offset % 4 === 0) {
|
|
1406
|
+
words = new Uint32Array(bytes.buffer, offset, WORDS);
|
|
1407
|
+
} else {
|
|
1408
|
+
words = new Uint32Array(WORDS);
|
|
1409
|
+
if (LITTLE_ENDIAN) {
|
|
1410
|
+
new Uint8Array(words.buffer).set(bytes.subarray(offset, offset + BITSET_BYTES));
|
|
1411
|
+
} else {
|
|
1412
|
+
for (let i = 0; i < WORDS; i++) words[i] = view.getUint32(offset + 4 * i, true);
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
conts[n++] = bitsetContainer(words, cardinality);
|
|
1416
|
+
end = offset + BITSET_BYTES;
|
|
1417
|
+
} else {
|
|
1418
|
+
const runs = view.getUint16(offset, true);
|
|
1419
|
+
if (alias && (offset + 2) % 2 === 0) {
|
|
1420
|
+
const pairs = new Uint16Array(bytes.buffer, offset + 2, 2 * runs);
|
|
1421
|
+
conts[n++] = new Container(RUN2, pairs, 0, runs, cardinality, false);
|
|
1422
|
+
} else {
|
|
1423
|
+
const into = alias ? new Uint16Array(2 * runs) : slab;
|
|
1424
|
+
getU16s(bytes, view, offset + 2, into, alias ? 0 : used, 2 * runs);
|
|
1425
|
+
conts[n++] = new Container(RUN2, into, alias ? 0 : used, runs, cardinality, small > 1);
|
|
1426
|
+
used += 2 * runs;
|
|
1427
|
+
}
|
|
1428
|
+
end = offset + 2 + 4 * runs;
|
|
1429
|
+
}
|
|
1430
|
+
}
|
|
1431
|
+
return { keys, conts, end };
|
|
1432
|
+
}
|
|
1433
|
+
var NO_U16 = new Uint16Array(0);
|
|
1434
|
+
function getU16s(bytes, view, at, slab, to, count) {
|
|
1435
|
+
if (LITTLE_ENDIAN) {
|
|
1436
|
+
new Uint8Array(slab.buffer, 2 * to, 2 * count).set(bytes.subarray(at, at + 2 * count));
|
|
1437
|
+
return;
|
|
1438
|
+
}
|
|
1439
|
+
for (let i = 0; i < count; i++) slab[to + i] = view.getUint16(at + 2 * i, true);
|
|
1440
|
+
}
|
|
1441
|
+
function trailingBytes(length, end) {
|
|
1442
|
+
return new IntegrityError2(
|
|
1443
|
+
`portable roaring: ${length - end} bytes follow the bitmap's last container, which ends at byte ${end}. One buffer holds one bitmap: to load several as one segment, combine them first and serialize the result.`
|
|
1444
|
+
);
|
|
1445
|
+
}
|
|
1446
|
+
|
|
1447
|
+
// src/ts-roaring/bitmap.ts
|
|
1448
|
+
var MAX_ID = 4294967295;
|
|
1449
|
+
function isId(value) {
|
|
1450
|
+
return Number.isInteger(value) && value >= 0 && value <= MAX_ID;
|
|
1451
|
+
}
|
|
1452
|
+
function badId(value) {
|
|
1453
|
+
return new ValidationError2(`${String(value)} is not an integer from 0 to ${MAX_ID}`);
|
|
1454
|
+
}
|
|
1455
|
+
function checkedId(value) {
|
|
1456
|
+
if (!isId(value)) throw badId(value);
|
|
1457
|
+
return value;
|
|
1458
|
+
}
|
|
1459
|
+
function collect(values) {
|
|
1460
|
+
if (values instanceof Uint32Array) return values;
|
|
1461
|
+
if (Array.isArray(values)) {
|
|
1462
|
+
const list = values;
|
|
1463
|
+
const out2 = new Uint32Array(list.length);
|
|
1464
|
+
for (let i = 0; i < list.length; i++) {
|
|
1465
|
+
const v = list[i];
|
|
1466
|
+
if (v >>> 0 !== v) throw badId(v);
|
|
1467
|
+
out2[i] = v;
|
|
1468
|
+
}
|
|
1469
|
+
return out2;
|
|
1470
|
+
}
|
|
1471
|
+
let out = new Uint32Array(1024);
|
|
1472
|
+
let n = 0;
|
|
1473
|
+
for (const v of values) {
|
|
1474
|
+
if (n === out.length) {
|
|
1475
|
+
const grown = new Uint32Array(2 * n);
|
|
1476
|
+
grown.set(out);
|
|
1477
|
+
out = grown;
|
|
1478
|
+
}
|
|
1479
|
+
out[n++] = checkedId(v);
|
|
1480
|
+
}
|
|
1481
|
+
return out.subarray(0, n);
|
|
1482
|
+
}
|
|
1483
|
+
function collectLenient(values) {
|
|
1484
|
+
const list = Array.isArray(values) ? values : Array.from(values);
|
|
1485
|
+
const out = new Uint32Array(list.length);
|
|
1486
|
+
let n = 0;
|
|
1487
|
+
for (let i = 0; i < list.length; i++) {
|
|
1488
|
+
const v = list[i];
|
|
1489
|
+
if (v >>> 0 === v) out[n++] = v;
|
|
1490
|
+
}
|
|
1491
|
+
return out.subarray(0, n);
|
|
1492
|
+
}
|
|
1493
|
+
function sortedIds(ids, owned) {
|
|
1494
|
+
for (let i = 1; i < ids.length; i++) {
|
|
1495
|
+
if (ids[i - 1] > ids[i]) return (owned ? ids : ids.slice()).sort();
|
|
1496
|
+
}
|
|
1497
|
+
return ids;
|
|
1498
|
+
}
|
|
1499
|
+
function lowerBound2(keys, key, from = 0) {
|
|
1500
|
+
let lo = from;
|
|
1501
|
+
let hi = keys.length;
|
|
1502
|
+
while (lo < hi) {
|
|
1503
|
+
const mid = lo + hi >>> 1;
|
|
1504
|
+
if (keys[mid] < key) lo = mid + 1;
|
|
1505
|
+
else hi = mid;
|
|
1506
|
+
}
|
|
1507
|
+
return lo;
|
|
1508
|
+
}
|
|
1509
|
+
function gallopKeys(keys, key, from) {
|
|
1510
|
+
let step = 1;
|
|
1511
|
+
let lo = from;
|
|
1512
|
+
let hi = from;
|
|
1513
|
+
while (hi < keys.length && keys[hi] < key) {
|
|
1514
|
+
lo = hi + 1;
|
|
1515
|
+
hi += step;
|
|
1516
|
+
step *= 2;
|
|
1517
|
+
}
|
|
1518
|
+
return lowerBoundIn(keys, key, lo, Math.min(hi, keys.length));
|
|
1519
|
+
}
|
|
1520
|
+
function lowerBoundIn(keys, key, from, to) {
|
|
1521
|
+
let lo = from;
|
|
1522
|
+
let hi = to;
|
|
1523
|
+
while (lo < hi) {
|
|
1524
|
+
const mid = lo + hi >>> 1;
|
|
1525
|
+
if (keys[mid] < key) lo = mid + 1;
|
|
1526
|
+
else hi = mid;
|
|
1527
|
+
}
|
|
1528
|
+
return lo;
|
|
1529
|
+
}
|
|
1530
|
+
var OR = 0;
|
|
1531
|
+
var AND = 1;
|
|
1532
|
+
var AND_NOT = 2;
|
|
1533
|
+
function combineContainers(op, a, b) {
|
|
1534
|
+
if (op === OR) return containerOr(a, b, !a.shared);
|
|
1535
|
+
if (op === AND) return containerAnd(a, b, !a.shared);
|
|
1536
|
+
return containerAndNot(a, b, !a.shared);
|
|
1537
|
+
}
|
|
1538
|
+
var TsBitmap = class _TsBitmap {
|
|
1539
|
+
#keys;
|
|
1540
|
+
#conts;
|
|
1541
|
+
#size;
|
|
1542
|
+
constructor(keys, conts, size) {
|
|
1543
|
+
this.#keys = keys;
|
|
1544
|
+
this.#conts = conts;
|
|
1545
|
+
this.#size = size;
|
|
347
1546
|
}
|
|
348
1547
|
static empty() {
|
|
349
|
-
return new
|
|
1548
|
+
return new _TsBitmap([], [], 0);
|
|
350
1549
|
}
|
|
351
1550
|
static fromValues(values) {
|
|
352
|
-
|
|
1551
|
+
const bitmap = _TsBitmap.empty();
|
|
1552
|
+
bitmap.addMany(values);
|
|
1553
|
+
return bitmap;
|
|
353
1554
|
}
|
|
354
1555
|
/**
|
|
355
|
-
* Cap the size, check the structure, then
|
|
356
|
-
*
|
|
357
|
-
* decode — the native addon is never handed unbounded, malformed or unsafe-format input. With `whole`, bytes
|
|
358
|
-
* after the bitmap's last container are refused too; without it they are ignored, as the native decoder ignores
|
|
359
|
-
* them.
|
|
1556
|
+
* Cap the size, check the structure, then build the containers. With `whole`, bytes after the last container are
|
|
1557
|
+
* refused too; without it they are ignored.
|
|
360
1558
|
*
|
|
361
|
-
*
|
|
362
|
-
*
|
|
363
|
-
* values out of order, overlapping runs, a cardinality that disagrees with the bits) decode into a bitmap
|
|
364
|
-
* whose `maximum()`, `has()` and `size` are wrong, and some of those shapes crash the process when used.
|
|
1559
|
+
* @throws {IntegrityError} if the input exceeds `maxBytes`, is not a well-formed portable bitmap, or (with `whole`)
|
|
1560
|
+
* has bytes after it.
|
|
365
1561
|
*/
|
|
366
1562
|
static safeDeserialize(bytes, maxBytes, options = {}) {
|
|
367
1563
|
if (bytes.length > maxBytes) {
|
|
368
|
-
throw new
|
|
1564
|
+
throw new IntegrityError3(`serialized bitmap is ${bytes.length}B, exceeds cap ${maxBytes}B`);
|
|
369
1565
|
}
|
|
370
|
-
const end =
|
|
1566
|
+
const { keys, conts, end } = decodeContainers(bytes);
|
|
371
1567
|
if (options.whole === true && end !== bytes.byteLength) {
|
|
372
|
-
throw
|
|
373
|
-
`portable roaring: ${bytes.byteLength - end} bytes follow the bitmap's last container, which ends at byte ${end}. One buffer holds one bitmap: to load several as one segment, combine them first (RoaringBitmap32.orMany) and serialize the result.`
|
|
374
|
-
);
|
|
375
|
-
}
|
|
376
|
-
try {
|
|
377
|
-
return new _SafeBitmap(RoaringBitmap32.deserialize(bytes, DeserializationFormat.portable));
|
|
378
|
-
} catch (err) {
|
|
379
|
-
throw new IntegrityError2(`failed to deserialize bitmap: ${err.message}`);
|
|
1568
|
+
throw trailingBytes(bytes.byteLength, end);
|
|
380
1569
|
}
|
|
1570
|
+
let size = 0;
|
|
1571
|
+
for (let i = 0; i < conts.length; i++) size += conts[i].card;
|
|
1572
|
+
return new _TsBitmap(keys, conts, size);
|
|
381
1573
|
}
|
|
382
1574
|
serialize() {
|
|
383
|
-
return this
|
|
1575
|
+
return serializeContainers(this.#keys, this.#conts);
|
|
384
1576
|
}
|
|
385
|
-
/**
|
|
386
|
-
* Convert containers to run-encoding where that is smaller. Representation only — membership is untouched, and
|
|
387
|
-
* the portable format still round-trips through {@link RoaringCodec.safeDeserialize}.
|
|
388
|
-
*
|
|
389
|
-
* Roaring's third container type is a RUN, and no implementation selects it on its own: it takes an explicit
|
|
390
|
-
* `runOptimize()` pass. Nothing here made that call, so run-shaped ids paid array or bitset prices — measured
|
|
391
|
-
* at **570×** for a contiguous 1M-id range (128.1 KiB → 0.2 KiB) and **63×** for a 2,000-run shape
|
|
392
|
-
* (536.5 KiB → 8.5 KiB). Sparse ids come out byte-identical, so this is never a losing trade; roaring keeps
|
|
393
|
-
* whichever encoding is smaller per container.
|
|
394
|
-
*
|
|
395
|
-
* Those two factors are THIS CALL's own before/after on the same ids. They are not the ones the site quotes
|
|
396
|
-
* (543× and 63×) — those compare the optimized encoding against the best *fixed* representation at its floor,
|
|
397
|
-
* a different baseline that happens to land near 63× on the run shape too. `pnpm bench:encoding` prints both
|
|
398
|
-
* columns; don't carry a figure between them without checking which denominator it had.
|
|
399
|
-
*
|
|
400
|
-
* Called only when writing an immutable objects generation — see {@link CodecBitmap.optimize} for why the read
|
|
401
|
-
* path deliberately does not.
|
|
402
|
-
*
|
|
403
|
-
* CANONICAL, which `runOptimize()` alone is not. Where a container's run and array encodings are the same size
|
|
404
|
-
* (cardinality = 2 × runs + 1: three values in one run, five in two), CRoaring keeps whichever kind the
|
|
405
|
-
* container already has. A chunk built from ids starts as an array and stays one; the same set reached through
|
|
406
|
-
* `addRange`, an earlier `runOptimize()` or an operation over run containers is a run, and serializes to other
|
|
407
|
-
* bytes. Undoing run compression first starts every container where one built from ids starts, so the bytes
|
|
408
|
-
* depend on membership alone. On a bitmap built from ids there is nothing to undo.
|
|
409
|
-
*/
|
|
1577
|
+
/** Re-encode each container canonically; membership is untouched. */
|
|
410
1578
|
optimize() {
|
|
411
|
-
this
|
|
412
|
-
|
|
1579
|
+
const conts = this.#conts;
|
|
1580
|
+
for (let i = 0; i < conts.length; i++) conts[i] = optimize(conts[i]);
|
|
413
1581
|
}
|
|
414
1582
|
/**
|
|
415
|
-
*
|
|
416
|
-
*
|
|
417
|
-
*
|
|
418
|
-
*
|
|
419
|
-
*
|
|
1583
|
+
* The set as storage chunks: each payload is the portable bytes of a one-container bitmap holding that chunk's low 16
|
|
1584
|
+
* bits, optimized the way {@link optimize} does. Nothing is built until a chunk is asked for, so a writer that yields
|
|
1585
|
+
* between chunks runs this in slices. The call snapshots the containers and marks each shared, so a change to the
|
|
1586
|
+
* bitmap while the chunks are read copies a container instead of altering what the chunks will say. The bitmap's own
|
|
1587
|
+
* containers are not optimized by it.
|
|
420
1588
|
*/
|
|
421
1589
|
encodeChunks() {
|
|
422
|
-
this.
|
|
423
|
-
|
|
1590
|
+
const keys = this.#keys.slice();
|
|
1591
|
+
const conts = this.#conts.slice();
|
|
1592
|
+
for (let i = 0; i < conts.length; i++) conts[i].shared = true;
|
|
1593
|
+
return {
|
|
1594
|
+
*[Symbol.iterator]() {
|
|
1595
|
+
for (let i = 0; i < conts.length; i++) {
|
|
1596
|
+
const c = optimize(conts[i]);
|
|
1597
|
+
yield {
|
|
1598
|
+
chunkKey: keys[i],
|
|
1599
|
+
payload: serializeContainers([0], [c]),
|
|
1600
|
+
cardinality: c.card
|
|
1601
|
+
};
|
|
1602
|
+
}
|
|
1603
|
+
}
|
|
1604
|
+
};
|
|
424
1605
|
}
|
|
425
|
-
/**
|
|
426
|
-
* Largest value, or `undefined` when empty. O(1) — roaring reads it off the last container, so the engine's
|
|
427
|
-
* per-chunk range assertion costs one call per chunk rather than a walk per id. The last container holds the
|
|
428
|
-
* largest value only because {@link SafeBitmap.safeDeserialize} refuses bytes whose containers or values are
|
|
429
|
-
* out of order.
|
|
430
|
-
*/
|
|
431
1606
|
maximum() {
|
|
432
|
-
|
|
1607
|
+
const last = this.#conts.length - 1;
|
|
1608
|
+
if (last < 0) return void 0;
|
|
1609
|
+
return this.#keys[last] * 65536 + containerMax(this.#conts[last]);
|
|
433
1610
|
}
|
|
434
1611
|
add(value) {
|
|
435
|
-
|
|
1612
|
+
checkedId(value);
|
|
1613
|
+
const key = value >>> 16;
|
|
1614
|
+
const low = value & 65535;
|
|
1615
|
+
const at = lowerBound2(this.#keys, key);
|
|
1616
|
+
const found = this.#keys[at] === key;
|
|
1617
|
+
if (!found) {
|
|
1618
|
+
this.#insert(at, key, arrayContainer(Uint16Array.of(low), 1));
|
|
1619
|
+
this.#size++;
|
|
1620
|
+
return;
|
|
1621
|
+
}
|
|
1622
|
+
const before = this.#conts[at];
|
|
1623
|
+
const after = containerAdd(before, low);
|
|
1624
|
+
this.#conts[at] = after;
|
|
1625
|
+
this.#size += after.card - before.card;
|
|
436
1626
|
}
|
|
1627
|
+
/**
|
|
1628
|
+
* Add the ids. They are grouped by key in ascending order, so each container is touched once, a key already held is
|
|
1629
|
+
* merged where it is, and the new keys are put in with one pass over the key list however many there are.
|
|
1630
|
+
*/
|
|
437
1631
|
addMany(values) {
|
|
438
|
-
|
|
1632
|
+
const ids = sortedIds(collect(values), !(values instanceof Uint32Array));
|
|
1633
|
+
const fresh = [];
|
|
1634
|
+
let at = 0;
|
|
1635
|
+
for (let i = 0; i < ids.length; ) {
|
|
1636
|
+
const key = ids[i] >>> 16;
|
|
1637
|
+
let end = i + 1;
|
|
1638
|
+
while (end < ids.length && ids[end] >>> 16 === key) end++;
|
|
1639
|
+
const group = fromSortedIds(ids, i, end);
|
|
1640
|
+
i = end;
|
|
1641
|
+
at = gallopKeys(this.#keys, key, at);
|
|
1642
|
+
if (this.#keys[at] === key) {
|
|
1643
|
+
const before = this.#conts[at];
|
|
1644
|
+
const after = containerOr(before, group, !before.shared);
|
|
1645
|
+
this.#conts[at] = after;
|
|
1646
|
+
this.#size += after.card - before.card;
|
|
1647
|
+
} else {
|
|
1648
|
+
fresh.push({ key, group });
|
|
1649
|
+
this.#size += group.card;
|
|
1650
|
+
}
|
|
1651
|
+
}
|
|
1652
|
+
if (fresh.length > 0) this.#insertAll(fresh);
|
|
439
1653
|
}
|
|
440
1654
|
remove(value) {
|
|
441
|
-
|
|
1655
|
+
if (!isId(value)) return;
|
|
1656
|
+
const key = value >>> 16;
|
|
1657
|
+
const at = lowerBound2(this.#keys, key);
|
|
1658
|
+
if (this.#keys[at] !== key) return;
|
|
1659
|
+
const before = this.#conts[at];
|
|
1660
|
+
const after = containerRemove(before, value & 65535);
|
|
1661
|
+
if (after === null) {
|
|
1662
|
+
this.#keys.splice(at, 1);
|
|
1663
|
+
this.#conts.splice(at, 1);
|
|
1664
|
+
this.#size -= before.card;
|
|
1665
|
+
return;
|
|
1666
|
+
}
|
|
1667
|
+
this.#conts[at] = after;
|
|
1668
|
+
this.#size += after.card - before.card;
|
|
442
1669
|
}
|
|
1670
|
+
/** Remove the ids (anything that is not an id is ignored), grouped by key; the keys left empty go in one pass. */
|
|
443
1671
|
removeMany(values) {
|
|
444
|
-
|
|
1672
|
+
const ids = sortedIds(collectLenient(values), true);
|
|
1673
|
+
const keys = this.#keys;
|
|
1674
|
+
const conts = this.#conts;
|
|
1675
|
+
let at = 0;
|
|
1676
|
+
let emptied = 0;
|
|
1677
|
+
for (let i = 0; i < ids.length; ) {
|
|
1678
|
+
const key = ids[i] >>> 16;
|
|
1679
|
+
let end = i + 1;
|
|
1680
|
+
while (end < ids.length && ids[end] >>> 16 === key) end++;
|
|
1681
|
+
const from = i;
|
|
1682
|
+
i = end;
|
|
1683
|
+
at = gallopKeys(keys, key, at);
|
|
1684
|
+
if (keys[at] !== key) continue;
|
|
1685
|
+
const before = conts[at];
|
|
1686
|
+
if (before.card === 0) continue;
|
|
1687
|
+
const after = containerAndNot(before, fromSortedIds(ids, from, end), !before.shared);
|
|
1688
|
+
this.#size -= before.card - (after === null ? 0 : after.card);
|
|
1689
|
+
if (after === null) {
|
|
1690
|
+
conts[at] = EMPTIED;
|
|
1691
|
+
emptied++;
|
|
1692
|
+
} else {
|
|
1693
|
+
conts[at] = after;
|
|
1694
|
+
}
|
|
1695
|
+
}
|
|
1696
|
+
if (emptied > 0) this.#dropEmptied();
|
|
445
1697
|
}
|
|
446
1698
|
has(value) {
|
|
447
|
-
|
|
1699
|
+
if (!isId(value)) return false;
|
|
1700
|
+
const key = value >>> 16;
|
|
1701
|
+
const at = lowerBound2(this.#keys, key);
|
|
1702
|
+
return this.#keys[at] === key && containerHas(this.#conts[at], value & 65535);
|
|
448
1703
|
}
|
|
449
1704
|
get size() {
|
|
450
|
-
return this
|
|
1705
|
+
return this.#size;
|
|
451
1706
|
}
|
|
452
1707
|
get isEmpty() {
|
|
453
|
-
return this
|
|
1708
|
+
return this.#size === 0;
|
|
454
1709
|
}
|
|
455
1710
|
clone() {
|
|
456
|
-
|
|
1711
|
+
const conts = new Array(this.#conts.length);
|
|
1712
|
+
for (let i = 0; i < conts.length; i++) {
|
|
1713
|
+
const c = this.#conts[i];
|
|
1714
|
+
c.shared = true;
|
|
1715
|
+
conts[i] = c;
|
|
1716
|
+
}
|
|
1717
|
+
return new _TsBitmap(this.#keys.slice(), conts, this.#size);
|
|
457
1718
|
}
|
|
458
|
-
// The binary set ops take the `CodecBitmap` interface type (per the seam), but a single store is
|
|
459
|
-
// single-codec (homogeneity contract), so `other` is always a `SafeBitmap` here — reach its private
|
|
460
|
-
// `bitmap` (accessible on same-class instances) for the native op.
|
|
461
|
-
/** In-place union: `this = this ∪ other`. */
|
|
462
1719
|
orInPlace(other) {
|
|
463
|
-
this
|
|
1720
|
+
this.#combine(_TsBitmap.#of(other), OR);
|
|
464
1721
|
}
|
|
465
|
-
/** In-place difference: `this = this \ other`. */
|
|
466
|
-
andNotInPlace(other) {
|
|
467
|
-
this.bitmap.andNotInPlace(other.bitmap);
|
|
468
|
-
}
|
|
469
|
-
/** In-place intersection: `this = this ∩ other`. */
|
|
470
1722
|
andInPlace(other) {
|
|
471
|
-
this
|
|
1723
|
+
this.#combine(_TsBitmap.#of(other), AND);
|
|
1724
|
+
}
|
|
1725
|
+
andNotInPlace(other) {
|
|
1726
|
+
this.#combine(_TsBitmap.#of(other), AND_NOT);
|
|
472
1727
|
}
|
|
473
|
-
/** Ascending iterator over the set values. */
|
|
474
1728
|
[Symbol.iterator]() {
|
|
475
|
-
return this
|
|
1729
|
+
return new BitmapIterator(this.#keys, this.#conts);
|
|
476
1730
|
}
|
|
477
1731
|
toArray() {
|
|
478
|
-
return this.
|
|
1732
|
+
return Array.from(this.toUint32Array());
|
|
479
1733
|
}
|
|
480
|
-
/** The
|
|
1734
|
+
/** The ids as a new ascending `Uint32Array`. */
|
|
481
1735
|
toUint32Array() {
|
|
482
|
-
|
|
1736
|
+
const out = new Uint32Array(this.#size);
|
|
1737
|
+
let at = 0;
|
|
1738
|
+
for (let i = 0; i < this.#conts.length; i++) {
|
|
1739
|
+
at = appendIds(this.#conts[i], out, at, this.#keys[i] * 65536);
|
|
1740
|
+
}
|
|
1741
|
+
return out;
|
|
483
1742
|
}
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
empty: () => SafeBitmap.empty(),
|
|
490
|
-
fromValues: (values) => SafeBitmap.fromValues(values),
|
|
491
|
-
safeDeserialize: (bytes, maxBytes, options) => SafeBitmap.safeDeserialize(bytes, maxBytes, options),
|
|
492
|
-
owns: (bitmap) => bitmap instanceof SafeBitmap
|
|
493
|
-
};
|
|
494
|
-
var ReadonlyRoaringView = class {
|
|
495
|
-
#bitmap;
|
|
496
|
-
constructor(bitmap) {
|
|
497
|
-
this.#bitmap = bitmap;
|
|
1743
|
+
static #of(other) {
|
|
1744
|
+
if (!(other instanceof _TsBitmap)) {
|
|
1745
|
+
throw new ValidationError2("a TypeScript roaring bitmap combines only with another one");
|
|
1746
|
+
}
|
|
1747
|
+
return other;
|
|
498
1748
|
}
|
|
499
|
-
|
|
500
|
-
|
|
1749
|
+
#insert(at, key, container) {
|
|
1750
|
+
if (at === this.#keys.length) {
|
|
1751
|
+
this.#keys.push(key);
|
|
1752
|
+
this.#conts.push(container);
|
|
1753
|
+
} else {
|
|
1754
|
+
this.#keys.splice(at, 0, key);
|
|
1755
|
+
this.#conts.splice(at, 0, container);
|
|
1756
|
+
}
|
|
501
1757
|
}
|
|
502
|
-
|
|
503
|
-
|
|
1758
|
+
/** Put the new keys, ascending and none held, in: after the last key by pushing, else in one merge pass. */
|
|
1759
|
+
#insertAll(fresh) {
|
|
1760
|
+
const keys = this.#keys;
|
|
1761
|
+
const conts = this.#conts;
|
|
1762
|
+
if (keys.length === 0 || keys[keys.length - 1] < fresh[0].key) {
|
|
1763
|
+
for (const { key, group } of fresh) {
|
|
1764
|
+
keys.push(key);
|
|
1765
|
+
conts.push(group);
|
|
1766
|
+
}
|
|
1767
|
+
return;
|
|
1768
|
+
}
|
|
1769
|
+
const outKeys = [];
|
|
1770
|
+
const outConts = [];
|
|
1771
|
+
let i = 0;
|
|
1772
|
+
let j = 0;
|
|
1773
|
+
while (i < keys.length || j < fresh.length) {
|
|
1774
|
+
if (j === fresh.length || i < keys.length && keys[i] < fresh[j].key) {
|
|
1775
|
+
outKeys.push(keys[i]);
|
|
1776
|
+
outConts.push(conts[i++]);
|
|
1777
|
+
} else {
|
|
1778
|
+
const next = fresh[j++];
|
|
1779
|
+
outKeys.push(next.key);
|
|
1780
|
+
outConts.push(next.group);
|
|
1781
|
+
}
|
|
1782
|
+
}
|
|
1783
|
+
this.#keys = outKeys;
|
|
1784
|
+
this.#conts = outConts;
|
|
1785
|
+
}
|
|
1786
|
+
/** Remove the keys whose container was emptied by {@link removeMany}, in one pass. */
|
|
1787
|
+
#dropEmptied() {
|
|
1788
|
+
let kept = 0;
|
|
1789
|
+
for (let i = 0; i < this.#conts.length; i++) {
|
|
1790
|
+
if (this.#conts[i] === EMPTIED) continue;
|
|
1791
|
+
this.#keys[kept] = this.#keys[i];
|
|
1792
|
+
this.#conts[kept++] = this.#conts[i];
|
|
1793
|
+
}
|
|
1794
|
+
this.#keys.length = kept;
|
|
1795
|
+
this.#conts.length = kept;
|
|
504
1796
|
}
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
1797
|
+
/**
|
|
1798
|
+
* Walk both key lists and rebuild this one: where both hold a key, the combine of the two containers; where only this
|
|
1799
|
+
* does, its container, unless the operation is an intersection; where only `that` does, a copy of its container for a
|
|
1800
|
+
* union and nothing otherwise. A combine that leaves no value drops the key. An intersection jumps over a stretch of
|
|
1801
|
+
* keys the other side lacks by doubling steps, so a few keys against many cost the few.
|
|
1802
|
+
*/
|
|
1803
|
+
#combine(that, op) {
|
|
1804
|
+
const a = this.#keys;
|
|
1805
|
+
const b = that.#keys;
|
|
1806
|
+
const ca = this.#conts;
|
|
1807
|
+
const cb = that.#conts;
|
|
1808
|
+
const keys = [];
|
|
1809
|
+
const conts = [];
|
|
1810
|
+
let size = 0;
|
|
1811
|
+
let i = 0;
|
|
1812
|
+
let j = 0;
|
|
1813
|
+
while (i < a.length && j < b.length) {
|
|
1814
|
+
const ka = a[i];
|
|
1815
|
+
const kb = b[j];
|
|
1816
|
+
if (ka === kb) {
|
|
1817
|
+
const c = combineContainers(op, ca[i++], cb[j++]);
|
|
1818
|
+
if (c !== null) {
|
|
1819
|
+
keys.push(ka);
|
|
1820
|
+
conts.push(c);
|
|
1821
|
+
size += c.card;
|
|
1822
|
+
}
|
|
1823
|
+
} else if (ka < kb) {
|
|
1824
|
+
if (op === AND) {
|
|
1825
|
+
i = gallopKeys(a, kb, i + 1);
|
|
1826
|
+
} else {
|
|
1827
|
+
keys.push(ka);
|
|
1828
|
+
conts.push(ca[i]);
|
|
1829
|
+
size += ca[i++].card;
|
|
1830
|
+
}
|
|
1831
|
+
} else if (op === AND) {
|
|
1832
|
+
j = gallopKeys(b, ka, j + 1);
|
|
1833
|
+
} else {
|
|
1834
|
+
if (op === OR) {
|
|
1835
|
+
keys.push(kb);
|
|
1836
|
+
conts.push(cloneContainer(cb[j]));
|
|
1837
|
+
size += cb[j].card;
|
|
1838
|
+
}
|
|
1839
|
+
j++;
|
|
1840
|
+
}
|
|
1841
|
+
}
|
|
1842
|
+
if (op !== AND) {
|
|
1843
|
+
for (; i < a.length; i++) {
|
|
1844
|
+
keys.push(a[i]);
|
|
1845
|
+
conts.push(ca[i]);
|
|
1846
|
+
size += ca[i].card;
|
|
1847
|
+
}
|
|
515
1848
|
}
|
|
516
|
-
|
|
1849
|
+
if (op === OR) {
|
|
1850
|
+
for (; j < b.length; j++) {
|
|
1851
|
+
keys.push(b[j]);
|
|
1852
|
+
conts.push(cloneContainer(cb[j]));
|
|
1853
|
+
size += cb[j].card;
|
|
1854
|
+
}
|
|
1855
|
+
}
|
|
1856
|
+
this.#keys = keys;
|
|
1857
|
+
this.#conts = conts;
|
|
1858
|
+
this.#size = size;
|
|
517
1859
|
}
|
|
518
1860
|
};
|
|
1861
|
+
var EMPTIED = arrayContainer(new Uint16Array(0), 0);
|
|
1862
|
+
var tsRoaringCodec = {
|
|
1863
|
+
empty: () => TsBitmap.empty(),
|
|
1864
|
+
fromValues: (values) => TsBitmap.fromValues(values),
|
|
1865
|
+
safeDeserialize: (bytes, maxBytes, options) => TsBitmap.safeDeserialize(bytes, maxBytes, options),
|
|
1866
|
+
owns: (bitmap) => bitmap instanceof TsBitmap,
|
|
1867
|
+
intersectSmallestFirst: true
|
|
1868
|
+
};
|
|
1869
|
+
|
|
1870
|
+
// src/roaring-codec.ts
|
|
1871
|
+
function bitmapAsLoadInput(input) {
|
|
1872
|
+
if (typeof input !== "object" || input === null) return input;
|
|
1873
|
+
const tag = Object.prototype.toString.call(input).slice(8, -1);
|
|
1874
|
+
if (tag === "Uint8Array" || tag === "Uint8ClampedArray") return input;
|
|
1875
|
+
return Symbol.iterator in input && typeof input.serialize === "function" ? { bitmap: input } : input;
|
|
1876
|
+
}
|
|
1877
|
+
var activeCodec = tsRoaringCodec;
|
|
1878
|
+
function flagshipCodec() {
|
|
1879
|
+
return activeCodec;
|
|
1880
|
+
}
|
|
519
1881
|
|
|
520
1882
|
// src/system-clock.ts
|
|
521
1883
|
var SystemClock = class {
|
|
@@ -655,7 +2017,7 @@ import {
|
|
|
655
2017
|
DEFAULT_RETRY_POLICY,
|
|
656
2018
|
NOOP_METRICS,
|
|
657
2019
|
RetryingStorageChunkSource,
|
|
658
|
-
ValidationError as
|
|
2020
|
+
ValidationError as ValidationError4,
|
|
659
2021
|
isStorageBackend
|
|
660
2022
|
} from "@cloudbitmaps/core";
|
|
661
2023
|
function resolveRetryPolicy(partial) {
|
|
@@ -679,7 +2041,7 @@ function wireStore(options, clock, rng, metrics) {
|
|
|
679
2041
|
if (options.retry !== false) {
|
|
680
2042
|
const { onRetry: userOnRetry, ...ov } = options.retry ?? {};
|
|
681
2043
|
if (userOnRetry !== void 0 && typeof userOnRetry !== "function") {
|
|
682
|
-
throw new
|
|
2044
|
+
throw new ValidationError4("retry.onRetry must be a function");
|
|
683
2045
|
}
|
|
684
2046
|
retryOptions = {
|
|
685
2047
|
clock,
|
|
@@ -710,7 +2072,7 @@ function wireStore(options, clock, rng, metrics) {
|
|
|
710
2072
|
function resolveStorageSource(options, clock) {
|
|
711
2073
|
const storage = options.storage;
|
|
712
2074
|
if (storage === null || typeof storage !== "object") {
|
|
713
|
-
throw new
|
|
2075
|
+
throw new ValidationError4(
|
|
714
2076
|
"`storage` must be a StorageBackend, an IStorageDriver, or a StorageChunkSource"
|
|
715
2077
|
);
|
|
716
2078
|
}
|
|
@@ -720,14 +2082,14 @@ function resolveStorageSource(options, clock) {
|
|
|
720
2082
|
const hasPutImmutable = typeof storage.putImmutable === "function";
|
|
721
2083
|
const isBackend = isStorageBackend(storage);
|
|
722
2084
|
if (isBackend && (hasGetChunk || hasPutImmutable)) {
|
|
723
|
-
throw new
|
|
2085
|
+
throw new ValidationError4(
|
|
724
2086
|
`\`storage\` is a StorageBackend that also exposes ${hasGetChunk ? "`getChunk`" : "`putImmutable`"} \u2014 ambiguous. A backend must not also be a driver or a source; pass whichever one you mean.`
|
|
725
2087
|
);
|
|
726
2088
|
}
|
|
727
2089
|
const hasStorageHalf = isObject(asBackend.storage);
|
|
728
2090
|
const hasRegistryHalf = isObject(asBackend.registry);
|
|
729
2091
|
if (!isBackend && hasPutImmutable && hasRegistryHalf) {
|
|
730
|
-
throw new
|
|
2092
|
+
throw new ValidationError4(
|
|
731
2093
|
"`storage` looks like a driver that also carries a `registry`. Passed as a bare driver it would have no pointer at all \u2014 generations would resolve by list-scan, so reads could serve a generation that was written but never published. If you meant a backend, use a backend class \u2014 S3Storage, GcsStorage, AzureBlobStorage, LocalFsStorage or MemoryStorage \u2014 or, to pair a driver of your own with a registry, brand the pair with `brandAsBackend` from `@cloudbitmaps/core/driver-kit`."
|
|
732
2094
|
);
|
|
733
2095
|
}
|
|
@@ -736,11 +2098,11 @@ function resolveStorageSource(options, clock) {
|
|
|
736
2098
|
const registryOk = typeof asBackend.registry.compareAndSwap === "function";
|
|
737
2099
|
if (!storageOk || !registryOk) {
|
|
738
2100
|
const bad = !storageOk ? "`storage` half is not an IStorageDriver (no `putImmutable`)" : "`registry` half is not an IRegistryDriver (no `compareAndSwap`)";
|
|
739
|
-
throw new
|
|
2101
|
+
throw new ValidationError4(
|
|
740
2102
|
"`storage` looks like a backend but its " + bad + " \u2014 use a backend class, or brand a pair of drivers with `brandAsBackend` from `@cloudbitmaps/core/driver-kit`."
|
|
741
2103
|
);
|
|
742
2104
|
}
|
|
743
|
-
throw new
|
|
2105
|
+
throw new ValidationError4(
|
|
744
2106
|
"`storage` must be a backend \u2014 S3Storage, GcsStorage, AzureBlobStorage, LocalFsStorage or MemoryStorage. An object with `.storage` and `.registry` is not one: a backend builds both halves from a single bucket and prefix, so they cannot disagree, and hand-assembling them re-opens exactly that mismatch \u2014 a store whose pointer and generations live in different places reads as empty rather than failing. A driver author who genuinely wants halves of their own \u2014 an instrumented driver, a registry in a database you already run \u2014 brands the pair with `brandAsBackend` from `@cloudbitmaps/core/driver-kit`, which is taking on that they agree."
|
|
745
2107
|
);
|
|
746
2108
|
}
|
|
@@ -761,18 +2123,18 @@ function resolveStorageSource(options, clock) {
|
|
|
761
2123
|
};
|
|
762
2124
|
}
|
|
763
2125
|
if (hasGetChunk && hasPutImmutable) {
|
|
764
|
-
throw new
|
|
2126
|
+
throw new ValidationError4(
|
|
765
2127
|
"`storage` exposes both `getChunk` and `putImmutable` \u2014 ambiguous; pass a StorageBackend, an IStorageDriver, or a StorageChunkSource, not a hybrid"
|
|
766
2128
|
);
|
|
767
2129
|
}
|
|
768
2130
|
if (!hasGetChunk && !hasPutImmutable) {
|
|
769
|
-
throw new
|
|
2131
|
+
throw new ValidationError4(
|
|
770
2132
|
"`storage` must be a StorageBackend, an IStorageDriver, or a StorageChunkSource"
|
|
771
2133
|
);
|
|
772
2134
|
}
|
|
773
2135
|
if (hasGetChunk) {
|
|
774
2136
|
if (options.encryption?.keystore !== void 0 || options.encryption?.required === true) {
|
|
775
|
-
throw new
|
|
2137
|
+
throw new ValidationError4(
|
|
776
2138
|
"keystore/requireEncryption apply only when the store builds its own read path: a StorageChunkSource of your own reads an encrypted segment by itself, if it must; to have the store decrypt, pass a backend"
|
|
777
2139
|
);
|
|
778
2140
|
}
|
|
@@ -794,32 +2156,32 @@ function resolveStorageSource(options, clock) {
|
|
|
794
2156
|
}
|
|
795
2157
|
|
|
796
2158
|
// src/options.ts
|
|
797
|
-
import { ValidationError as
|
|
2159
|
+
import { ValidationError as ValidationError5 } from "@cloudbitmaps/core";
|
|
798
2160
|
var keysOf = () => (keys) => keys;
|
|
799
2161
|
var kindOf = (v) => v === null ? "null" : Array.isArray(v) ? "an array" : `a ${typeof v}`;
|
|
800
2162
|
function optionsError(options, op, known, booleans = [], misplaced = []) {
|
|
801
2163
|
if (options === void 0 || options === null) return void 0;
|
|
802
2164
|
if (typeof options !== "object" || Array.isArray(options)) {
|
|
803
|
-
return new
|
|
2165
|
+
return new ValidationError5(`${op}: options must be an object; got ${kindOf(options)}`);
|
|
804
2166
|
}
|
|
805
2167
|
const bag = options;
|
|
806
2168
|
const unknown = Object.keys(bag).filter((k) => !known.includes(k) && bag[k] !== void 0);
|
|
807
2169
|
for (const k of misplaced) if (!unknown.includes(k) && bag[k] !== void 0) unknown.push(k);
|
|
808
2170
|
if (unknown.length > 0) {
|
|
809
|
-
return new
|
|
2171
|
+
return new ValidationError5(
|
|
810
2172
|
`${op}: unknown option${unknown.length > 1 ? "s" : ""} ${unknown.map((k) => `"${k}"`).join(", ")}; it takes { ${known.join(", ")} }`
|
|
811
2173
|
);
|
|
812
2174
|
}
|
|
813
2175
|
const audit = bag.audit;
|
|
814
2176
|
if (audit !== void 0 && audit !== null && typeof audit.onEvent !== "function") {
|
|
815
|
-
return new
|
|
2177
|
+
return new ValidationError5(
|
|
816
2178
|
`${op}: audit must be a sink with an onEvent(event) method, such as a RecordingAuditSink`
|
|
817
2179
|
);
|
|
818
2180
|
}
|
|
819
2181
|
for (const name of booleans) {
|
|
820
2182
|
const v = bag[name];
|
|
821
2183
|
if (v !== void 0 && typeof v !== "boolean") {
|
|
822
|
-
return new
|
|
2184
|
+
return new ValidationError5(`${op}: \`${name}\` must be a boolean; got ${kindOf(v)}`);
|
|
823
2185
|
}
|
|
824
2186
|
}
|
|
825
2187
|
return void 0;
|
|
@@ -844,9 +2206,9 @@ import {
|
|
|
844
2206
|
excludingReservedRows as excludingReservedRows2,
|
|
845
2207
|
readRetentionPolicy,
|
|
846
2208
|
CloudRoaringError,
|
|
847
|
-
ValidationError as
|
|
2209
|
+
ValidationError as ValidationError7,
|
|
848
2210
|
WriteConflictError as WriteConflictError2,
|
|
849
|
-
IntegrityError as
|
|
2211
|
+
IntegrityError as IntegrityError4,
|
|
850
2212
|
NotFoundError as NotFoundError2,
|
|
851
2213
|
UnsupportedError as UnsupportedError3,
|
|
852
2214
|
CapabilityError,
|
|
@@ -868,7 +2230,7 @@ var SystemRng = class {
|
|
|
868
2230
|
};
|
|
869
2231
|
function validateRef(ref, verb) {
|
|
870
2232
|
if (typeof ref !== "object" || ref === null) {
|
|
871
|
-
throw new
|
|
2233
|
+
throw new ValidationError6(
|
|
872
2234
|
"a segment ref is an object such as { segment: 'name' }; store.segment() takes the bare name"
|
|
873
2235
|
);
|
|
874
2236
|
}
|
|
@@ -889,7 +2251,7 @@ function validateConcurrency(concurrency) {
|
|
|
889
2251
|
function requireScope(options, op) {
|
|
890
2252
|
if (options.namespace !== void 0) {
|
|
891
2253
|
if (typeof options.namespace !== "string") {
|
|
892
|
-
throw new
|
|
2254
|
+
throw new ValidationError6(
|
|
893
2255
|
`${op}: namespace must be a string; got ${kindOf(options.namespace)}`
|
|
894
2256
|
);
|
|
895
2257
|
}
|
|
@@ -897,12 +2259,12 @@ function requireScope(options, op) {
|
|
|
897
2259
|
}
|
|
898
2260
|
refuseReservedNamespace(options.namespace);
|
|
899
2261
|
if (options.namespace !== void 0 && options.allNamespaces === true) {
|
|
900
|
-
throw new
|
|
2262
|
+
throw new ValidationError6(
|
|
901
2263
|
`${op}: pass a namespace or { allNamespaces: true }, not both: with both, it is unclear whether to scan one namespace or every one`
|
|
902
2264
|
);
|
|
903
2265
|
}
|
|
904
2266
|
if (options.namespace === void 0 && options.allNamespaces !== true) {
|
|
905
|
-
throw new
|
|
2267
|
+
throw new ValidationError6(
|
|
906
2268
|
`${op} scans the global id space across all namespaces \u2014 pass an explicit \`namespace\`, or \`{ allNamespaces: true }\` to intentionally sweep the whole fleet`
|
|
907
2269
|
);
|
|
908
2270
|
}
|
|
@@ -1010,16 +2372,16 @@ var originOf;
|
|
|
1010
2372
|
function assertOneStore(verb, role, h, origin) {
|
|
1011
2373
|
if (h instanceof Segment) {
|
|
1012
2374
|
if (originOf(h) === origin) return;
|
|
1013
|
-
throw new
|
|
2375
|
+
throw new ValidationError6(
|
|
1014
2376
|
`${verb}: ${role} belongs to another store; combine segments of one store: open each with this store's segment()`
|
|
1015
2377
|
);
|
|
1016
2378
|
}
|
|
1017
2379
|
if (typeof h === "object" && h !== null && h[SEGMENT_BRAND] === true) {
|
|
1018
|
-
throw new
|
|
2380
|
+
throw new ValidationError6(
|
|
1019
2381
|
`${verb}: ${role} comes from another installed copy of @cloudbitmaps/roaring, so it belongs to another store; install one copy and combine segments of one store`
|
|
1020
2382
|
);
|
|
1021
2383
|
}
|
|
1022
|
-
throw new
|
|
2384
|
+
throw new ValidationError6(`${verb}: ${role} must be a segment from this store's segment()`);
|
|
1023
2385
|
}
|
|
1024
2386
|
var MATERIALIZE_MANY_KEYS = [
|
|
1025
2387
|
"operands",
|
|
@@ -1109,7 +2471,7 @@ var CloudRoaring = class _CloudRoaring {
|
|
|
1109
2471
|
*/
|
|
1110
2472
|
static rejectUnknownOptions(options) {
|
|
1111
2473
|
if (options === null || options === void 0 || typeof options !== "object") {
|
|
1112
|
-
throw new
|
|
2474
|
+
throw new ValidationError6(
|
|
1113
2475
|
"CloudRoaring needs an options object with a `storage` key \u2014 got " + (options === null ? "null" : typeof options)
|
|
1114
2476
|
);
|
|
1115
2477
|
}
|
|
@@ -1127,7 +2489,7 @@ var CloudRoaring = class _CloudRoaring {
|
|
|
1127
2489
|
const tag = Object.prototype.toString.call(value).slice(8, -1);
|
|
1128
2490
|
if (typeof value !== "object" || value === null || NOT_A_GROUP[tag] !== void 0) {
|
|
1129
2491
|
const got = typeof value !== "object" ? typeof value : NOT_A_GROUP[tag];
|
|
1130
|
-
throw new
|
|
2492
|
+
throw new ValidationError6(
|
|
1131
2493
|
`CloudRoaring's \`${group}\` must be an object${offOk ? " or `false`" : ""} \u2014 got ${got}`
|
|
1132
2494
|
);
|
|
1133
2495
|
}
|
|
@@ -1137,7 +2499,7 @@ var CloudRoaring = class _CloudRoaring {
|
|
|
1137
2499
|
if (unknown.length === 0) return;
|
|
1138
2500
|
const takes = (keys) => keys.map((k) => `\`${k}\``).join(", ");
|
|
1139
2501
|
const named = [...new Set(unknown.map((u) => u.group))];
|
|
1140
|
-
throw new
|
|
2502
|
+
throw new ValidationError6(
|
|
1141
2503
|
`CloudRoaring does not take ${takes(unknown.map((u) => u.group === null ? u.key : `${u.group}.${u.key}`))}. ` + named.map(
|
|
1142
2504
|
(g) => g === null ? `The store takes ${takes(OPTION_KEYS.top)}.` : `\`${g}\` takes ${takes(OPTION_KEYS[g])}.`
|
|
1143
2505
|
).join(" ") + " https://github.com/cloudbitmaps/cloudbitmaps/blob/main/docs/guide/api-reference.md#build-a-store--new-cloudroaringoptions"
|
|
@@ -1155,7 +2517,7 @@ var CloudRoaring = class _CloudRoaring {
|
|
|
1155
2517
|
];
|
|
1156
2518
|
const entropy = options.seams?.entropy;
|
|
1157
2519
|
if (entropy !== void 0 && typeof entropy !== "function") {
|
|
1158
|
-
throw new
|
|
2520
|
+
throw new ValidationError6(
|
|
1159
2521
|
"CloudRoaring's `seams.entropy` must be a function `(length) => Uint8Array` returning that many random bytes"
|
|
1160
2522
|
);
|
|
1161
2523
|
}
|
|
@@ -1163,7 +2525,7 @@ var CloudRoaring = class _CloudRoaring {
|
|
|
1163
2525
|
if (seam === void 0) continue;
|
|
1164
2526
|
const has = (m) => seam !== null && typeof seam[m] === "function";
|
|
1165
2527
|
if (seam === null || typeof seam !== "object" || !needs.every(has)) {
|
|
1166
|
-
throw new
|
|
2528
|
+
throw new ValidationError6(
|
|
1167
2529
|
`CloudRoaring's \`${name}\` must be an object with ${needs.map((m) => `\`${m}()\``).join(" and ")}`
|
|
1168
2530
|
);
|
|
1169
2531
|
}
|
|
@@ -1183,7 +2545,7 @@ var CloudRoaring = class _CloudRoaring {
|
|
|
1183
2545
|
requirePositiveInt("cache.readerMaxBytes", cache.readerMaxBytes);
|
|
1184
2546
|
const ttl = cache.ttlMs;
|
|
1185
2547
|
if (ttl !== void 0 && (typeof ttl !== "number" || !Number.isFinite(ttl) || ttl <= 0)) {
|
|
1186
|
-
throw new
|
|
2548
|
+
throw new ValidationError6(
|
|
1187
2549
|
`cache.ttlMs must be a finite number above 0 (milliseconds); got ${typeof ttl === "string" ? JSON.stringify(ttl) : String(ttl)}`
|
|
1188
2550
|
);
|
|
1189
2551
|
}
|
|
@@ -1215,7 +2577,7 @@ var CloudRoaring = class _CloudRoaring {
|
|
|
1215
2577
|
const deps = {
|
|
1216
2578
|
storage: wired.storage,
|
|
1217
2579
|
cache,
|
|
1218
|
-
codec:
|
|
2580
|
+
codec: flagshipCodec(),
|
|
1219
2581
|
// the facade injects the flagship codec; core stays codec-agnostic
|
|
1220
2582
|
clock,
|
|
1221
2583
|
metrics,
|
|
@@ -1258,7 +2620,7 @@ var CloudRoaring = class _CloudRoaring {
|
|
|
1258
2620
|
clock: this.clock,
|
|
1259
2621
|
rng: this.rng,
|
|
1260
2622
|
entropy: this.entropy,
|
|
1261
|
-
codec:
|
|
2623
|
+
codec: flagshipCodec(),
|
|
1262
2624
|
// facade injects the flagship codec
|
|
1263
2625
|
keystore: this.keystore,
|
|
1264
2626
|
requireEncryption: this.requireEncryption,
|
|
@@ -1275,17 +2637,17 @@ var CloudRoaring = class _CloudRoaring {
|
|
|
1275
2637
|
*/
|
|
1276
2638
|
segment(name, options) {
|
|
1277
2639
|
if (typeof name === "object" && name !== null) {
|
|
1278
|
-
throw new
|
|
2640
|
+
throw new ValidationError6(
|
|
1279
2641
|
Array.isArray(name) ? "segment: the name is a string, store.segment('name'), not an array" : "segment: the name is a string, not a ref: for a ref, call store.segment(ref.segment, { namespace: ref.namespace })"
|
|
1280
2642
|
);
|
|
1281
2643
|
}
|
|
1282
2644
|
if (options !== void 0 && options !== null) {
|
|
1283
2645
|
if (typeof options !== "object" || Array.isArray(options)) {
|
|
1284
|
-
throw new
|
|
2646
|
+
throw new ValidationError6("segment: options must be an object such as { namespace }");
|
|
1285
2647
|
}
|
|
1286
2648
|
const proto = Object.getPrototypeOf(options);
|
|
1287
2649
|
if (proto !== null && Object.getPrototypeOf(proto) !== null) {
|
|
1288
|
-
throw new
|
|
2650
|
+
throw new ValidationError6(
|
|
1289
2651
|
"segment: options must be a plain object such as { namespace }, not a class instance or an object built on another"
|
|
1290
2652
|
);
|
|
1291
2653
|
}
|
|
@@ -1293,7 +2655,7 @@ var CloudRoaring = class _CloudRoaring {
|
|
|
1293
2655
|
(k) => k !== "namespace" && options[k] !== void 0
|
|
1294
2656
|
);
|
|
1295
2657
|
if (unknown.length > 0) {
|
|
1296
|
-
throw new
|
|
2658
|
+
throw new ValidationError6(
|
|
1297
2659
|
`segment: unknown option${unknown.length > 1 ? "s" : ""} ${unknown.map((k) => `"${k}"`).join(", ")}; a handle takes { namespace } only`
|
|
1298
2660
|
);
|
|
1299
2661
|
}
|
|
@@ -1403,20 +2765,20 @@ var CloudRoaring = class _CloudRoaring {
|
|
|
1403
2765
|
/** The one body of the forms above. */
|
|
1404
2766
|
async materializeMany(options) {
|
|
1405
2767
|
if (typeof options !== "object" || options === null) {
|
|
1406
|
-
throw new
|
|
2768
|
+
throw new ValidationError6(
|
|
1407
2769
|
"materializeMany needs an options object with `operands`, `outputs` and `keep`"
|
|
1408
2770
|
);
|
|
1409
2771
|
}
|
|
1410
2772
|
const epochAt = options.feed === void 0 ? 0 : this.epochNow();
|
|
1411
2773
|
const unknown = unknownManyKeys(options);
|
|
1412
2774
|
if (unknown.length > 0) {
|
|
1413
|
-
throw new
|
|
2775
|
+
throw new ValidationError6(
|
|
1414
2776
|
`materializeMany: unknown option${unknown.length > 1 ? "s" : ""} ${unknown.map((k) => `"${k}"`).join(", ")}`
|
|
1415
2777
|
);
|
|
1416
2778
|
}
|
|
1417
2779
|
const dryRunIn = options.dryRun;
|
|
1418
2780
|
if (dryRunIn !== void 0 && typeof dryRunIn !== "boolean") {
|
|
1419
|
-
throw new
|
|
2781
|
+
throw new ValidationError6("materializeMany: dryRun must be a boolean");
|
|
1420
2782
|
}
|
|
1421
2783
|
const dryRun = dryRunIn === true;
|
|
1422
2784
|
const operandsIn = options.operands;
|
|
@@ -1428,7 +2790,7 @@ var CloudRoaring = class _CloudRoaring {
|
|
|
1428
2790
|
const feedIn = options.feed;
|
|
1429
2791
|
const mayBeEmptyIn = options.mayBeEmpty;
|
|
1430
2792
|
if (feedIn !== void 0 && options.maxBufferedBytes === void 0) {
|
|
1431
|
-
throw new
|
|
2793
|
+
throw new ValidationError6(
|
|
1432
2794
|
"materializeMany: maxBufferedBytes is required with a feed: the feed is read once, so the call runs as one group and the budget is what bounds it"
|
|
1433
2795
|
);
|
|
1434
2796
|
}
|
|
@@ -1438,15 +2800,15 @@ var CloudRoaring = class _CloudRoaring {
|
|
|
1438
2800
|
const budgetOption = options.budget;
|
|
1439
2801
|
const allowAbsentOperands = options.allowAbsentOperands;
|
|
1440
2802
|
if (typeof pinOption !== "boolean")
|
|
1441
|
-
throw new
|
|
2803
|
+
throw new ValidationError6("materializeMany: pin must be a boolean");
|
|
1442
2804
|
if (allowAbsentOperands !== void 0 && typeof allowAbsentOperands !== "boolean") {
|
|
1443
|
-
throw new
|
|
2805
|
+
throw new ValidationError6("materializeMany: allowAbsentOperands must be a boolean");
|
|
1444
2806
|
}
|
|
1445
2807
|
if (typeof operandsIn !== "object" || operandsIn === null || Array.isArray(operandsIn)) {
|
|
1446
|
-
throw new
|
|
2808
|
+
throw new ValidationError6("materializeMany: operands must be an object of name to segment");
|
|
1447
2809
|
}
|
|
1448
2810
|
if (!Array.isArray(outputsIn) || outputsIn.length === 0) {
|
|
1449
|
-
throw new
|
|
2811
|
+
throw new ValidationError6("materializeMany: outputs must be a non-empty array");
|
|
1450
2812
|
}
|
|
1451
2813
|
const names = Object.keys(operandsIn);
|
|
1452
2814
|
const handles = /* @__PURE__ */ new Map();
|
|
@@ -1457,14 +2819,14 @@ var CloudRoaring = class _CloudRoaring {
|
|
|
1457
2819
|
}
|
|
1458
2820
|
if (mayBeEmptyIn !== void 0 && feedIn === void 0) {
|
|
1459
2821
|
if (!Array.isArray(mayBeEmptyIn)) {
|
|
1460
|
-
throw new
|
|
2822
|
+
throw new ValidationError6(
|
|
1461
2823
|
"materializeMany: mayBeEmpty must be an array of fed operand names"
|
|
1462
2824
|
);
|
|
1463
2825
|
}
|
|
1464
2826
|
if (mayBeEmptyIn.length > 0) {
|
|
1465
2827
|
const first = mayBeEmptyIn[0];
|
|
1466
2828
|
const what = typeof first !== "string" ? "something that is not a name" : handles.has(first) ? `"${first}", a stored operand` : `"${first}", which is not an operand of this call`;
|
|
1467
|
-
throw new
|
|
2829
|
+
throw new ValidationError6(
|
|
1468
2830
|
`materializeMany: mayBeEmpty names ${what}; it names fed operands, and this call has no feed`
|
|
1469
2831
|
);
|
|
1470
2832
|
}
|
|
@@ -1474,13 +2836,13 @@ var CloudRoaring = class _CloudRoaring {
|
|
|
1474
2836
|
const destKeys = /* @__PURE__ */ new Set();
|
|
1475
2837
|
outputsIn.forEach((raw, i) => {
|
|
1476
2838
|
if (typeof raw !== "object" || raw === null) {
|
|
1477
|
-
throw new
|
|
2839
|
+
throw new ValidationError6(`outputs[${i}] must be an object`);
|
|
1478
2840
|
}
|
|
1479
2841
|
const bad = Object.keys(raw).filter(
|
|
1480
2842
|
(k) => !MATERIALIZE_MANY_OUTPUT_KEYS.includes(k)
|
|
1481
2843
|
);
|
|
1482
2844
|
if (bad.length > 0) {
|
|
1483
|
-
throw new
|
|
2845
|
+
throw new ValidationError6(
|
|
1484
2846
|
`outputs[${i}]: unknown option${bad.length > 1 ? "s" : ""} ${bad.map((k) => `"${k}"`).join(", ")}`
|
|
1485
2847
|
);
|
|
1486
2848
|
}
|
|
@@ -1488,12 +2850,12 @@ var CloudRoaring = class _CloudRoaring {
|
|
|
1488
2850
|
const dest = spec.dest;
|
|
1489
2851
|
assertOneStore("materializeMany", `outputs[${i}].dest`, dest, this.origin);
|
|
1490
2852
|
if (operandKeys.has(dest.key())) {
|
|
1491
|
-
throw new
|
|
2853
|
+
throw new ValidationError6(
|
|
1492
2854
|
`outputs[${i}].dest is also an operand of the call: one call is one pass over operands that do not change under it, so chain two calls`
|
|
1493
2855
|
);
|
|
1494
2856
|
}
|
|
1495
2857
|
if (destKeys.has(dest.key())) {
|
|
1496
|
-
throw new
|
|
2858
|
+
throw new ValidationError6(
|
|
1497
2859
|
`outputs[${i}].dest names a segment another output of the call writes`
|
|
1498
2860
|
);
|
|
1499
2861
|
}
|
|
@@ -1566,13 +2928,13 @@ var CloudRoaring = class _CloudRoaring {
|
|
|
1566
2928
|
held.set(key, { at, handle });
|
|
1567
2929
|
} else if (prior.at !== void 0 && at !== void 0) {
|
|
1568
2930
|
if (!samePin(prior.at, at)) {
|
|
1569
|
-
throw new
|
|
2931
|
+
throw new ValidationError6(
|
|
1570
2932
|
`materializeMany: operand "${name}" holds a segment another operand holds, ${twoPins(prior.at, at)}: one call reads a segment at one generation`
|
|
1571
2933
|
);
|
|
1572
2934
|
}
|
|
1573
2935
|
} else if (prior.at !== void 0 || at !== void 0) {
|
|
1574
2936
|
if (!pinOption) {
|
|
1575
|
-
throw new
|
|
2937
|
+
throw new ValidationError6(
|
|
1576
2938
|
`materializeMany: operand "${name}" holds a segment another operand holds, ${twoPins(prior.at, at)}: one call reads a segment at one generation`
|
|
1577
2939
|
);
|
|
1578
2940
|
}
|
|
@@ -1600,7 +2962,7 @@ var CloudRoaring = class _CloudRoaring {
|
|
|
1600
2962
|
const final = rebindCombineMany(compiled, operandSpecs(pins));
|
|
1601
2963
|
return runCombineMany(final, {
|
|
1602
2964
|
source,
|
|
1603
|
-
codec:
|
|
2965
|
+
codec: flagshipCodec(),
|
|
1604
2966
|
clock: this.clock,
|
|
1605
2967
|
...metricsOn ? { metrics: this.metrics } : {}
|
|
1606
2968
|
});
|
|
@@ -1660,7 +3022,7 @@ var CloudRoaring = class _CloudRoaring {
|
|
|
1660
3022
|
/** A call's feed with the store's erasure counter: read once here, checked by the combine before any record is read. */
|
|
1661
3023
|
feedOf(feed, mayBeEmpty, epochAt) {
|
|
1662
3024
|
if (typeof feed !== "object" || feed === null || Array.isArray(feed)) {
|
|
1663
|
-
throw new
|
|
3025
|
+
throw new ValidationError6(
|
|
1664
3026
|
"materializeMany: feed must be an object with names, records and counts"
|
|
1665
3027
|
);
|
|
1666
3028
|
}
|
|
@@ -2103,9 +3465,10 @@ var CloudRoaring = class _CloudRoaring {
|
|
|
2103
3465
|
* `input` is ids (any sync or async iterable of integers in `[0, 2^32)`), or a whole bitmap: `{ bitmap }`, anything
|
|
2104
3466
|
* with `serialize('portable')` such as `roaring`'s `RoaringBitmap32`, or `{ serialized }`, portable Roaring bytes.
|
|
2105
3467
|
* A bitmap is checked (size cap, structure, safe deserializer) before the first request, written from its own
|
|
2106
|
-
* containers with no per-id work, and gives the generation chunk for chunk what its ids would.
|
|
2107
|
-
*
|
|
2108
|
-
*
|
|
3468
|
+
* containers with no per-id work, and gives the generation chunk for chunk what its ids would. An
|
|
3469
|
+
* iterable with a `serialize` method (a `RoaringBitmap32`, another copy's bitmap, or a bitmap `deserializePortable`
|
|
3470
|
+
* returned) passed as ids loads as `{ bitmap }` and is not iterated. A `Uint8Array` or `Buffer` passed as ids is
|
|
3471
|
+
* refused with `ValidationError`, since each byte would load as an id, even when it has a `serialize` of its own:
|
|
2109
3472
|
* pass bytes as `{ serialized }`.
|
|
2110
3473
|
*
|
|
2111
3474
|
* Ids are held whole in memory before the object is written: the generation's bitmaps and a buffer of up to about 28
|
|
@@ -2207,7 +3570,7 @@ var CloudRoaring = class _CloudRoaring {
|
|
|
2207
3570
|
const sameBackend = reads !== void 0 && (reads.origin === this.origin || this.registry !== void 0 && REGISTRY_OF.get(reads.origin) === this.registry);
|
|
2208
3571
|
if (sameBackend && reads.keys.includes(segmentKey(ref))) {
|
|
2209
3572
|
const named = ref.namespace === void 0 ? ref.segment : `${ref.namespace}/${ref.segment}`;
|
|
2210
|
-
throw new
|
|
3573
|
+
throw new ValidationError6(
|
|
2211
3574
|
`load: the ids come from a read of the segment "${named}" that is being loaded, and a load publishes over whatever the segment is by then, so another process's newer load of it can be replaced by a result built from the one before, with no conflict reported. This release has no fenced in-place update: write the result into a new segment and point readers at it`
|
|
2212
3575
|
);
|
|
2213
3576
|
}
|
|
@@ -2271,7 +3634,7 @@ var CloudRoaring = class _CloudRoaring {
|
|
|
2271
3634
|
async dropSegment(ref, options) {
|
|
2272
3635
|
ref = validateRef(ref, "dropSegment");
|
|
2273
3636
|
if (options === void 0 || options === null) {
|
|
2274
|
-
throw new
|
|
3637
|
+
throw new ValidationError6("dropSegment: options { confirmSegment } are required");
|
|
2275
3638
|
}
|
|
2276
3639
|
checkOptions(options, "dropSegment", CALL_KEYS.dropSegment, ["dryRun"]);
|
|
2277
3640
|
const deps = this.lifecycleDeps("dropSegment");
|
|
@@ -2560,7 +3923,7 @@ var CloudRoaring = class _CloudRoaring {
|
|
|
2560
3923
|
return new SegmentEngine({
|
|
2561
3924
|
storage: this.retryOptions === void 0 ? pinned : new RetryingStorageChunkSource2(pinned, this.retryOptions),
|
|
2562
3925
|
cache: this.cache,
|
|
2563
|
-
codec:
|
|
3926
|
+
codec: flagshipCodec(),
|
|
2564
3927
|
clock: this.clock,
|
|
2565
3928
|
metrics: this.metrics,
|
|
2566
3929
|
budget: this.budget,
|
|
@@ -2590,7 +3953,7 @@ var CloudRoaring = class _CloudRoaring {
|
|
|
2590
3953
|
if (held.has(key)) {
|
|
2591
3954
|
const before = held.get(key);
|
|
2592
3955
|
if (!samePin(before, at)) {
|
|
2593
|
-
throw new
|
|
3956
|
+
throw new ValidationError6(
|
|
2594
3957
|
`the same segment is in this combine twice, ${twoPins(before, at)}: one call reads a segment at one generation, so materialise one of them into a segment of its own first, with \`materializeMany({ operands: { src: seg }, outputs: [{ dest, expr: { or: ['src'] } }], keep })\``
|
|
2595
3958
|
);
|
|
2596
3959
|
}
|
|
@@ -2724,7 +4087,7 @@ var CloudRoaring = class _CloudRoaring {
|
|
|
2724
4087
|
checkOptions(options, "exportSegments", CALL_KEYS.exportSegments, [], MISPLACED.exportSegments);
|
|
2725
4088
|
const opts = picked(options, CALL_KEYS.exportSegments);
|
|
2726
4089
|
const registry = this.requireRegistry("exportSegments");
|
|
2727
|
-
return runExport(this, registry, sink, { ...opts, codec:
|
|
4090
|
+
return runExport(this, registry, sink, { ...opts, codec: flagshipCodec() });
|
|
2728
4091
|
}
|
|
2729
4092
|
};
|
|
2730
4093
|
var withBatches = (gen, batches) => Object.assign(gen, { batches });
|
|
@@ -2752,7 +4115,7 @@ var readOptions = (options) => ({
|
|
|
2752
4115
|
});
|
|
2753
4116
|
var NO_SEGMENTS = [];
|
|
2754
4117
|
function segmentList(list, what) {
|
|
2755
|
-
if (!Array.isArray(list)) throw new
|
|
4118
|
+
if (!Array.isArray(list)) throw new ValidationError6(`${what} must be an array of segments`);
|
|
2756
4119
|
return list;
|
|
2757
4120
|
}
|
|
2758
4121
|
var STREAM_SOURCES = /* @__PURE__ */ new WeakMap();
|
|
@@ -2765,7 +4128,7 @@ function operandsLabel(verb) {
|
|
|
2765
4128
|
return verb === "andNot" ? "andNot: `excludes`" : `${verb}: \`others\``;
|
|
2766
4129
|
}
|
|
2767
4130
|
function refuseNoOperands(verb) {
|
|
2768
|
-
throw new
|
|
4131
|
+
throw new ValidationError6(
|
|
2769
4132
|
verb === "intersect" ? "intersect requires at least one segment to intersect with; to read every id of one segment, use iterate()" : "intersectInto requires at least one segment to intersect with; to copy this segment into dest, call materializeMany({ operands: { src: thisSegment }, outputs: [{ dest, expr: { or: ['src'] } }], keep })"
|
|
2770
4133
|
);
|
|
2771
4134
|
}
|
|
@@ -2846,7 +4209,7 @@ var Segment = class _Segment {
|
|
|
2846
4209
|
*/
|
|
2847
4210
|
constructor(parts) {
|
|
2848
4211
|
if (!minting) {
|
|
2849
|
-
throw new
|
|
4212
|
+
throw new ValidationError6(
|
|
2850
4213
|
"a Segment is not constructed directly; call `store.segment(name)`"
|
|
2851
4214
|
);
|
|
2852
4215
|
}
|
|
@@ -2960,11 +4323,11 @@ var Segment = class _Segment {
|
|
|
2960
4323
|
leaseUntilOf(op, options) {
|
|
2961
4324
|
if (options === void 0 || options === null) return void 0;
|
|
2962
4325
|
if (typeof options !== "object" || Array.isArray(options)) {
|
|
2963
|
-
throw new
|
|
4326
|
+
throw new ValidationError6(`${op}: options must be an object such as { leaseUntil }`);
|
|
2964
4327
|
}
|
|
2965
4328
|
const unknown = Object.keys(options).filter((k) => k !== "leaseUntil");
|
|
2966
4329
|
if (unknown.length > 0) {
|
|
2967
|
-
throw new
|
|
4330
|
+
throw new ValidationError6(
|
|
2968
4331
|
`${op}: unknown option${unknown.length > 1 ? "s" : ""} ${unknown.map((k) => `"${k}"`).join(", ")}; this version takes { leaseUntil } only`
|
|
2969
4332
|
);
|
|
2970
4333
|
}
|
|
@@ -2972,17 +4335,17 @@ var Segment = class _Segment {
|
|
|
2972
4335
|
if (until === void 0) return void 0;
|
|
2973
4336
|
const now = this.clock.now();
|
|
2974
4337
|
if (typeof until !== "number" || !Number.isSafeInteger(until)) {
|
|
2975
|
-
throw new
|
|
4338
|
+
throw new ValidationError6(
|
|
2976
4339
|
`${op}: leaseUntil must be an integer epoch-MILLISECONDS; got ${String(until)}`
|
|
2977
4340
|
);
|
|
2978
4341
|
}
|
|
2979
4342
|
if (until <= now) {
|
|
2980
|
-
throw new
|
|
4343
|
+
throw new ValidationError6(
|
|
2981
4344
|
`${op}: leaseUntil (${until}) is not after now (${now}); it is epoch MILLISECONDS, so a value in seconds reads as long past. Use \`Date.now() + hours * 3_600_000\``
|
|
2982
4345
|
);
|
|
2983
4346
|
}
|
|
2984
4347
|
if (until > now + MAX_LEASE_MS) {
|
|
2985
|
-
throw new
|
|
4348
|
+
throw new ValidationError6(
|
|
2986
4349
|
`${op}: leaseUntil is more than 14 days away; the longest lease is ${MAX_LEASE_MS} ms. Take a new lease when a job outlasts it`
|
|
2987
4350
|
);
|
|
2988
4351
|
}
|
|
@@ -3086,22 +4449,22 @@ var Segment = class _Segment {
|
|
|
3086
4449
|
const { generation, fingerprint, version } = at ?? {};
|
|
3087
4450
|
const unknown = typeof at === "object" && at !== null ? Object.keys(at).filter((k) => !["generation", "fingerprint", "version"].includes(k)) : [];
|
|
3088
4451
|
if (unknown.length > 0) {
|
|
3089
|
-
throw new
|
|
4452
|
+
throw new ValidationError6(
|
|
3090
4453
|
`pinAt: unknown option${unknown.length > 1 ? "s" : ""} ${unknown.map((k) => `"${k}"`).join(", ")}; pinAt takes { generation, fingerprint } and a pin's \`version\`, which it does not read`
|
|
3091
4454
|
);
|
|
3092
4455
|
}
|
|
3093
4456
|
if (generation === null) {
|
|
3094
|
-
throw new
|
|
4457
|
+
throw new ValidationError6(
|
|
3095
4458
|
"pinAt: the pin named no generation (the segment had none when it was pinned), so there is nothing to reopen"
|
|
3096
4459
|
);
|
|
3097
4460
|
}
|
|
3098
4461
|
if (version !== void 0 && typeof version !== "string") {
|
|
3099
|
-
throw new
|
|
4462
|
+
throw new ValidationError6(
|
|
3100
4463
|
"pinAt: `version`, when given, is the string a pin recorded in its pinnedAt; pinAt does not read it, so leave it out if you have none"
|
|
3101
4464
|
);
|
|
3102
4465
|
}
|
|
3103
4466
|
if (typeof generation !== "number" || !Number.isSafeInteger(generation) || generation < 0 || typeof fingerprint !== "string" || !/^\d+:\d+$/.test(fingerprint)) {
|
|
3104
|
-
throw new
|
|
4467
|
+
throw new ValidationError6(
|
|
3105
4468
|
"pinAt: pass { generation, fingerprint } as recorded by an earlier pin (its pinnedAt); a generation number without the fingerprint of its object does not identify it"
|
|
3106
4469
|
);
|
|
3107
4470
|
}
|
|
@@ -3150,7 +4513,7 @@ var Segment = class _Segment {
|
|
|
3150
4513
|
if (role === void 0) return;
|
|
3151
4514
|
const { namespace, segment } = dest.ref;
|
|
3152
4515
|
const named = namespace === void 0 ? segment : `${namespace}/${segment}`;
|
|
3153
|
-
throw new
|
|
4516
|
+
throw new ValidationError6(
|
|
3154
4517
|
`${verb}: the destination "${named}" is also ${role} of the call, and a call that reads a segment while it publishes to it can replace a newer load of it with a result built from an older one, with no conflict reported. This release has no fenced in-place update: combine into a new segment and point readers at it`
|
|
3155
4518
|
);
|
|
3156
4519
|
}
|
|
@@ -3580,25 +4943,25 @@ function parseConfig(env) {
|
|
|
3580
4943
|
);
|
|
3581
4944
|
if (unknown.length > 0) {
|
|
3582
4945
|
const which = unknown.length > 1 ? `${unknown.join(", ")} are not settings export-segments takes.` : `${unknown[0]} is not a setting export-segments takes.`;
|
|
3583
|
-
throw new
|
|
4946
|
+
throw new ValidationError7(
|
|
3584
4947
|
`${which} It takes ${EXPORT_VARIABLES.join(", ")}; run export-segments --help`
|
|
3585
4948
|
);
|
|
3586
4949
|
}
|
|
3587
4950
|
const root = env.CR_EXPORT_ROOT;
|
|
3588
4951
|
if (root === void 0 || root === "") {
|
|
3589
|
-
throw new
|
|
4952
|
+
throw new ValidationError7(
|
|
3590
4953
|
"CR_EXPORT_ROOT is not set: the directory that holds the store's storage/ and registry/. export-segments also needs CR_EXPORT_OUT; run export-segments --help"
|
|
3591
4954
|
);
|
|
3592
4955
|
}
|
|
3593
4956
|
const out = env.CR_EXPORT_OUT;
|
|
3594
4957
|
if (out === void 0 || out === "") {
|
|
3595
|
-
throw new
|
|
4958
|
+
throw new ValidationError7(
|
|
3596
4959
|
"CR_EXPORT_OUT is not set: the directory to write the dump to. export-segments also needs CR_EXPORT_ROOT; run export-segments --help"
|
|
3597
4960
|
);
|
|
3598
4961
|
}
|
|
3599
4962
|
const format = env.CR_EXPORT_FORMAT || "roaring";
|
|
3600
4963
|
if (format !== "roaring" && format !== "ndjson") {
|
|
3601
|
-
throw new
|
|
4964
|
+
throw new ValidationError7(`CR_EXPORT_FORMAT must be "roaring" or "ndjson"; got ${format}`);
|
|
3602
4965
|
}
|
|
3603
4966
|
const namespace = env.CR_EXPORT_NAMESPACE || void 0;
|
|
3604
4967
|
return { root, out, format, namespace };
|
|
@@ -3613,7 +4976,7 @@ async function ensureOwnDirectory(out, dir) {
|
|
|
3613
4976
|
}
|
|
3614
4977
|
const found = await lstat(dir);
|
|
3615
4978
|
const refuse = (why) => {
|
|
3616
|
-
throw new
|
|
4979
|
+
throw new ValidationError7(`the export directory is not one this tool made: ${why}`);
|
|
3617
4980
|
};
|
|
3618
4981
|
if (found.isSymbolicLink()) refuse("a namespace directory is a symbolic link");
|
|
3619
4982
|
if (!found.isDirectory()) refuse("a namespace path is not a directory");
|
|
@@ -3628,7 +4991,7 @@ function fsSink(out) {
|
|
|
3628
4991
|
async open(ref, ext) {
|
|
3629
4992
|
const part = namespacePathPart(ref.namespace);
|
|
3630
4993
|
if (part.toLowerCase() === MANIFEST_NAME) {
|
|
3631
|
-
throw new
|
|
4994
|
+
throw new ValidationError7(
|
|
3632
4995
|
`a namespace named ${MANIFEST_NAME} (in any letter case) cannot be exported to a directory: its folder would be the manifest's path`
|
|
3633
4996
|
);
|
|
3634
4997
|
}
|
|
@@ -3673,10 +5036,10 @@ async function requireStoreRoot(root) {
|
|
|
3673
5036
|
try {
|
|
3674
5037
|
entries = await readdir(root);
|
|
3675
5038
|
} catch {
|
|
3676
|
-
throw new
|
|
5039
|
+
throw new ValidationError7("CR_EXPORT_ROOT does not name a directory that can be read");
|
|
3677
5040
|
}
|
|
3678
5041
|
if (entries.length === 0) {
|
|
3679
|
-
throw new
|
|
5042
|
+
throw new ValidationError7(
|
|
3680
5043
|
"CR_EXPORT_ROOT is empty: it holds no store (an unmounted volume, or the wrong directory)"
|
|
3681
5044
|
);
|
|
3682
5045
|
}
|
|
@@ -3692,7 +5055,7 @@ async function main(env = process.env, now = () => Date.now()) {
|
|
|
3692
5055
|
const store = new CloudRoaring({ storage });
|
|
3693
5056
|
const priorManifest = await lstat(join(config.out, MANIFEST_NAME)).catch(() => null);
|
|
3694
5057
|
if (priorManifest?.isDirectory() === true) {
|
|
3695
|
-
throw new
|
|
5058
|
+
throw new ValidationError7(
|
|
3696
5059
|
`${join(config.out, MANIFEST_NAME)} is a directory, so the manifest cannot be written there: remove or rename it, or export to a fresh directory`
|
|
3697
5060
|
);
|
|
3698
5061
|
}
|