@cloudbitmaps/roaring 0.24.0 → 0.26.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/PRIVACY.md +1 -1
- package/README.md +32 -4
- package/dist/bin/export-segments.js +1628 -211
- package/dist/bin/export-segments.js.map +4 -4
- package/dist/bitmap.d.ts +223 -0
- package/dist/index.d.ts +58 -6
- package/dist/index.js +1988 -198
- package/dist/index.js.map +4 -4
- package/package.json +2 -2
- package/dist/roaring-codec.d.ts +0 -49
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
MAX_LEASE_MS,
|
|
27
27
|
NotFoundError,
|
|
28
28
|
UnsupportedError as UnsupportedError2,
|
|
29
|
-
ValidationError as
|
|
29
|
+
ValidationError as ValidationError5,
|
|
30
30
|
errorKind,
|
|
31
31
|
WriteConflictError,
|
|
32
32
|
checkBudget,
|
|
@@ -129,14 +129,99 @@ function refuseReservedNamespace(namespace) {
|
|
|
129
129
|
}
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
-
// src/roaring-codec.ts
|
|
133
|
-
import { ValidationError as ValidationError3, decodeSerialized } from "@cloudbitmaps/core";
|
|
134
|
-
|
|
135
132
|
// src/ts-roaring/bitmap.ts
|
|
136
|
-
import { IntegrityError as IntegrityError3, ValidationError as ValidationError2 } from "@cloudbitmaps/core";
|
|
133
|
+
import { IntegrityError as IntegrityError3, ValidationError as ValidationError2, refusalOfId } from "@cloudbitmaps/core";
|
|
137
134
|
|
|
138
135
|
// src/portable/layout.ts
|
|
139
136
|
import { IntegrityError } from "@cloudbitmaps/core";
|
|
137
|
+
|
|
138
|
+
// src/portable/popcount.ts
|
|
139
|
+
var BITSET_WORDS = 2048;
|
|
140
|
+
function popcount32(word) {
|
|
141
|
+
let w = word - (word >>> 1 & 1431655765);
|
|
142
|
+
w = (w & 858993459) + (w >>> 2 & 858993459);
|
|
143
|
+
return Math.imul(w + (w >>> 4) & 252645135, 16843009) >>> 24;
|
|
144
|
+
}
|
|
145
|
+
function popcountWords(d) {
|
|
146
|
+
let total = 0;
|
|
147
|
+
let ones = 0;
|
|
148
|
+
let twos = 0;
|
|
149
|
+
let fours = 0;
|
|
150
|
+
let eights = 0;
|
|
151
|
+
for (let i = 0; i < BITSET_WORDS; i += 16) {
|
|
152
|
+
let u;
|
|
153
|
+
let twosA;
|
|
154
|
+
let twosB;
|
|
155
|
+
let foursA;
|
|
156
|
+
let foursB;
|
|
157
|
+
let x = d[i];
|
|
158
|
+
let y = d[i + 1];
|
|
159
|
+
u = ones ^ x;
|
|
160
|
+
twosA = ones & x | u & y;
|
|
161
|
+
ones = u ^ y;
|
|
162
|
+
x = d[i + 2];
|
|
163
|
+
y = d[i + 3];
|
|
164
|
+
u = ones ^ x;
|
|
165
|
+
twosB = ones & x | u & y;
|
|
166
|
+
ones = u ^ y;
|
|
167
|
+
u = twos ^ twosA;
|
|
168
|
+
foursA = twos & twosA | u & twosB;
|
|
169
|
+
twos = u ^ twosB;
|
|
170
|
+
x = d[i + 4];
|
|
171
|
+
y = d[i + 5];
|
|
172
|
+
u = ones ^ x;
|
|
173
|
+
twosA = ones & x | u & y;
|
|
174
|
+
ones = u ^ y;
|
|
175
|
+
x = d[i + 6];
|
|
176
|
+
y = d[i + 7];
|
|
177
|
+
u = ones ^ x;
|
|
178
|
+
twosB = ones & x | u & y;
|
|
179
|
+
ones = u ^ y;
|
|
180
|
+
u = twos ^ twosA;
|
|
181
|
+
foursB = twos & twosA | u & twosB;
|
|
182
|
+
twos = u ^ twosB;
|
|
183
|
+
u = fours ^ foursA;
|
|
184
|
+
const eightsA = fours & foursA | u & foursB;
|
|
185
|
+
fours = u ^ foursB;
|
|
186
|
+
x = d[i + 8];
|
|
187
|
+
y = d[i + 9];
|
|
188
|
+
u = ones ^ x;
|
|
189
|
+
twosA = ones & x | u & y;
|
|
190
|
+
ones = u ^ y;
|
|
191
|
+
x = d[i + 10];
|
|
192
|
+
y = d[i + 11];
|
|
193
|
+
u = ones ^ x;
|
|
194
|
+
twosB = ones & x | u & y;
|
|
195
|
+
ones = u ^ y;
|
|
196
|
+
u = twos ^ twosA;
|
|
197
|
+
foursA = twos & twosA | u & twosB;
|
|
198
|
+
twos = u ^ twosB;
|
|
199
|
+
x = d[i + 12];
|
|
200
|
+
y = d[i + 13];
|
|
201
|
+
u = ones ^ x;
|
|
202
|
+
twosA = ones & x | u & y;
|
|
203
|
+
ones = u ^ y;
|
|
204
|
+
x = d[i + 14];
|
|
205
|
+
y = d[i + 15];
|
|
206
|
+
u = ones ^ x;
|
|
207
|
+
twosB = ones & x | u & y;
|
|
208
|
+
ones = u ^ y;
|
|
209
|
+
u = twos ^ twosA;
|
|
210
|
+
foursB = twos & twosA | u & twosB;
|
|
211
|
+
twos = u ^ twosB;
|
|
212
|
+
u = fours ^ foursA;
|
|
213
|
+
const eightsB = fours & foursA | u & foursB;
|
|
214
|
+
fours = u ^ foursB;
|
|
215
|
+
u = eights ^ eightsA;
|
|
216
|
+
const sixteens = eights & eightsA | u & eightsB;
|
|
217
|
+
eights = u ^ eightsB;
|
|
218
|
+
total += popcount32(sixteens);
|
|
219
|
+
}
|
|
220
|
+
return 16 * total + 8 * popcount32(eights) + 4 * popcount32(fours) + 2 * popcount32(twos) + popcount32(ones);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// src/portable/layout.ts
|
|
224
|
+
var LITTLE_ENDIAN = new Uint8Array(Uint16Array.of(1).buffer)[0] === 1;
|
|
140
225
|
var SERIAL_COOKIE_NO_RUNCONTAINER = 12346;
|
|
141
226
|
var SERIAL_COOKIE = 12347;
|
|
142
227
|
var NO_OFFSET_THRESHOLD = 4;
|
|
@@ -201,7 +286,7 @@ function walk(bytes, out) {
|
|
|
201
286
|
const key = view.getUint16(descriptiveAt + i * 4, true);
|
|
202
287
|
if (key <= previousKey) {
|
|
203
288
|
throw new IntegrityError(
|
|
204
|
-
`portable roaring: container keys are not strictly ascending
|
|
289
|
+
`portable roaring: container keys are not strictly ascending at index ${i}`
|
|
205
290
|
);
|
|
206
291
|
}
|
|
207
292
|
previousKey = key;
|
|
@@ -234,7 +319,7 @@ function checkContainer(bytes, view, pos, kind, cardinality, i) {
|
|
|
234
319
|
if (pos + BITMAP_CONTAINER_BYTES > length) {
|
|
235
320
|
throw overrun(bytes, pos, BITMAP_CONTAINER_BYTES, `container ${i} (bitmap)`);
|
|
236
321
|
}
|
|
237
|
-
const bits =
|
|
322
|
+
const bits = bitsetBits(bytes, pos);
|
|
238
323
|
if (bits !== cardinality) {
|
|
239
324
|
throw new IntegrityError(
|
|
240
325
|
`portable roaring: container ${i} (bitmap) holds ${bits} values, but its header says ${cardinality}`
|
|
@@ -294,25 +379,22 @@ function checkRuns(view, at, runs, index) {
|
|
|
294
379
|
}
|
|
295
380
|
return covered;
|
|
296
381
|
}
|
|
297
|
-
function
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
w = (w & 858993459) + (w >>> 2 & 858993459);
|
|
303
|
-
bits += Math.imul(w + (w >>> 4) & 252645135, 16843009) >>> 24;
|
|
304
|
-
}
|
|
305
|
-
return bits;
|
|
382
|
+
function bitsetBits(bytes, at) {
|
|
383
|
+
const offset = bytes.byteOffset + at;
|
|
384
|
+
if ((offset & 3) === 0) return popcountWords(new Uint32Array(bytes.buffer, offset, BITSET_WORDS));
|
|
385
|
+
scratchBytes.set(bytes.subarray(at, at + BITMAP_CONTAINER_BYTES));
|
|
386
|
+
return popcountWords(scratchWords);
|
|
306
387
|
}
|
|
388
|
+
var scratchWords = new Uint32Array(BITSET_WORDS);
|
|
389
|
+
var scratchBytes = new Uint8Array(scratchWords.buffer);
|
|
307
390
|
|
|
308
391
|
// src/ts-roaring/containers.ts
|
|
309
392
|
var ARRAY2 = 0;
|
|
310
393
|
var BITSET = 1;
|
|
311
394
|
var RUN2 = 2;
|
|
312
|
-
var WORDS =
|
|
395
|
+
var WORDS = BITSET_WORDS;
|
|
313
396
|
var BITSET_BYTES = 8192;
|
|
314
397
|
var GALLOP_SKEW = 16;
|
|
315
|
-
var LITTLE_ENDIAN = new Uint8Array(Uint16Array.of(1).buffer)[0] === 1;
|
|
316
398
|
var Container = class {
|
|
317
399
|
constructor(kind, data, off, len, card, shared) {
|
|
318
400
|
this.kind = kind;
|
|
@@ -362,12 +444,7 @@ function pairs16(n) {
|
|
|
362
444
|
function arrayOfScratch(scratch, n) {
|
|
363
445
|
return n === 0 ? null : arrayContainer(scratch.slice(0, n), n);
|
|
364
446
|
}
|
|
365
|
-
function
|
|
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) {
|
|
447
|
+
function popcountAnd(d, e) {
|
|
371
448
|
let total = 0;
|
|
372
449
|
let ones = 0;
|
|
373
450
|
let twos = 0;
|
|
@@ -379,26 +456,26 @@ function popcountWords(d) {
|
|
|
379
456
|
let twosB;
|
|
380
457
|
let foursA;
|
|
381
458
|
let foursB;
|
|
382
|
-
let x = d[i];
|
|
383
|
-
let y = d[i + 1];
|
|
459
|
+
let x = d[i] & e[i];
|
|
460
|
+
let y = d[i + 1] & e[i + 1];
|
|
384
461
|
u = ones ^ x;
|
|
385
462
|
twosA = ones & x | u & y;
|
|
386
463
|
ones = u ^ y;
|
|
387
|
-
x = d[i + 2];
|
|
388
|
-
y = d[i + 3];
|
|
464
|
+
x = d[i + 2] & e[i + 2];
|
|
465
|
+
y = d[i + 3] & e[i + 3];
|
|
389
466
|
u = ones ^ x;
|
|
390
467
|
twosB = ones & x | u & y;
|
|
391
468
|
ones = u ^ y;
|
|
392
469
|
u = twos ^ twosA;
|
|
393
470
|
foursA = twos & twosA | u & twosB;
|
|
394
471
|
twos = u ^ twosB;
|
|
395
|
-
x = d[i + 4];
|
|
396
|
-
y = d[i + 5];
|
|
472
|
+
x = d[i + 4] & e[i + 4];
|
|
473
|
+
y = d[i + 5] & e[i + 5];
|
|
397
474
|
u = ones ^ x;
|
|
398
475
|
twosA = ones & x | u & y;
|
|
399
476
|
ones = u ^ y;
|
|
400
|
-
x = d[i + 6];
|
|
401
|
-
y = d[i + 7];
|
|
477
|
+
x = d[i + 6] & e[i + 6];
|
|
478
|
+
y = d[i + 7] & e[i + 7];
|
|
402
479
|
u = ones ^ x;
|
|
403
480
|
twosB = ones & x | u & y;
|
|
404
481
|
ones = u ^ y;
|
|
@@ -408,26 +485,26 @@ function popcountWords(d) {
|
|
|
408
485
|
u = fours ^ foursA;
|
|
409
486
|
const eightsA = fours & foursA | u & foursB;
|
|
410
487
|
fours = u ^ foursB;
|
|
411
|
-
x = d[i + 8];
|
|
412
|
-
y = d[i + 9];
|
|
488
|
+
x = d[i + 8] & e[i + 8];
|
|
489
|
+
y = d[i + 9] & e[i + 9];
|
|
413
490
|
u = ones ^ x;
|
|
414
491
|
twosA = ones & x | u & y;
|
|
415
492
|
ones = u ^ y;
|
|
416
|
-
x = d[i + 10];
|
|
417
|
-
y = d[i + 11];
|
|
493
|
+
x = d[i + 10] & e[i + 10];
|
|
494
|
+
y = d[i + 11] & e[i + 11];
|
|
418
495
|
u = ones ^ x;
|
|
419
496
|
twosB = ones & x | u & y;
|
|
420
497
|
ones = u ^ y;
|
|
421
498
|
u = twos ^ twosA;
|
|
422
499
|
foursA = twos & twosA | u & twosB;
|
|
423
500
|
twos = u ^ twosB;
|
|
424
|
-
x = d[i + 12];
|
|
425
|
-
y = d[i + 13];
|
|
501
|
+
x = d[i + 12] & e[i + 12];
|
|
502
|
+
y = d[i + 13] & e[i + 13];
|
|
426
503
|
u = ones ^ x;
|
|
427
504
|
twosA = ones & x | u & y;
|
|
428
505
|
ones = u ^ y;
|
|
429
|
-
x = d[i + 14];
|
|
430
|
-
y = d[i + 15];
|
|
506
|
+
x = d[i + 14] & e[i + 14];
|
|
507
|
+
y = d[i + 15] & e[i + 15];
|
|
431
508
|
u = ones ^ x;
|
|
432
509
|
twosB = ones & x | u & y;
|
|
433
510
|
ones = u ^ y;
|
|
@@ -470,6 +547,19 @@ function clearRange(words, start, end) {
|
|
|
470
547
|
for (let i = first + 1; i < last; i++) words[i] = 0;
|
|
471
548
|
words[last] = words[last] & ~tail;
|
|
472
549
|
}
|
|
550
|
+
function flipRange(words, start, end) {
|
|
551
|
+
const first = start >>> 5;
|
|
552
|
+
const last = end >>> 5;
|
|
553
|
+
const head = 4294967295 << (start & 31) >>> 0;
|
|
554
|
+
const tail = 4294967295 >>> 31 - (end & 31);
|
|
555
|
+
if (first === last) {
|
|
556
|
+
words[first] = words[first] ^ head & tail;
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
559
|
+
words[first] = words[first] ^ head;
|
|
560
|
+
for (let i = first + 1; i < last; i++) words[i] = ~words[i];
|
|
561
|
+
words[last] = words[last] ^ tail;
|
|
562
|
+
}
|
|
473
563
|
function fromSortedIds(ids, from, to) {
|
|
474
564
|
const n = to - from;
|
|
475
565
|
if (n <= ARRAY_MAX_CARDINALITY) {
|
|
@@ -525,11 +615,12 @@ function writeLows(c, out) {
|
|
|
525
615
|
}
|
|
526
616
|
}
|
|
527
617
|
}
|
|
618
|
+
var SMALL_IDS = 32;
|
|
528
619
|
function appendIds(c, out, at, base) {
|
|
529
620
|
if (c.kind === ARRAY2) {
|
|
530
621
|
const u162 = lows16(c);
|
|
531
622
|
const end = c.off + c.len;
|
|
532
|
-
if (base === 0) {
|
|
623
|
+
if (base === 0 && c.len >= SMALL_IDS) {
|
|
533
624
|
out.set(u162.subarray(c.off, end), at);
|
|
534
625
|
return at + c.len;
|
|
535
626
|
}
|
|
@@ -552,14 +643,15 @@ function appendIds(c, out, at, base) {
|
|
|
552
643
|
const u16 = lows16(c);
|
|
553
644
|
for (let r = 0; r < c.len; r++) {
|
|
554
645
|
const start = u16[c.off + 2 * r];
|
|
555
|
-
const
|
|
556
|
-
if (
|
|
557
|
-
|
|
646
|
+
const length = u16[c.off + 2 * r + 1];
|
|
647
|
+
if (length < LONG_RUN) {
|
|
648
|
+
const last = base + start + length;
|
|
649
|
+
for (let v = base + start; v <= last; v++) out[at++] = v;
|
|
558
650
|
continue;
|
|
559
651
|
}
|
|
560
652
|
const from = at;
|
|
561
|
-
out.set(iota().subarray(start,
|
|
562
|
-
at +=
|
|
653
|
+
out.set(iota().subarray(start, start + length + 1), at);
|
|
654
|
+
at += length + 1;
|
|
563
655
|
if (base !== 0) for (let i = from; i < at; i++) out[i] = out[i] + base;
|
|
564
656
|
}
|
|
565
657
|
return at;
|
|
@@ -645,31 +737,130 @@ function containerHas(c, low) {
|
|
|
645
737
|
const r = c.off + 2 * (after - 1);
|
|
646
738
|
return low <= u16[r] + u16[r + 1];
|
|
647
739
|
}
|
|
740
|
+
function runsAfter(data, off, from, len, value) {
|
|
741
|
+
let step = 1;
|
|
742
|
+
let lo = from;
|
|
743
|
+
let hi = from;
|
|
744
|
+
while (hi < len && data[off + 2 * hi] <= value) {
|
|
745
|
+
lo = hi + 1;
|
|
746
|
+
hi += step;
|
|
747
|
+
step *= 2;
|
|
748
|
+
}
|
|
749
|
+
if (hi > len) hi = len;
|
|
750
|
+
while (lo < hi) {
|
|
751
|
+
const mid = lo + hi >>> 1;
|
|
752
|
+
if (data[off + 2 * mid] <= value) lo = mid + 1;
|
|
753
|
+
else hi = mid;
|
|
754
|
+
}
|
|
755
|
+
return lo;
|
|
756
|
+
}
|
|
757
|
+
function runsOrPlain(pairs, runs, card, copy) {
|
|
758
|
+
const plain = card <= ARRAY_MAX_CARDINALITY ? 2 * card : BITSET_BYTES;
|
|
759
|
+
if (2 + 4 * runs < plain) {
|
|
760
|
+
return runContainer(copy ? pairs.slice(0, 2 * runs) : pairs, runs, card);
|
|
761
|
+
}
|
|
762
|
+
return fromRunPairs(pairs, runs, card);
|
|
763
|
+
}
|
|
764
|
+
function addToRuns(c, low) {
|
|
765
|
+
const u16 = lows16(c);
|
|
766
|
+
const next = runsAfter(u16, c.off, 0, c.len, low);
|
|
767
|
+
const prev = next - 1;
|
|
768
|
+
const joinPrev = prev >= 0 && u16[c.off + 2 * prev] + u16[c.off + 2 * prev + 1] + 1 === low;
|
|
769
|
+
const joinNext = next < c.len && u16[c.off + 2 * next] === low + 1;
|
|
770
|
+
const runs = c.len + 1 - (joinPrev ? 1 : 0) - (joinNext ? 1 : 0);
|
|
771
|
+
const out = new Uint16Array(2 * runs);
|
|
772
|
+
const head = joinPrev ? prev : next;
|
|
773
|
+
out.set(u16.subarray(c.off, c.off + 2 * head));
|
|
774
|
+
let at = 2 * head;
|
|
775
|
+
if (joinPrev && joinNext) {
|
|
776
|
+
out[at++] = u16[c.off + 2 * prev];
|
|
777
|
+
out[at++] = u16[c.off + 2 * next] + u16[c.off + 2 * next + 1] - u16[c.off + 2 * prev];
|
|
778
|
+
} else if (joinPrev) {
|
|
779
|
+
out[at++] = u16[c.off + 2 * prev];
|
|
780
|
+
out[at++] = u16[c.off + 2 * prev + 1] + 1;
|
|
781
|
+
} else if (joinNext) {
|
|
782
|
+
out[at++] = low;
|
|
783
|
+
out[at++] = u16[c.off + 2 * next + 1] + 1;
|
|
784
|
+
} else {
|
|
785
|
+
out[at++] = low;
|
|
786
|
+
out[at++] = 0;
|
|
787
|
+
}
|
|
788
|
+
const rest = joinNext ? next + 1 : next;
|
|
789
|
+
out.set(u16.subarray(c.off + 2 * rest, c.off + 2 * c.len), at);
|
|
790
|
+
return runsOrPlain(out, runs, c.card + 1, false);
|
|
791
|
+
}
|
|
648
792
|
function containerAdd(c, low) {
|
|
649
793
|
if (containerHas(c, low)) return c;
|
|
650
|
-
|
|
651
|
-
if (
|
|
652
|
-
const words = writableWords(
|
|
794
|
+
if (c.kind === RUN2) return addToRuns(c, low);
|
|
795
|
+
if (c.kind === BITSET) {
|
|
796
|
+
const words = writableWords(c);
|
|
653
797
|
words[low >>> 5] = words[low >>> 5] | 1 << (low & 31);
|
|
654
|
-
return bitsetContainer(words,
|
|
798
|
+
return bitsetContainer(words, c.card + 1);
|
|
655
799
|
}
|
|
656
|
-
if (
|
|
657
|
-
const words = toWords(
|
|
800
|
+
if (c.card === ARRAY_MAX_CARDINALITY) {
|
|
801
|
+
const words = toWords(c);
|
|
658
802
|
words[low >>> 5] = words[low >>> 5] | 1 << (low & 31);
|
|
659
|
-
return bitsetContainer(words,
|
|
803
|
+
return bitsetContainer(words, c.card + 1);
|
|
660
804
|
}
|
|
661
|
-
const old = lows16(
|
|
662
|
-
const at = lowerBound(old,
|
|
805
|
+
const old = lows16(c);
|
|
806
|
+
const at = lowerBound(old, c.off, c.len, low, 1);
|
|
663
807
|
let u16 = old;
|
|
664
|
-
if (!
|
|
665
|
-
u16.copyWithin(at + 1, at,
|
|
808
|
+
if (!c.shared && c.off === 0 && old.length > c.len) {
|
|
809
|
+
u16.copyWithin(at + 1, at, c.len);
|
|
666
810
|
} else {
|
|
667
|
-
u16 = new Uint16Array(Math.min(ARRAY_MAX_CARDINALITY, Math.max(8,
|
|
668
|
-
u16.set(old.subarray(
|
|
669
|
-
u16.set(old.subarray(
|
|
811
|
+
u16 = new Uint16Array(Math.min(ARRAY_MAX_CARDINALITY, Math.max(8, c.len * 2)));
|
|
812
|
+
u16.set(old.subarray(c.off, c.off + at));
|
|
813
|
+
u16.set(old.subarray(c.off + at, c.off + c.len), at + 1);
|
|
670
814
|
}
|
|
671
815
|
u16[at] = low;
|
|
672
|
-
return arrayContainer(u16,
|
|
816
|
+
return arrayContainer(u16, c.card + 1);
|
|
817
|
+
}
|
|
818
|
+
function addFewToRuns(c, ids, from, to) {
|
|
819
|
+
const x = lows16(c);
|
|
820
|
+
let data = x;
|
|
821
|
+
let base = c.off;
|
|
822
|
+
let out = null;
|
|
823
|
+
let n = c.len;
|
|
824
|
+
let added = 0;
|
|
825
|
+
for (let k = from; k < to; k++) {
|
|
826
|
+
const low = ids[k] & 65535;
|
|
827
|
+
const next = runsAfter(data, base, 0, n, low);
|
|
828
|
+
const prev = next - 1;
|
|
829
|
+
const prevEnd = prev >= 0 ? data[base + 2 * prev] + data[base + 2 * prev + 1] : -2;
|
|
830
|
+
if (prevEnd >= low) continue;
|
|
831
|
+
if (out === null) {
|
|
832
|
+
out = new Uint16Array(2 * (c.len + to - from));
|
|
833
|
+
out.set(x.subarray(c.off, c.off + 2 * c.len));
|
|
834
|
+
data = out;
|
|
835
|
+
base = 0;
|
|
836
|
+
}
|
|
837
|
+
const joinPrev = prevEnd + 1 === low;
|
|
838
|
+
const joinNext = next < n && out[2 * next] === low + 1;
|
|
839
|
+
if (joinPrev && joinNext) {
|
|
840
|
+
out[2 * prev + 1] = out[2 * next] + out[2 * next + 1] - out[2 * prev];
|
|
841
|
+
out.copyWithin(2 * next, 2 * next + 2, 2 * n);
|
|
842
|
+
n--;
|
|
843
|
+
} else if (joinPrev) {
|
|
844
|
+
out[2 * prev + 1] = out[2 * prev + 1] + 1;
|
|
845
|
+
} else if (joinNext) {
|
|
846
|
+
out[2 * next] = low;
|
|
847
|
+
out[2 * next + 1] = out[2 * next + 1] + 1;
|
|
848
|
+
} else {
|
|
849
|
+
out.copyWithin(2 * next + 2, 2 * next, 2 * n);
|
|
850
|
+
out[2 * next] = low;
|
|
851
|
+
out[2 * next + 1] = 0;
|
|
852
|
+
n++;
|
|
853
|
+
}
|
|
854
|
+
added++;
|
|
855
|
+
}
|
|
856
|
+
if (out === null) return c;
|
|
857
|
+
return runsOrPlain(out, n, c.card + added, true);
|
|
858
|
+
}
|
|
859
|
+
function containerAddSorted(c, ids, from, to) {
|
|
860
|
+
if (c.kind === RUN2) return addFewToRuns(c, ids, from, to);
|
|
861
|
+
let cur = c;
|
|
862
|
+
for (let k = from; k < to; k++) cur = containerAdd(cur, ids[k] & 65535);
|
|
863
|
+
return cur;
|
|
673
864
|
}
|
|
674
865
|
function containerRemove(c, low) {
|
|
675
866
|
if (!containerHas(c, low)) return c;
|
|
@@ -691,6 +882,15 @@ function containerRemove(c, low) {
|
|
|
691
882
|
u16.set(old.subarray(plain.off + at + 1, plain.off + plain.len), at);
|
|
692
883
|
return arrayContainer(u16, plain.card - 1);
|
|
693
884
|
}
|
|
885
|
+
function containerMin(c) {
|
|
886
|
+
if (c.kind === ARRAY2 || c.kind === RUN2) return c.data[c.off];
|
|
887
|
+
const words = words32(c);
|
|
888
|
+
for (let i = 0; i < WORDS; i++) {
|
|
889
|
+
const w = words[i];
|
|
890
|
+
if (w !== 0) return i * 32 + 31 - Math.clz32(w & -w);
|
|
891
|
+
}
|
|
892
|
+
throw new RangeError("a bitset container holds no bits");
|
|
893
|
+
}
|
|
694
894
|
function containerMax(c) {
|
|
695
895
|
if (c.kind === ARRAY2) return c.data[c.off + c.len - 1];
|
|
696
896
|
if (c.kind === RUN2) {
|
|
@@ -785,6 +985,7 @@ function skewed(shorter, longer) {
|
|
|
785
985
|
return longer >= GALLOP_SKEW * shorter;
|
|
786
986
|
}
|
|
787
987
|
var PROBE_MIN = 32;
|
|
988
|
+
var MERGE_FIRST = 64;
|
|
788
989
|
var probeWords = new Uint32Array(WORDS);
|
|
789
990
|
function andArrays(a, b) {
|
|
790
991
|
const small = a.len <= b.len ? a : b;
|
|
@@ -959,6 +1160,70 @@ function orArrays(a, b) {
|
|
|
959
1160
|
while (j < je) out[n++] = y[j++];
|
|
960
1161
|
return arrayOfScratch(out, n);
|
|
961
1162
|
}
|
|
1163
|
+
function andWords(out, x, y) {
|
|
1164
|
+
for (let i = 0; i < WORDS; i += 4) {
|
|
1165
|
+
const X0 = x[i];
|
|
1166
|
+
const Y0 = y[i];
|
|
1167
|
+
const X1 = x[i + 1];
|
|
1168
|
+
const Y1 = y[i + 1];
|
|
1169
|
+
const X2 = x[i + 2];
|
|
1170
|
+
const Y2 = y[i + 2];
|
|
1171
|
+
const X3 = x[i + 3];
|
|
1172
|
+
const Y3 = y[i + 3];
|
|
1173
|
+
out[i] = X0 & Y0;
|
|
1174
|
+
out[i + 1] = X1 & Y1;
|
|
1175
|
+
out[i + 2] = X2 & Y2;
|
|
1176
|
+
out[i + 3] = X3 & Y3;
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
function orWords(out, x, y) {
|
|
1180
|
+
for (let i = 0; i < WORDS; i += 4) {
|
|
1181
|
+
const X0 = x[i];
|
|
1182
|
+
const Y0 = y[i];
|
|
1183
|
+
const X1 = x[i + 1];
|
|
1184
|
+
const Y1 = y[i + 1];
|
|
1185
|
+
const X2 = x[i + 2];
|
|
1186
|
+
const Y2 = y[i + 2];
|
|
1187
|
+
const X3 = x[i + 3];
|
|
1188
|
+
const Y3 = y[i + 3];
|
|
1189
|
+
out[i] = X0 | Y0;
|
|
1190
|
+
out[i + 1] = X1 | Y1;
|
|
1191
|
+
out[i + 2] = X2 | Y2;
|
|
1192
|
+
out[i + 3] = X3 | Y3;
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
function xorWords(out, x, y) {
|
|
1196
|
+
for (let i = 0; i < WORDS; i += 4) {
|
|
1197
|
+
const X0 = x[i];
|
|
1198
|
+
const Y0 = y[i];
|
|
1199
|
+
const X1 = x[i + 1];
|
|
1200
|
+
const Y1 = y[i + 1];
|
|
1201
|
+
const X2 = x[i + 2];
|
|
1202
|
+
const Y2 = y[i + 2];
|
|
1203
|
+
const X3 = x[i + 3];
|
|
1204
|
+
const Y3 = y[i + 3];
|
|
1205
|
+
out[i] = X0 ^ Y0;
|
|
1206
|
+
out[i + 1] = X1 ^ Y1;
|
|
1207
|
+
out[i + 2] = X2 ^ Y2;
|
|
1208
|
+
out[i + 3] = X3 ^ Y3;
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
function andNotWords(out, x, y) {
|
|
1212
|
+
for (let i = 0; i < WORDS; i += 4) {
|
|
1213
|
+
const X0 = x[i];
|
|
1214
|
+
const Y0 = y[i];
|
|
1215
|
+
const X1 = x[i + 1];
|
|
1216
|
+
const Y1 = y[i + 1];
|
|
1217
|
+
const X2 = x[i + 2];
|
|
1218
|
+
const Y2 = y[i + 2];
|
|
1219
|
+
const X3 = x[i + 3];
|
|
1220
|
+
const Y3 = y[i + 3];
|
|
1221
|
+
out[i] = X0 & ~Y0;
|
|
1222
|
+
out[i + 1] = X1 & ~Y1;
|
|
1223
|
+
out[i + 2] = X2 & ~Y2;
|
|
1224
|
+
out[i + 3] = X3 & ~Y3;
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
962
1227
|
function orIntoBitset(dest, other, inPlace) {
|
|
963
1228
|
const words = inPlace ? words32(dest) : words32(dest).slice();
|
|
964
1229
|
if (other.kind === ARRAY2) {
|
|
@@ -976,8 +1241,7 @@ function orIntoBitset(dest, other, inPlace) {
|
|
|
976
1241
|
return bitsetContainer(words, card);
|
|
977
1242
|
}
|
|
978
1243
|
if (other.kind === BITSET) {
|
|
979
|
-
|
|
980
|
-
for (let i = 0; i < WORDS; i++) words[i] = words[i] | o[i];
|
|
1244
|
+
orWords(words, words, words32(other));
|
|
981
1245
|
} else {
|
|
982
1246
|
const pairs = lows16(other);
|
|
983
1247
|
for (let r = 0; r < other.len; r++) {
|
|
@@ -987,6 +1251,81 @@ function orIntoBitset(dest, other, inPlace) {
|
|
|
987
1251
|
}
|
|
988
1252
|
return bitsetContainer(words, popcountWords(words));
|
|
989
1253
|
}
|
|
1254
|
+
function orBitsetWords(list) {
|
|
1255
|
+
const bits = [];
|
|
1256
|
+
for (const c of list) if (c.kind === BITSET) bits.push(words32(c));
|
|
1257
|
+
const n = bits.length;
|
|
1258
|
+
if (n === 0) return new Uint32Array(WORDS);
|
|
1259
|
+
let k;
|
|
1260
|
+
let words;
|
|
1261
|
+
if (n >= 4) {
|
|
1262
|
+
const a = bits[0];
|
|
1263
|
+
const b = bits[1];
|
|
1264
|
+
const c = bits[2];
|
|
1265
|
+
const d = bits[3];
|
|
1266
|
+
words = new Uint32Array(WORDS);
|
|
1267
|
+
for (let i = 0; i < WORDS; i++)
|
|
1268
|
+
words[i] = a[i] | b[i] | c[i] | d[i];
|
|
1269
|
+
k = 4;
|
|
1270
|
+
} else {
|
|
1271
|
+
words = bits[0].slice();
|
|
1272
|
+
k = 1;
|
|
1273
|
+
}
|
|
1274
|
+
for (; k + 4 <= n; k += 4) {
|
|
1275
|
+
const a = bits[k];
|
|
1276
|
+
const b = bits[k + 1];
|
|
1277
|
+
const c = bits[k + 2];
|
|
1278
|
+
const d = bits[k + 3];
|
|
1279
|
+
for (let i = 0; i < WORDS; i++) {
|
|
1280
|
+
words[i] = words[i] | a[i] | b[i] | c[i] | d[i];
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
for (; k < n; k++) {
|
|
1284
|
+
const o = bits[k];
|
|
1285
|
+
for (let i = 0; i < WORDS; i++) words[i] = words[i] | o[i];
|
|
1286
|
+
}
|
|
1287
|
+
return words;
|
|
1288
|
+
}
|
|
1289
|
+
function orManyContainers(list) {
|
|
1290
|
+
let total = 0;
|
|
1291
|
+
let allArrays = true;
|
|
1292
|
+
for (const c of list) {
|
|
1293
|
+
total += c.card;
|
|
1294
|
+
if (c.kind !== ARRAY2) allArrays = false;
|
|
1295
|
+
}
|
|
1296
|
+
if (allArrays && total <= ARRAY_MAX_CARDINALITY) {
|
|
1297
|
+
const out = values16(total);
|
|
1298
|
+
let n = 0;
|
|
1299
|
+
for (const c of list) {
|
|
1300
|
+
out.set(lows16(c).subarray(c.off, c.off + c.len), n);
|
|
1301
|
+
n += c.len;
|
|
1302
|
+
}
|
|
1303
|
+
const sorted = out.subarray(0, n).sort();
|
|
1304
|
+
let distinct = 0;
|
|
1305
|
+
for (let i = 0; i < n; i++) {
|
|
1306
|
+
const v = sorted[i];
|
|
1307
|
+
if (i === 0 || v !== sorted[distinct - 1]) sorted[distinct++] = v;
|
|
1308
|
+
}
|
|
1309
|
+
return arrayContainer(sorted.slice(0, distinct), distinct);
|
|
1310
|
+
}
|
|
1311
|
+
const words = orBitsetWords(list);
|
|
1312
|
+
for (const c of list) {
|
|
1313
|
+
if (c.kind === ARRAY2) {
|
|
1314
|
+
const u16 = lows16(c);
|
|
1315
|
+
for (let i = c.off; i < c.off + c.len; i++) {
|
|
1316
|
+
const v = u16[i];
|
|
1317
|
+
words[v >>> 5] = words[v >>> 5] | 1 << (v & 31);
|
|
1318
|
+
}
|
|
1319
|
+
} else if (c.kind === RUN2) {
|
|
1320
|
+
const pairs = lows16(c);
|
|
1321
|
+
for (let r = 0; r < c.len; r++) {
|
|
1322
|
+
const start = pairs[c.off + 2 * r];
|
|
1323
|
+
setRange(words, start, start + pairs[c.off + 2 * r + 1]);
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
return fromWordsCard(words, popcountWords(words));
|
|
1328
|
+
}
|
|
990
1329
|
function fromRunPairs(pairs, runs, card) {
|
|
991
1330
|
if (card === 0) return null;
|
|
992
1331
|
if (card <= ARRAY_MAX_CARDINALITY) {
|
|
@@ -1030,7 +1369,7 @@ function andRuns(a, b) {
|
|
|
1030
1369
|
if (ae < be) i++;
|
|
1031
1370
|
else j++;
|
|
1032
1371
|
}
|
|
1033
|
-
return
|
|
1372
|
+
return card === 0 ? null : runsOrPlain(out, runs, card, true);
|
|
1034
1373
|
}
|
|
1035
1374
|
function orRuns(a, b) {
|
|
1036
1375
|
const x = lows16(a);
|
|
@@ -1070,7 +1409,7 @@ function orRuns(a, b) {
|
|
|
1070
1409
|
}
|
|
1071
1410
|
}
|
|
1072
1411
|
flush();
|
|
1073
|
-
return
|
|
1412
|
+
return runsOrPlain(out, runs, card, true);
|
|
1074
1413
|
}
|
|
1075
1414
|
function andNotRuns(a, b) {
|
|
1076
1415
|
const x = lows16(a);
|
|
@@ -1104,7 +1443,7 @@ function andNotRuns(a, b) {
|
|
|
1104
1443
|
k++;
|
|
1105
1444
|
}
|
|
1106
1445
|
}
|
|
1107
|
-
return
|
|
1446
|
+
return card === 0 ? null : runsOrPlain(out, runs, card, true);
|
|
1108
1447
|
}
|
|
1109
1448
|
function bitsetInRuns(a, b) {
|
|
1110
1449
|
const words = words32(a);
|
|
@@ -1156,7 +1495,7 @@ function containerAnd(a, b, inPlace = false) {
|
|
|
1156
1495
|
const x = words32(a);
|
|
1157
1496
|
const y = words32(b);
|
|
1158
1497
|
const out = inPlace ? x : new Uint32Array(WORDS);
|
|
1159
|
-
|
|
1498
|
+
andWords(out, x, y);
|
|
1160
1499
|
return fromWordsCard(out, popcountWords(out));
|
|
1161
1500
|
}
|
|
1162
1501
|
if (a.kind > b.kind) return containerAnd(b, a);
|
|
@@ -1164,48 +1503,738 @@ function containerAnd(a, b, inPlace = false) {
|
|
|
1164
1503
|
if (b.kind === ARRAY2) return andArrays(a, b);
|
|
1165
1504
|
return b.kind === BITSET ? filterByBits(a, b, true) : filterByRuns(a, b, true);
|
|
1166
1505
|
}
|
|
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
|
-
|
|
1175
|
-
|
|
1506
|
+
return b.kind === RUN2 && a.kind === RUN2 ? andRuns(a, b) : bitsetInRuns(a, b);
|
|
1507
|
+
}
|
|
1508
|
+
function containerOr(a, b, inPlace = false) {
|
|
1509
|
+
if (a.kind === BITSET) return orIntoBitset(a, b, inPlace);
|
|
1510
|
+
if (b.kind === BITSET) return orIntoBitset(b, a, false);
|
|
1511
|
+
if (a.kind === ARRAY2 && b.kind === ARRAY2) return orArrays(a, b);
|
|
1512
|
+
if (a.kind === RUN2 && b.kind === RUN2) return orRuns(a, b);
|
|
1513
|
+
return a.kind === RUN2 ? orRunArray(a, b, inPlace) : orRunArray(b, a, false);
|
|
1514
|
+
}
|
|
1515
|
+
var EXPAND_MIN_STEPS = 1024;
|
|
1516
|
+
function expandsRunArray(runs, array) {
|
|
1517
|
+
return expandsRunSteps(runs, array.len);
|
|
1518
|
+
}
|
|
1519
|
+
function expandsRunSteps(runs, values) {
|
|
1520
|
+
const steps = runs.len + values;
|
|
1521
|
+
if (steps < EXPAND_MIN_STEPS) return false;
|
|
1522
|
+
const cardMax = runs.card + values;
|
|
1523
|
+
const plainMax = cardMax <= ARRAY_MAX_CARDINALITY ? 2 * cardMax : BITSET_BYTES;
|
|
1524
|
+
return 2 + 4 * steps >= plainMax;
|
|
1525
|
+
}
|
|
1526
|
+
function walksRunIds(runs, count) {
|
|
1527
|
+
return runs.kind === RUN2 && !expandsRunSteps(runs, count);
|
|
1528
|
+
}
|
|
1529
|
+
function orRunArrayExpand(runs, array, keep) {
|
|
1530
|
+
const words = toWords(runs);
|
|
1531
|
+
const v = lows16(array);
|
|
1532
|
+
let added = 0;
|
|
1533
|
+
for (let i = array.off; i < array.off + array.len; i++) {
|
|
1534
|
+
const value = v[i];
|
|
1535
|
+
const word = words[value >>> 5];
|
|
1536
|
+
const bit = 1 << (value & 31);
|
|
1537
|
+
if ((word & bit) === 0) {
|
|
1538
|
+
words[value >>> 5] = word | bit;
|
|
1539
|
+
added++;
|
|
1540
|
+
}
|
|
1541
|
+
}
|
|
1542
|
+
if (added === 0 && keep) return runs;
|
|
1543
|
+
return optimize(fromWordsCard(words, runs.card + added));
|
|
1544
|
+
}
|
|
1545
|
+
function orRunArray(runs, array, keep) {
|
|
1546
|
+
return expandsRunArray(runs, array) ? orRunArrayExpand(runs, array, keep) : orRunArrayWalk(runs, array, keep);
|
|
1547
|
+
}
|
|
1548
|
+
function orRunArrayWalk(runs, array, keep) {
|
|
1549
|
+
const x = lows16(runs);
|
|
1550
|
+
const v = lows16(array);
|
|
1551
|
+
const out = pairs16(2 * (runs.len + array.len));
|
|
1552
|
+
const runEnd = runs.off + 2 * runs.len;
|
|
1553
|
+
const valueEnd = array.off + array.len;
|
|
1554
|
+
let r = runs.off;
|
|
1555
|
+
let vi = array.off;
|
|
1556
|
+
let at = 0;
|
|
1557
|
+
let from = 0;
|
|
1558
|
+
let to = -2;
|
|
1559
|
+
let added = 0;
|
|
1560
|
+
while (vi < valueEnd) {
|
|
1561
|
+
const value = v[vi++];
|
|
1562
|
+
while (r < runEnd && x[r] <= value) {
|
|
1563
|
+
const start = x[r];
|
|
1564
|
+
const end = start + x[r + 1];
|
|
1565
|
+
r += 2;
|
|
1566
|
+
if (start <= to + 1) {
|
|
1567
|
+
if (end > to) to = end;
|
|
1568
|
+
} else {
|
|
1569
|
+
if (to >= 0) {
|
|
1570
|
+
out[at++] = from;
|
|
1571
|
+
out[at++] = to - from;
|
|
1572
|
+
}
|
|
1573
|
+
from = start;
|
|
1574
|
+
to = end;
|
|
1575
|
+
}
|
|
1576
|
+
}
|
|
1577
|
+
if (value <= to) continue;
|
|
1578
|
+
added++;
|
|
1579
|
+
if (value === to + 1) {
|
|
1580
|
+
to = value;
|
|
1581
|
+
} else {
|
|
1582
|
+
if (to >= 0) {
|
|
1583
|
+
out[at++] = from;
|
|
1584
|
+
out[at++] = to - from;
|
|
1585
|
+
}
|
|
1586
|
+
from = value;
|
|
1587
|
+
to = value;
|
|
1588
|
+
}
|
|
1589
|
+
}
|
|
1590
|
+
while (r < runEnd) {
|
|
1591
|
+
const start = x[r];
|
|
1592
|
+
const end = start + x[r + 1];
|
|
1593
|
+
r += 2;
|
|
1594
|
+
if (start <= to + 1) {
|
|
1595
|
+
if (end > to) to = end;
|
|
1596
|
+
} else {
|
|
1597
|
+
if (to >= 0) {
|
|
1598
|
+
out[at++] = from;
|
|
1599
|
+
out[at++] = to - from;
|
|
1600
|
+
}
|
|
1601
|
+
from = start;
|
|
1602
|
+
to = end;
|
|
1603
|
+
}
|
|
1604
|
+
}
|
|
1605
|
+
out[at++] = from;
|
|
1606
|
+
out[at++] = to - from;
|
|
1607
|
+
if (added === 0 && keep) return runs;
|
|
1608
|
+
return runsOrPlain(out, at >>> 1, runs.card + added, true);
|
|
1609
|
+
}
|
|
1610
|
+
function orRunIdsWalk(runs, ids, from, to) {
|
|
1611
|
+
const x = lows16(runs);
|
|
1612
|
+
const out = pairs16(2 * (runs.len + to - from));
|
|
1613
|
+
const runEnd = runs.off + 2 * runs.len;
|
|
1614
|
+
let r = runs.off;
|
|
1615
|
+
let vi = from;
|
|
1616
|
+
let at = 0;
|
|
1617
|
+
let start = 0;
|
|
1618
|
+
let last = -2;
|
|
1619
|
+
let added = 0;
|
|
1620
|
+
while (vi < to) {
|
|
1621
|
+
const value = ids[vi++] & 65535;
|
|
1622
|
+
while (r < runEnd && x[r] <= value) {
|
|
1623
|
+
const s = x[r];
|
|
1624
|
+
const end = s + x[r + 1];
|
|
1625
|
+
r += 2;
|
|
1626
|
+
if (s <= last + 1) {
|
|
1627
|
+
if (end > last) last = end;
|
|
1628
|
+
} else {
|
|
1629
|
+
if (last >= 0) {
|
|
1630
|
+
out[at++] = start;
|
|
1631
|
+
out[at++] = last - start;
|
|
1632
|
+
}
|
|
1633
|
+
start = s;
|
|
1634
|
+
last = end;
|
|
1635
|
+
}
|
|
1636
|
+
}
|
|
1637
|
+
if (value <= last) continue;
|
|
1638
|
+
added++;
|
|
1639
|
+
if (value === last + 1) {
|
|
1640
|
+
last = value;
|
|
1641
|
+
} else {
|
|
1642
|
+
if (last >= 0) {
|
|
1643
|
+
out[at++] = start;
|
|
1644
|
+
out[at++] = last - start;
|
|
1645
|
+
}
|
|
1646
|
+
start = value;
|
|
1647
|
+
last = value;
|
|
1648
|
+
}
|
|
1649
|
+
}
|
|
1650
|
+
while (r < runEnd) {
|
|
1651
|
+
const s = x[r];
|
|
1652
|
+
const end = s + x[r + 1];
|
|
1653
|
+
r += 2;
|
|
1654
|
+
if (s <= last + 1) {
|
|
1655
|
+
if (end > last) last = end;
|
|
1656
|
+
} else {
|
|
1657
|
+
if (last >= 0) {
|
|
1658
|
+
out[at++] = start;
|
|
1659
|
+
out[at++] = last - start;
|
|
1660
|
+
}
|
|
1661
|
+
start = s;
|
|
1662
|
+
last = end;
|
|
1663
|
+
}
|
|
1664
|
+
}
|
|
1665
|
+
out[at++] = start;
|
|
1666
|
+
out[at++] = last - start;
|
|
1667
|
+
if (added === 0) return runs;
|
|
1668
|
+
return runsOrPlain(out, at >>> 1, runs.card + added, true);
|
|
1669
|
+
}
|
|
1670
|
+
function containerAndNot(a, b, inPlace = false) {
|
|
1671
|
+
if (a.kind === ARRAY2) {
|
|
1672
|
+
if (b.kind === ARRAY2) return andNotArrays(a, b);
|
|
1673
|
+
return b.kind === BITSET ? filterByBits(a, b, false) : filterByRuns(a, b, false);
|
|
1674
|
+
}
|
|
1675
|
+
if (a.kind === RUN2 && b.kind === RUN2) return andNotRuns(a, b);
|
|
1676
|
+
const words = a.kind === BITSET ? inPlace ? words32(a) : words32(a).slice() : toWords(a);
|
|
1677
|
+
if (b.kind === ARRAY2) {
|
|
1678
|
+
const u16 = lows16(b);
|
|
1679
|
+
for (let i = b.off; i < b.off + b.len; i++) {
|
|
1680
|
+
const v = u16[i];
|
|
1681
|
+
words[v >>> 5] = words[v >>> 5] & ~(1 << (v & 31));
|
|
1682
|
+
}
|
|
1683
|
+
} else if (b.kind === BITSET) {
|
|
1684
|
+
andNotWords(words, words, words32(b));
|
|
1685
|
+
} else {
|
|
1686
|
+
const pairs = lows16(b);
|
|
1687
|
+
for (let r = 0; r < b.len; r++) {
|
|
1688
|
+
const start = pairs[b.off + 2 * r];
|
|
1689
|
+
clearRange(words, start, start + pairs[b.off + 2 * r + 1]);
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1692
|
+
return fromWordsCard(words, popcountWords(words));
|
|
1693
|
+
}
|
|
1694
|
+
function xorArrays(a, b) {
|
|
1695
|
+
const x = lows16(a);
|
|
1696
|
+
const y = lows16(b);
|
|
1697
|
+
const ie = a.off + a.len;
|
|
1698
|
+
const je = b.off + b.len;
|
|
1699
|
+
const out = values16(a.len + b.len);
|
|
1700
|
+
let n = 0;
|
|
1701
|
+
let i = a.off;
|
|
1702
|
+
let j = b.off;
|
|
1703
|
+
while (i < ie && j < je) {
|
|
1704
|
+
const p = x[i];
|
|
1705
|
+
const q = y[j];
|
|
1706
|
+
out[n] = p < q ? p : q;
|
|
1707
|
+
n += p === q ? 0 : 1;
|
|
1708
|
+
i += p <= q ? 1 : 0;
|
|
1709
|
+
j += p >= q ? 1 : 0;
|
|
1710
|
+
}
|
|
1711
|
+
while (i < ie) out[n++] = x[i++];
|
|
1712
|
+
while (j < je) out[n++] = y[j++];
|
|
1713
|
+
if (n <= ARRAY_MAX_CARDINALITY) return arrayOfScratch(out, n);
|
|
1714
|
+
const words = new Uint32Array(WORDS);
|
|
1715
|
+
for (let k = 0; k < n; k++) {
|
|
1716
|
+
const v = out[k];
|
|
1717
|
+
words[v >>> 5] = words[v >>> 5] | 1 << (v & 31);
|
|
1718
|
+
}
|
|
1719
|
+
return bitsetContainer(words, n);
|
|
1720
|
+
}
|
|
1721
|
+
function xorRuns(a, b) {
|
|
1722
|
+
const x = lows16(a);
|
|
1723
|
+
const y = lows16(b);
|
|
1724
|
+
const na = 2 * a.len;
|
|
1725
|
+
const nb = 2 * b.len;
|
|
1726
|
+
const out = pairs16(2 * (a.len + b.len));
|
|
1727
|
+
const NONE = 2147483647;
|
|
1728
|
+
let i = 0;
|
|
1729
|
+
let j = 0;
|
|
1730
|
+
let pa = na > 0 ? boundary(x, a.off, 0) : NONE;
|
|
1731
|
+
let pb = nb > 0 ? boundary(y, b.off, 0) : NONE;
|
|
1732
|
+
let open2 = -1;
|
|
1733
|
+
let runs = 0;
|
|
1734
|
+
let card = 0;
|
|
1735
|
+
while (i < na || j < nb) {
|
|
1736
|
+
let p;
|
|
1737
|
+
if (pa === pb) {
|
|
1738
|
+
i++;
|
|
1739
|
+
j++;
|
|
1740
|
+
pa = i < na ? boundary(x, a.off, i) : NONE;
|
|
1741
|
+
pb = j < nb ? boundary(y, b.off, j) : NONE;
|
|
1742
|
+
continue;
|
|
1743
|
+
}
|
|
1744
|
+
if (pa < pb) {
|
|
1745
|
+
p = pa;
|
|
1746
|
+
i++;
|
|
1747
|
+
pa = i < na ? boundary(x, a.off, i) : NONE;
|
|
1748
|
+
} else {
|
|
1749
|
+
p = pb;
|
|
1750
|
+
j++;
|
|
1751
|
+
pb = j < nb ? boundary(y, b.off, j) : NONE;
|
|
1752
|
+
}
|
|
1753
|
+
if (open2 < 0) {
|
|
1754
|
+
open2 = p;
|
|
1755
|
+
} else {
|
|
1756
|
+
out[2 * runs] = open2;
|
|
1757
|
+
out[2 * runs + 1] = p - 1 - open2;
|
|
1758
|
+
runs++;
|
|
1759
|
+
card += p - open2;
|
|
1760
|
+
open2 = -1;
|
|
1761
|
+
}
|
|
1762
|
+
}
|
|
1763
|
+
return card === 0 ? null : runsOrPlain(out, runs, card, true);
|
|
1764
|
+
}
|
|
1765
|
+
function boundary(u16, off, k) {
|
|
1766
|
+
const at = off + (k & ~1);
|
|
1767
|
+
return u16[at] + ((k & 1) === 0 ? 0 : u16[at + 1] + 1);
|
|
1768
|
+
}
|
|
1769
|
+
function containerXor(a, b, inPlace = false) {
|
|
1770
|
+
if (a.kind === BITSET || b.kind === BITSET) {
|
|
1771
|
+
const base = a.kind === BITSET ? a : b;
|
|
1772
|
+
const other = base === a ? b : a;
|
|
1773
|
+
if (other.kind === BITSET) {
|
|
1774
|
+
const x = words32(a);
|
|
1775
|
+
const y = words32(b);
|
|
1776
|
+
const out = inPlace ? x : new Uint32Array(WORDS);
|
|
1777
|
+
xorWords(out, x, y);
|
|
1778
|
+
return fromWordsCard(out, popcountWords(out));
|
|
1779
|
+
}
|
|
1780
|
+
const words2 = inPlace && base === a ? words32(base) : words32(base).slice();
|
|
1781
|
+
if (other.kind === ARRAY2) {
|
|
1782
|
+
return fromWordsCard(words2, flipValues(words2, other, base.card));
|
|
1783
|
+
}
|
|
1784
|
+
const pairs = lows16(other);
|
|
1785
|
+
for (let r = 0; r < other.len; r++) {
|
|
1786
|
+
const start = pairs[other.off + 2 * r];
|
|
1787
|
+
flipRange(words2, start, start + pairs[other.off + 2 * r + 1]);
|
|
1788
|
+
}
|
|
1789
|
+
return fromWordsCard(words2, popcountWords(words2));
|
|
1790
|
+
}
|
|
1791
|
+
if (a.kind === ARRAY2 && b.kind === ARRAY2) return xorArrays(a, b);
|
|
1792
|
+
if (a.kind === RUN2 && b.kind === RUN2) return xorRuns(a, b);
|
|
1793
|
+
const runs = a.kind === RUN2 ? a : b;
|
|
1794
|
+
const array = runs === a ? b : a;
|
|
1795
|
+
const words = toWords(runs);
|
|
1796
|
+
return fromWordsCard(words, flipValues(words, array, runs.card));
|
|
1797
|
+
}
|
|
1798
|
+
function flipValues(words, array, card) {
|
|
1799
|
+
const u16 = lows16(array);
|
|
1800
|
+
let n = card;
|
|
1801
|
+
for (let i = array.off; i < array.off + array.len; i++) {
|
|
1802
|
+
const v = u16[i];
|
|
1803
|
+
const w = words[v >>> 5];
|
|
1804
|
+
words[v >>> 5] = w ^ 1 << (v & 31);
|
|
1805
|
+
n += 1 - 2 * (w >>> (v & 31) & 1);
|
|
1806
|
+
}
|
|
1807
|
+
return n;
|
|
1808
|
+
}
|
|
1809
|
+
function bitsInRange(words, start, end) {
|
|
1810
|
+
const first = start >>> 5;
|
|
1811
|
+
const last = end >>> 5;
|
|
1812
|
+
const head = 4294967295 << (start & 31) >>> 0;
|
|
1813
|
+
const tail = 4294967295 >>> 31 - (end & 31);
|
|
1814
|
+
if (first === last) return popcount32(words[first] & head & tail);
|
|
1815
|
+
let n = popcount32(words[first] & head) + popcount32(words[last] & tail);
|
|
1816
|
+
for (let i = first + 1; i < last; i++) n += popcount32(words[i]);
|
|
1817
|
+
return n;
|
|
1818
|
+
}
|
|
1819
|
+
function andCountArrays(a, b) {
|
|
1820
|
+
const small = a.len <= b.len ? a : b;
|
|
1821
|
+
const big = small === a ? b : a;
|
|
1822
|
+
const s = lows16(small);
|
|
1823
|
+
const l = lows16(big);
|
|
1824
|
+
const se = small.off + small.len;
|
|
1825
|
+
const le = big.off + big.len;
|
|
1826
|
+
let n = 0;
|
|
1827
|
+
if (skewed(small.len, big.len)) {
|
|
1828
|
+
let at = big.off;
|
|
1829
|
+
for (let i2 = small.off; i2 < se; i2++) {
|
|
1830
|
+
const v = s[i2];
|
|
1831
|
+
at = gallop(l, 0, at, le, v);
|
|
1832
|
+
if (at === le) break;
|
|
1833
|
+
if (l[at] === v) n++;
|
|
1834
|
+
}
|
|
1835
|
+
return n;
|
|
1836
|
+
}
|
|
1837
|
+
if (small.len >= PROBE_MIN) {
|
|
1838
|
+
const first = s[small.off];
|
|
1839
|
+
const last = s[se - 1];
|
|
1840
|
+
if (last < l[big.off] || first > l[le - 1]) return 0;
|
|
1841
|
+
const from = gallop(l, 0, big.off, le, first);
|
|
1842
|
+
const to = gallop(l, 0, from, le, last + 1);
|
|
1843
|
+
const words = probeWords;
|
|
1844
|
+
for (let i2 = small.off; i2 < se; i2++) {
|
|
1845
|
+
const v = s[i2];
|
|
1846
|
+
words[v >>> 5] = words[v >>> 5] | 1 << (v & 31);
|
|
1847
|
+
}
|
|
1848
|
+
for (let j2 = from; j2 < to; j2++) {
|
|
1849
|
+
const v = l[j2];
|
|
1850
|
+
n += words[v >>> 5] >>> (v & 31) & 1;
|
|
1851
|
+
}
|
|
1852
|
+
for (let i2 = small.off; i2 < se; i2++) words[s[i2] >>> 5] = 0;
|
|
1853
|
+
return n;
|
|
1854
|
+
}
|
|
1855
|
+
let i = small.off;
|
|
1856
|
+
let j = big.off;
|
|
1857
|
+
while (i < se && j < le) {
|
|
1858
|
+
const x = s[i];
|
|
1859
|
+
const y = l[j];
|
|
1860
|
+
n += x === y ? 1 : 0;
|
|
1861
|
+
i += x <= y ? 1 : 0;
|
|
1862
|
+
j += x >= y ? 1 : 0;
|
|
1863
|
+
}
|
|
1864
|
+
return n;
|
|
1865
|
+
}
|
|
1866
|
+
function andCountArrayBitset(a, b) {
|
|
1867
|
+
const u16 = lows16(a);
|
|
1868
|
+
const words = words32(b);
|
|
1869
|
+
let n = 0;
|
|
1870
|
+
for (let i = a.off; i < a.off + a.len; i++) {
|
|
1871
|
+
const v = u16[i];
|
|
1872
|
+
n += words[v >>> 5] >>> (v & 31) & 1;
|
|
1873
|
+
}
|
|
1874
|
+
return n;
|
|
1875
|
+
}
|
|
1876
|
+
function andCountArrayRuns(a, b) {
|
|
1877
|
+
const u16 = lows16(a);
|
|
1878
|
+
const pairs = lows16(b);
|
|
1879
|
+
const ae = a.off + a.len;
|
|
1880
|
+
let n = 0;
|
|
1881
|
+
if (skewed(a.len, b.len)) {
|
|
1882
|
+
for (let i2 = a.off; i2 < ae; i2++) {
|
|
1883
|
+
const v = u16[i2];
|
|
1884
|
+
const after = lowerBound(pairs, b.off, b.len, v + 1, 2);
|
|
1885
|
+
if (after === 0) continue;
|
|
1886
|
+
const r = b.off + 2 * (after - 1);
|
|
1887
|
+
if (v <= pairs[r] + pairs[r + 1]) n++;
|
|
1888
|
+
}
|
|
1889
|
+
return n;
|
|
1890
|
+
}
|
|
1891
|
+
let i = a.off;
|
|
1892
|
+
for (let r = 0; r < b.len && i < ae; r++) {
|
|
1893
|
+
const start = pairs[b.off + 2 * r];
|
|
1894
|
+
const end = start + pairs[b.off + 2 * r + 1];
|
|
1895
|
+
while (i < ae && u16[i] < start) i++;
|
|
1896
|
+
while (i < ae && u16[i] <= end) {
|
|
1897
|
+
n++;
|
|
1898
|
+
i++;
|
|
1899
|
+
}
|
|
1900
|
+
}
|
|
1901
|
+
return n;
|
|
1902
|
+
}
|
|
1903
|
+
function andCountBitsetRuns(a, b) {
|
|
1904
|
+
const words = words32(a);
|
|
1905
|
+
const pairs = lows16(b);
|
|
1906
|
+
let n = 0;
|
|
1907
|
+
for (let r = 0; r < b.len; r++) {
|
|
1908
|
+
const start = pairs[b.off + 2 * r];
|
|
1909
|
+
n += bitsInRange(words, start, start + pairs[b.off + 2 * r + 1]);
|
|
1910
|
+
}
|
|
1911
|
+
return n;
|
|
1912
|
+
}
|
|
1913
|
+
function andCountRuns(a, b) {
|
|
1914
|
+
const x = lows16(a);
|
|
1915
|
+
const y = lows16(b);
|
|
1916
|
+
let n = 0;
|
|
1917
|
+
let i = 0;
|
|
1918
|
+
let j = 0;
|
|
1919
|
+
while (i < a.len && j < b.len) {
|
|
1920
|
+
const as = x[a.off + 2 * i];
|
|
1921
|
+
const ae = as + x[a.off + 2 * i + 1];
|
|
1922
|
+
const bs = y[b.off + 2 * j];
|
|
1923
|
+
const be = bs + y[b.off + 2 * j + 1];
|
|
1924
|
+
const lo = as > bs ? as : bs;
|
|
1925
|
+
const hi = ae < be ? ae : be;
|
|
1926
|
+
if (lo <= hi) n += hi - lo + 1;
|
|
1927
|
+
if (ae < be) i++;
|
|
1928
|
+
else j++;
|
|
1929
|
+
}
|
|
1930
|
+
return n;
|
|
1931
|
+
}
|
|
1932
|
+
function containerAndCard(a, b) {
|
|
1933
|
+
if (a.kind === BITSET && b.kind === BITSET) {
|
|
1934
|
+
return popcountAnd(words32(a), words32(b));
|
|
1935
|
+
}
|
|
1936
|
+
if (a.kind > b.kind) return containerAndCard(b, a);
|
|
1937
|
+
if (a.kind === ARRAY2) {
|
|
1938
|
+
if (b.kind === ARRAY2) return andCountArrays(a, b);
|
|
1939
|
+
return b.kind === BITSET ? andCountArrayBitset(a, b) : andCountArrayRuns(a, b);
|
|
1940
|
+
}
|
|
1941
|
+
return b.kind === RUN2 && a.kind === RUN2 ? andCountRuns(a, b) : andCountBitsetRuns(a, b);
|
|
1942
|
+
}
|
|
1943
|
+
function anyBitInRange(words, start, end) {
|
|
1944
|
+
const first = start >>> 5;
|
|
1945
|
+
const last = end >>> 5;
|
|
1946
|
+
const head = 4294967295 << (start & 31) >>> 0;
|
|
1947
|
+
const tail = 4294967295 >>> 31 - (end & 31);
|
|
1948
|
+
if (first === last) return (words[first] & head & tail) !== 0;
|
|
1949
|
+
if ((words[first] & head) !== 0 || (words[last] & tail) !== 0)
|
|
1950
|
+
return true;
|
|
1951
|
+
for (let i = first + 1; i < last; i++) if (words[i] !== 0) return true;
|
|
1952
|
+
return false;
|
|
1953
|
+
}
|
|
1954
|
+
function allBitsInRange(words, start, end) {
|
|
1955
|
+
const first = start >>> 5;
|
|
1956
|
+
const last = end >>> 5;
|
|
1957
|
+
const head = 4294967295 << (start & 31) >>> 0;
|
|
1958
|
+
const tail = 4294967295 >>> 31 - (end & 31);
|
|
1959
|
+
if (first === last) return (~words[first] & head & tail) === 0;
|
|
1960
|
+
if ((~words[first] & head) !== 0 || (~words[last] & tail) !== 0)
|
|
1961
|
+
return false;
|
|
1962
|
+
for (let i = first + 1; i < last; i++) if (words[i] !== 4294967295) return false;
|
|
1963
|
+
return true;
|
|
1964
|
+
}
|
|
1965
|
+
function subsetArrays(a, b) {
|
|
1966
|
+
const x = lows16(a);
|
|
1967
|
+
const y = lows16(b);
|
|
1968
|
+
const ie = a.off + a.len;
|
|
1969
|
+
const je = b.off + b.len;
|
|
1970
|
+
let j = b.off;
|
|
1971
|
+
if (skewed(a.len, b.len)) {
|
|
1972
|
+
for (let i2 = a.off; i2 < ie; i2++) {
|
|
1973
|
+
const v = x[i2];
|
|
1974
|
+
j = gallop(y, 0, j, je, v);
|
|
1975
|
+
if (j === je || y[j] !== v) return false;
|
|
1976
|
+
}
|
|
1977
|
+
return true;
|
|
1978
|
+
}
|
|
1979
|
+
let i = a.off;
|
|
1980
|
+
while (i < ie && j < je) {
|
|
1981
|
+
const p = x[i];
|
|
1982
|
+
const q = y[j];
|
|
1983
|
+
if (p < q) return false;
|
|
1984
|
+
i += p === q ? 1 : 0;
|
|
1985
|
+
j++;
|
|
1986
|
+
}
|
|
1987
|
+
return i === ie;
|
|
1988
|
+
}
|
|
1989
|
+
function subsetArrayRuns(a, b) {
|
|
1990
|
+
const u16 = lows16(a);
|
|
1991
|
+
const pairs = lows16(b);
|
|
1992
|
+
let r = 0;
|
|
1993
|
+
for (let i = a.off; i < a.off + a.len; i++) {
|
|
1994
|
+
const v = u16[i];
|
|
1995
|
+
while (r < b.len && pairs[b.off + 2 * r] + pairs[b.off + 2 * r + 1] < v)
|
|
1996
|
+
r++;
|
|
1997
|
+
if (r === b.len || pairs[b.off + 2 * r] > v) return false;
|
|
1998
|
+
}
|
|
1999
|
+
return true;
|
|
2000
|
+
}
|
|
2001
|
+
function subsetRunsArray(a, b) {
|
|
2002
|
+
const pairs = lows16(a);
|
|
2003
|
+
const y = lows16(b);
|
|
2004
|
+
const je = b.off + b.len;
|
|
2005
|
+
let j = b.off;
|
|
2006
|
+
for (let r = 0; r < a.len; r++) {
|
|
2007
|
+
const start = pairs[a.off + 2 * r];
|
|
2008
|
+
const last = start + pairs[a.off + 2 * r + 1];
|
|
2009
|
+
j = gallop(y, 0, j, je, start);
|
|
2010
|
+
const end = j + (last - start);
|
|
2011
|
+
if (end >= je || y[j] !== start || y[end] !== last) return false;
|
|
2012
|
+
j = end + 1;
|
|
2013
|
+
}
|
|
2014
|
+
return true;
|
|
2015
|
+
}
|
|
2016
|
+
function subsetRuns(a, b) {
|
|
2017
|
+
const x = lows16(a);
|
|
2018
|
+
const y = lows16(b);
|
|
2019
|
+
let j = 0;
|
|
2020
|
+
for (let i = 0; i < a.len; i++) {
|
|
2021
|
+
const start = x[a.off + 2 * i];
|
|
2022
|
+
const last = start + x[a.off + 2 * i + 1];
|
|
2023
|
+
while (j < b.len && y[b.off + 2 * j] + y[b.off + 2 * j + 1] < start)
|
|
2024
|
+
j++;
|
|
2025
|
+
if (j === b.len || y[b.off + 2 * j] > start) return false;
|
|
2026
|
+
if (y[b.off + 2 * j] + y[b.off + 2 * j + 1] < last) return false;
|
|
2027
|
+
}
|
|
2028
|
+
return true;
|
|
2029
|
+
}
|
|
2030
|
+
function subsetBitsetRuns(a, b) {
|
|
2031
|
+
const words = words32(a);
|
|
2032
|
+
const pairs = lows16(b);
|
|
2033
|
+
let from = 0;
|
|
2034
|
+
for (let r = 0; r < b.len; r++) {
|
|
2035
|
+
const start = pairs[b.off + 2 * r];
|
|
2036
|
+
if (start > from && anyBitInRange(words, from, start - 1)) return false;
|
|
2037
|
+
from = start + pairs[b.off + 2 * r + 1] + 1;
|
|
2038
|
+
}
|
|
2039
|
+
return from > 65535 || !anyBitInRange(words, from, 65535);
|
|
2040
|
+
}
|
|
2041
|
+
function containersSubset(a, b) {
|
|
2042
|
+
if (a.card > b.card) return false;
|
|
2043
|
+
if (a.kind === ARRAY2) {
|
|
2044
|
+
if (b.kind === ARRAY2) return subsetArrays(a, b);
|
|
2045
|
+
if (b.kind === RUN2) return subsetArrayRuns(a, b);
|
|
2046
|
+
const u16 = lows16(a);
|
|
2047
|
+
const words2 = words32(b);
|
|
2048
|
+
for (let i = a.off; i < a.off + a.len; i++) {
|
|
2049
|
+
const v = u16[i];
|
|
2050
|
+
if ((words2[v >>> 5] >>> (v & 31) & 1) === 0) return false;
|
|
2051
|
+
}
|
|
2052
|
+
return true;
|
|
2053
|
+
}
|
|
2054
|
+
if (a.kind === BITSET) {
|
|
2055
|
+
if (b.kind === BITSET) {
|
|
2056
|
+
const x = words32(a);
|
|
2057
|
+
const y = words32(b);
|
|
2058
|
+
for (let i = 0; i < WORDS; i += 8) {
|
|
2059
|
+
const lack = x[i] & ~y[i] | x[i + 1] & ~y[i + 1] | x[i + 2] & ~y[i + 2] | x[i + 3] & ~y[i + 3] | x[i + 4] & ~y[i + 4] | x[i + 5] & ~y[i + 5] | x[i + 6] & ~y[i + 6] | x[i + 7] & ~y[i + 7];
|
|
2060
|
+
if (lack !== 0) return false;
|
|
2061
|
+
}
|
|
2062
|
+
return true;
|
|
2063
|
+
}
|
|
2064
|
+
if (b.kind === RUN2) return subsetBitsetRuns(a, b);
|
|
2065
|
+
return containerAndCard(a, b) === a.card;
|
|
2066
|
+
}
|
|
2067
|
+
if (b.kind === ARRAY2) return subsetRunsArray(a, b);
|
|
2068
|
+
if (b.kind === RUN2) return subsetRuns(a, b);
|
|
2069
|
+
const words = words32(b);
|
|
2070
|
+
const pairs = lows16(a);
|
|
2071
|
+
for (let r = 0; r < a.len; r++) {
|
|
2072
|
+
const start = pairs[a.off + 2 * r];
|
|
2073
|
+
if (!allBitsInRange(words, start, start + pairs[a.off + 2 * r + 1])) return false;
|
|
2074
|
+
}
|
|
2075
|
+
return true;
|
|
2076
|
+
}
|
|
2077
|
+
function containersEqual(a, b) {
|
|
2078
|
+
if (a.card !== b.card) return false;
|
|
2079
|
+
if (a.kind !== b.kind) return containerAndCard(a, b) === a.card;
|
|
2080
|
+
if (a.kind === BITSET) return equalWords(words32(a), 0, words32(b), 0, WORDS);
|
|
2081
|
+
if (a.len !== b.len) return false;
|
|
2082
|
+
const x = lows16(a);
|
|
2083
|
+
const y = lows16(b);
|
|
2084
|
+
const n = a.kind === ARRAY2 ? a.len : 2 * a.len;
|
|
2085
|
+
if (n < EQUAL_VIEW_MIN) {
|
|
2086
|
+
if (a.off === 0 && b.off === 0) return equalU16(x, 0, y, 0, n);
|
|
2087
|
+
return equalU16(x, a.off, y, b.off, n);
|
|
2088
|
+
}
|
|
2089
|
+
const xb = x.byteOffset + 2 * a.off;
|
|
2090
|
+
const yb = y.byteOffset + 2 * b.off;
|
|
2091
|
+
if (usesEqualView(n, xb, yb)) {
|
|
2092
|
+
const m = n >>> 1;
|
|
2093
|
+
if (!equalWords(new Uint32Array(x.buffer, xb, m), 0, new Uint32Array(y.buffer, yb, m), 0, m))
|
|
2094
|
+
return false;
|
|
2095
|
+
return (n & 1) === 0 || x[a.off + n - 1] === y[b.off + n - 1];
|
|
2096
|
+
}
|
|
2097
|
+
return equalU16(x, a.off, y, b.off, n);
|
|
2098
|
+
}
|
|
2099
|
+
var EQUAL_VIEW_MIN = 512;
|
|
2100
|
+
function usesEqualView(n, xb, yb) {
|
|
2101
|
+
return n >= EQUAL_VIEW_MIN && (xb & 3) === 0 && (yb & 3) === 0;
|
|
2102
|
+
}
|
|
2103
|
+
function equalWords(x, xo, y, yo, n) {
|
|
2104
|
+
let i = 0;
|
|
2105
|
+
for (const end = n - 7; i < end; i += 8) {
|
|
2106
|
+
const d = x[xo + i] ^ y[yo + i] | x[xo + i + 1] ^ y[yo + i + 1] | x[xo + i + 2] ^ y[yo + i + 2] | x[xo + i + 3] ^ y[yo + i + 3] | x[xo + i + 4] ^ y[yo + i + 4] | x[xo + i + 5] ^ y[yo + i + 5] | x[xo + i + 6] ^ y[yo + i + 6] | x[xo + i + 7] ^ y[yo + i + 7];
|
|
2107
|
+
if (d !== 0) return false;
|
|
2108
|
+
}
|
|
2109
|
+
for (; i < n; i++) if (x[xo + i] !== y[yo + i]) return false;
|
|
2110
|
+
return true;
|
|
2111
|
+
}
|
|
2112
|
+
function equalU16(x, xo, y, yo, n) {
|
|
2113
|
+
let i = 0;
|
|
2114
|
+
for (const end = n - 7; i < end; i += 8) {
|
|
2115
|
+
const d = x[xo + i] ^ y[yo + i] | x[xo + i + 1] ^ y[yo + i + 1] | x[xo + i + 2] ^ y[yo + i + 2] | x[xo + i + 3] ^ y[yo + i + 3] | x[xo + i + 4] ^ y[yo + i + 4] | x[xo + i + 5] ^ y[yo + i + 5] | x[xo + i + 6] ^ y[yo + i + 6] | x[xo + i + 7] ^ y[yo + i + 7];
|
|
2116
|
+
if (d !== 0) return false;
|
|
2117
|
+
}
|
|
2118
|
+
for (; i < n; i++) if (x[xo + i] !== y[yo + i]) return false;
|
|
2119
|
+
return true;
|
|
2120
|
+
}
|
|
2121
|
+
function intersectsArrays(a, b) {
|
|
2122
|
+
const small = a.len <= b.len ? a : b;
|
|
2123
|
+
const big = small === a ? b : a;
|
|
2124
|
+
const s = lows16(small);
|
|
2125
|
+
const l = lows16(big);
|
|
2126
|
+
const se = small.off + small.len;
|
|
2127
|
+
const le = big.off + big.len;
|
|
2128
|
+
if (s[se - 1] < l[big.off] || s[small.off] > l[le - 1]) {
|
|
2129
|
+
return false;
|
|
2130
|
+
}
|
|
2131
|
+
if (skewed(small.len, big.len)) {
|
|
2132
|
+
let at = big.off;
|
|
2133
|
+
for (let i2 = small.off; i2 < se; i2++) {
|
|
2134
|
+
const v = s[i2];
|
|
2135
|
+
at = gallop(l, 0, at, le, v);
|
|
2136
|
+
if (at === le) return false;
|
|
2137
|
+
if (l[at] === v) return true;
|
|
2138
|
+
}
|
|
2139
|
+
return false;
|
|
2140
|
+
}
|
|
2141
|
+
let i = small.off;
|
|
2142
|
+
let j = big.off;
|
|
2143
|
+
if (small.len >= PROBE_MIN) {
|
|
2144
|
+
for (let step = 0; step < MERGE_FIRST && i < se && j < le; step++) {
|
|
2145
|
+
const x = s[i];
|
|
2146
|
+
const y = l[j];
|
|
2147
|
+
if (x === y) return true;
|
|
2148
|
+
if (x < y) i++;
|
|
2149
|
+
else j++;
|
|
2150
|
+
}
|
|
2151
|
+
if (i === se || j === le) return false;
|
|
2152
|
+
const left = i;
|
|
2153
|
+
const from = gallop(l, 0, j, le, s[left]);
|
|
2154
|
+
const to = gallop(l, 0, from, le, s[se - 1] + 1);
|
|
2155
|
+
const words = probeWords;
|
|
2156
|
+
for (let k = left; k < se; k++) {
|
|
2157
|
+
const v = s[k];
|
|
2158
|
+
words[v >>> 5] = words[v >>> 5] | 1 << (v & 31);
|
|
2159
|
+
}
|
|
2160
|
+
let hit = false;
|
|
2161
|
+
for (let k = from; k < to; k++) {
|
|
2162
|
+
const v = l[k];
|
|
2163
|
+
if ((words[v >>> 5] >>> (v & 31) & 1) === 1) {
|
|
2164
|
+
hit = true;
|
|
2165
|
+
break;
|
|
2166
|
+
}
|
|
2167
|
+
}
|
|
2168
|
+
for (let k = left; k < se; k++) words[s[k] >>> 5] = 0;
|
|
2169
|
+
return hit;
|
|
2170
|
+
}
|
|
2171
|
+
while (i < se && j < le) {
|
|
2172
|
+
const x = s[i];
|
|
2173
|
+
const y = l[j];
|
|
2174
|
+
if (x === y) return true;
|
|
2175
|
+
if (x < y) i++;
|
|
2176
|
+
else j++;
|
|
2177
|
+
}
|
|
2178
|
+
return false;
|
|
1176
2179
|
}
|
|
1177
|
-
function
|
|
1178
|
-
const u16 = lows16(
|
|
1179
|
-
|
|
2180
|
+
function intersectsArrayRuns(a, b) {
|
|
2181
|
+
const u16 = lows16(a);
|
|
2182
|
+
const pairs = lows16(b);
|
|
2183
|
+
let r = 0;
|
|
2184
|
+
for (let i = a.off; i < a.off + a.len; i++) {
|
|
1180
2185
|
const v = u16[i];
|
|
1181
|
-
|
|
2186
|
+
while (r < b.len && pairs[b.off + 2 * r] + pairs[b.off + 2 * r + 1] < v) {
|
|
2187
|
+
r++;
|
|
2188
|
+
}
|
|
2189
|
+
if (r === b.len) return false;
|
|
2190
|
+
if (pairs[b.off + 2 * r] <= v) return true;
|
|
1182
2191
|
}
|
|
1183
|
-
return
|
|
2192
|
+
return false;
|
|
1184
2193
|
}
|
|
1185
|
-
function
|
|
2194
|
+
function containersIntersect(a, b) {
|
|
2195
|
+
if (a.kind > b.kind) return containersIntersect(b, a);
|
|
1186
2196
|
if (a.kind === ARRAY2) {
|
|
1187
|
-
if (b.kind === ARRAY2) return
|
|
1188
|
-
|
|
2197
|
+
if (b.kind === ARRAY2) return intersectsArrays(a, b);
|
|
2198
|
+
if (b.kind === RUN2) return intersectsArrayRuns(a, b);
|
|
2199
|
+
const u16 = lows16(a);
|
|
2200
|
+
const words = words32(b);
|
|
2201
|
+
for (let i2 = a.off; i2 < a.off + a.len; i2++) {
|
|
2202
|
+
const v = u16[i2];
|
|
2203
|
+
if ((words[v >>> 5] >>> (v & 31) & 1) === 1) return true;
|
|
2204
|
+
}
|
|
2205
|
+
return false;
|
|
1189
2206
|
}
|
|
1190
|
-
if (a.kind ===
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
2207
|
+
if (a.kind === BITSET) {
|
|
2208
|
+
const x2 = words32(a);
|
|
2209
|
+
if (b.kind === BITSET) {
|
|
2210
|
+
const y2 = words32(b);
|
|
2211
|
+
for (let i2 = 0; i2 < WORDS; i2 += 8) {
|
|
2212
|
+
const both = x2[i2] & y2[i2] | x2[i2 + 1] & y2[i2 + 1] | x2[i2 + 2] & y2[i2 + 2] | x2[i2 + 3] & y2[i2 + 3] | x2[i2 + 4] & y2[i2 + 4] | x2[i2 + 5] & y2[i2 + 5] | x2[i2 + 6] & y2[i2 + 6] | x2[i2 + 7] & y2[i2 + 7];
|
|
2213
|
+
if (both !== 0) return true;
|
|
2214
|
+
}
|
|
2215
|
+
return false;
|
|
1197
2216
|
}
|
|
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
2217
|
const pairs = lows16(b);
|
|
1203
2218
|
for (let r = 0; r < b.len; r++) {
|
|
1204
2219
|
const start = pairs[b.off + 2 * r];
|
|
1205
|
-
|
|
2220
|
+
if (anyBitInRange(x2, start, start + pairs[b.off + 2 * r + 1])) return true;
|
|
1206
2221
|
}
|
|
2222
|
+
return false;
|
|
1207
2223
|
}
|
|
1208
|
-
|
|
2224
|
+
const x = lows16(a);
|
|
2225
|
+
const y = lows16(b);
|
|
2226
|
+
let i = 0;
|
|
2227
|
+
let j = 0;
|
|
2228
|
+
while (i < a.len && j < b.len) {
|
|
2229
|
+
const as = x[a.off + 2 * i];
|
|
2230
|
+
const ae = as + x[a.off + 2 * i + 1];
|
|
2231
|
+
const bs = y[b.off + 2 * j];
|
|
2232
|
+
const be = bs + y[b.off + 2 * j + 1];
|
|
2233
|
+
if ((as > bs ? as : bs) <= (ae < be ? ae : be)) return true;
|
|
2234
|
+
if (ae < be) i++;
|
|
2235
|
+
else j++;
|
|
2236
|
+
}
|
|
2237
|
+
return false;
|
|
1209
2238
|
}
|
|
1210
2239
|
|
|
1211
2240
|
// src/ts-roaring/iterator.ts
|
|
@@ -1302,7 +2331,16 @@ function bodySize(c) {
|
|
|
1302
2331
|
if (c.kind === BITSET) return BITSET_BYTES;
|
|
1303
2332
|
return 2 + 4 * c.len;
|
|
1304
2333
|
}
|
|
2334
|
+
var SMALL_BODY = 64;
|
|
1305
2335
|
function putU16s(out, at, src, from, count) {
|
|
2336
|
+
if (count < SMALL_BODY) {
|
|
2337
|
+
for (let i = 0; i < count; i++) {
|
|
2338
|
+
const v = src[from + i];
|
|
2339
|
+
out[at++] = v & 255;
|
|
2340
|
+
out[at++] = v >>> 8;
|
|
2341
|
+
}
|
|
2342
|
+
return;
|
|
2343
|
+
}
|
|
1306
2344
|
if (LITTLE_ENDIAN) {
|
|
1307
2345
|
out.set(new Uint8Array(src.buffer, src.byteOffset + 2 * from, 2 * count), at);
|
|
1308
2346
|
return;
|
|
@@ -1357,7 +2395,7 @@ function serializeContainers(keys, conts) {
|
|
|
1357
2395
|
}
|
|
1358
2396
|
return out;
|
|
1359
2397
|
}
|
|
1360
|
-
function decodeContainers(input) {
|
|
2398
|
+
function decodeContainers(input, detached = false) {
|
|
1361
2399
|
const bytes = Uint8Array.prototype.slice.call(input);
|
|
1362
2400
|
const layout = parsePortableLayout(bytes);
|
|
1363
2401
|
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
@@ -1367,18 +2405,21 @@ function decodeContainers(input) {
|
|
|
1367
2405
|
let end = bytes.byteLength === 0 ? 0 : 8;
|
|
1368
2406
|
let slabLength = 0;
|
|
1369
2407
|
let small = 0;
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
2408
|
+
if (!detached) {
|
|
2409
|
+
for (const { cardinality, kind, offset } of layout) {
|
|
2410
|
+
if (kind === ARRAY) {
|
|
2411
|
+
slabLength += cardinality;
|
|
2412
|
+
small++;
|
|
2413
|
+
} else if (kind !== BITMAP) {
|
|
2414
|
+
slabLength += 2 * view.getUint16(offset, true);
|
|
2415
|
+
small++;
|
|
2416
|
+
}
|
|
1377
2417
|
}
|
|
1378
2418
|
}
|
|
1379
2419
|
const own = LITTLE_ENDIAN && bytes.byteOffset === 0 && bytes.buffer instanceof ArrayBuffer && bytes.buffer.byteLength === bytes.byteLength;
|
|
1380
|
-
const alias = own && small === 1;
|
|
1381
|
-
const
|
|
2420
|
+
const alias = !detached && own && small === 1;
|
|
2421
|
+
const solo = alias || detached;
|
|
2422
|
+
const slab = solo ? NO_U16 : new Uint16Array(slabLength);
|
|
1382
2423
|
let used = 0;
|
|
1383
2424
|
for (const { key, cardinality, kind, offset } of layout) {
|
|
1384
2425
|
keys[n] = key;
|
|
@@ -1387,22 +2428,22 @@ function decodeContainers(input) {
|
|
|
1387
2428
|
const values = new Uint16Array(bytes.buffer, offset, cardinality);
|
|
1388
2429
|
conts[n++] = new Container(ARRAY2, values, 0, cardinality, cardinality, false);
|
|
1389
2430
|
} else {
|
|
1390
|
-
const into =
|
|
1391
|
-
getU16s(bytes, view, offset, into,
|
|
2431
|
+
const into = solo ? new Uint16Array(cardinality) : slab;
|
|
2432
|
+
getU16s(bytes, view, offset, into, solo ? 0 : used, cardinality);
|
|
1392
2433
|
conts[n++] = new Container(
|
|
1393
2434
|
ARRAY2,
|
|
1394
2435
|
into,
|
|
1395
|
-
|
|
2436
|
+
solo ? 0 : used,
|
|
1396
2437
|
cardinality,
|
|
1397
2438
|
cardinality,
|
|
1398
|
-
small > 1
|
|
2439
|
+
!solo && small > 1
|
|
1399
2440
|
);
|
|
1400
2441
|
used += cardinality;
|
|
1401
2442
|
}
|
|
1402
2443
|
end = offset + 2 * cardinality;
|
|
1403
2444
|
} else if (kind === BITMAP) {
|
|
1404
2445
|
let words;
|
|
1405
|
-
if (own && offset % 4 === 0) {
|
|
2446
|
+
if (!detached && own && offset % 4 === 0) {
|
|
1406
2447
|
words = new Uint32Array(bytes.buffer, offset, WORDS);
|
|
1407
2448
|
} else {
|
|
1408
2449
|
words = new Uint32Array(WORDS);
|
|
@@ -1420,9 +2461,16 @@ function decodeContainers(input) {
|
|
|
1420
2461
|
const pairs = new Uint16Array(bytes.buffer, offset + 2, 2 * runs);
|
|
1421
2462
|
conts[n++] = new Container(RUN2, pairs, 0, runs, cardinality, false);
|
|
1422
2463
|
} else {
|
|
1423
|
-
const into =
|
|
1424
|
-
getU16s(bytes, view, offset + 2, into,
|
|
1425
|
-
conts[n++] = new Container(
|
|
2464
|
+
const into = solo ? new Uint16Array(2 * runs) : slab;
|
|
2465
|
+
getU16s(bytes, view, offset + 2, into, solo ? 0 : used, 2 * runs);
|
|
2466
|
+
conts[n++] = new Container(
|
|
2467
|
+
RUN2,
|
|
2468
|
+
into,
|
|
2469
|
+
solo ? 0 : used,
|
|
2470
|
+
runs,
|
|
2471
|
+
cardinality,
|
|
2472
|
+
!solo && small > 1
|
|
2473
|
+
);
|
|
1426
2474
|
used += 2 * runs;
|
|
1427
2475
|
}
|
|
1428
2476
|
end = offset + 2 + 4 * runs;
|
|
@@ -1449,11 +2497,8 @@ var MAX_ID = 4294967295;
|
|
|
1449
2497
|
function isId(value) {
|
|
1450
2498
|
return Number.isInteger(value) && value >= 0 && value <= MAX_ID;
|
|
1451
2499
|
}
|
|
1452
|
-
function badId(value) {
|
|
1453
|
-
return new ValidationError2(`${String(value)} is not an integer from 0 to ${MAX_ID}`);
|
|
1454
|
-
}
|
|
1455
2500
|
function checkedId(value) {
|
|
1456
|
-
if (!isId(value)) throw
|
|
2501
|
+
if (!isId(value)) throw refusalOfId(value);
|
|
1457
2502
|
return value;
|
|
1458
2503
|
}
|
|
1459
2504
|
function collect(values) {
|
|
@@ -1461,10 +2506,17 @@ function collect(values) {
|
|
|
1461
2506
|
if (Array.isArray(values)) {
|
|
1462
2507
|
const list = values;
|
|
1463
2508
|
const out2 = new Uint32Array(list.length);
|
|
1464
|
-
|
|
2509
|
+
let i = 0;
|
|
2510
|
+
try {
|
|
2511
|
+
for (; i < list.length; i++) {
|
|
2512
|
+
const v = list[i];
|
|
2513
|
+
if (v >>> 0 !== v) throw refusalOfId(v);
|
|
2514
|
+
out2[i] = v;
|
|
2515
|
+
}
|
|
2516
|
+
} catch (error) {
|
|
1465
2517
|
const v = list[i];
|
|
1466
|
-
if (v
|
|
1467
|
-
|
|
2518
|
+
if (typeof v !== "number") throw refusalOfId(v);
|
|
2519
|
+
throw error;
|
|
1468
2520
|
}
|
|
1469
2521
|
return out2;
|
|
1470
2522
|
}
|
|
@@ -1481,6 +2533,7 @@ function collect(values) {
|
|
|
1481
2533
|
return out.subarray(0, n);
|
|
1482
2534
|
}
|
|
1483
2535
|
function collectLenient(values) {
|
|
2536
|
+
if (values instanceof Uint32Array) return values.slice();
|
|
1484
2537
|
const list = Array.isArray(values) ? values : Array.from(values);
|
|
1485
2538
|
const out = new Uint32Array(list.length);
|
|
1486
2539
|
let n = 0;
|
|
@@ -1490,6 +2543,11 @@ function collectLenient(values) {
|
|
|
1490
2543
|
}
|
|
1491
2544
|
return out.subarray(0, n);
|
|
1492
2545
|
}
|
|
2546
|
+
var FEW_IDS = 4;
|
|
2547
|
+
function groupPath(before, count) {
|
|
2548
|
+
if (count <= FEW_IDS) return "few";
|
|
2549
|
+
return walksRunIds(before, count) ? "walk" : "merge";
|
|
2550
|
+
}
|
|
1493
2551
|
function sortedIds(ids, owned) {
|
|
1494
2552
|
for (let i = 1; i < ids.length; i++) {
|
|
1495
2553
|
if (ids[i - 1] > ids[i]) return (owned ? ids : ids.slice()).sort();
|
|
@@ -1530,9 +2588,11 @@ function lowerBoundIn(keys, key, from, to) {
|
|
|
1530
2588
|
var OR = 0;
|
|
1531
2589
|
var AND = 1;
|
|
1532
2590
|
var AND_NOT = 2;
|
|
2591
|
+
var XOR = 3;
|
|
1533
2592
|
function combineContainers(op, a, b) {
|
|
1534
|
-
if (op === OR) return containerOr(a, b, !a.shared);
|
|
2593
|
+
if (op === OR) return containerOr(a, b, !a.shared || a.kind === RUN2);
|
|
1535
2594
|
if (op === AND) return containerAnd(a, b, !a.shared);
|
|
2595
|
+
if (op === XOR) return containerXor(a, b, !a.shared);
|
|
1536
2596
|
return containerAndNot(a, b, !a.shared);
|
|
1537
2597
|
}
|
|
1538
2598
|
var TsBitmap = class _TsBitmap {
|
|
@@ -1554,7 +2614,9 @@ var TsBitmap = class _TsBitmap {
|
|
|
1554
2614
|
}
|
|
1555
2615
|
/**
|
|
1556
2616
|
* 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.
|
|
2617
|
+
* refused too; without it they are ignored. With `detached`, every container gets storage of its own, copied out of
|
|
2618
|
+
* the input, so nothing the result holds is a view of one shared buffer: a bitmap that is kept and then reduced
|
|
2619
|
+
* does not keep the whole input alive.
|
|
1558
2620
|
*
|
|
1559
2621
|
* @throws {IntegrityError} if the input exceeds `maxBytes`, is not a well-formed portable bitmap, or (with `whole`)
|
|
1560
2622
|
* has bytes after it.
|
|
@@ -1563,7 +2625,7 @@ var TsBitmap = class _TsBitmap {
|
|
|
1563
2625
|
if (bytes.length > maxBytes) {
|
|
1564
2626
|
throw new IntegrityError3(`serialized bitmap is ${bytes.length}B, exceeds cap ${maxBytes}B`);
|
|
1565
2627
|
}
|
|
1566
|
-
const { keys, conts, end } = decodeContainers(bytes);
|
|
2628
|
+
const { keys, conts, end } = decodeContainers(bytes, options.detached === true);
|
|
1567
2629
|
if (options.whole === true && end !== bytes.byteLength) {
|
|
1568
2630
|
throw trailingBytes(bytes.byteLength, end);
|
|
1569
2631
|
}
|
|
@@ -1579,6 +2641,12 @@ var TsBitmap = class _TsBitmap {
|
|
|
1579
2641
|
const conts = this.#conts;
|
|
1580
2642
|
for (let i = 0; i < conts.length; i++) conts[i] = optimize(conts[i]);
|
|
1581
2643
|
}
|
|
2644
|
+
/** Whether at least one container is held as runs. */
|
|
2645
|
+
hasRunContainer() {
|
|
2646
|
+
for (let i = 0; i < this.#conts.length; i++)
|
|
2647
|
+
if (this.#conts[i].kind === RUN2) return true;
|
|
2648
|
+
return false;
|
|
2649
|
+
}
|
|
1582
2650
|
/**
|
|
1583
2651
|
* The set as storage chunks: each payload is the portable bytes of a one-container bitmap holding that chunk's low 16
|
|
1584
2652
|
* bits, optimized the way {@link optimize} does. Nothing is built until a chunk is asked for, so a writer that yields
|
|
@@ -1603,6 +2671,11 @@ var TsBitmap = class _TsBitmap {
|
|
|
1603
2671
|
}
|
|
1604
2672
|
};
|
|
1605
2673
|
}
|
|
2674
|
+
/** The smallest id, or `undefined` when the bitmap is empty. */
|
|
2675
|
+
minimum() {
|
|
2676
|
+
if (this.#conts.length === 0) return void 0;
|
|
2677
|
+
return this.#keys[0] * 65536 + containerMin(this.#conts[0]);
|
|
2678
|
+
}
|
|
1606
2679
|
maximum() {
|
|
1607
2680
|
const last = this.#conts.length - 1;
|
|
1608
2681
|
if (last < 0) return void 0;
|
|
@@ -1636,36 +2709,50 @@ var TsBitmap = class _TsBitmap {
|
|
|
1636
2709
|
const key = ids[i] >>> 16;
|
|
1637
2710
|
let end = i + 1;
|
|
1638
2711
|
while (end < ids.length && ids[end] >>> 16 === key) end++;
|
|
1639
|
-
const
|
|
2712
|
+
const first = i;
|
|
1640
2713
|
i = end;
|
|
1641
2714
|
at = gallopKeys(this.#keys, key, at);
|
|
1642
2715
|
if (this.#keys[at] === key) {
|
|
1643
2716
|
const before = this.#conts[at];
|
|
1644
|
-
const
|
|
2717
|
+
const path = groupPath(before, end - first);
|
|
2718
|
+
const after = path === "few" ? containerAddSorted(before, ids, first, end) : path === "walk" ? orRunIdsWalk(before, ids, first, end) : containerOr(
|
|
2719
|
+
before,
|
|
2720
|
+
fromSortedIds(ids, first, end),
|
|
2721
|
+
!before.shared || before.kind === RUN2
|
|
2722
|
+
);
|
|
1645
2723
|
this.#conts[at] = after;
|
|
1646
2724
|
this.#size += after.card - before.card;
|
|
1647
2725
|
} else {
|
|
2726
|
+
const group = fromSortedIds(ids, first, end);
|
|
1648
2727
|
fresh.push({ key, group });
|
|
1649
2728
|
this.#size += group.card;
|
|
1650
2729
|
}
|
|
1651
2730
|
}
|
|
1652
2731
|
if (fresh.length > 0) this.#insertAll(fresh);
|
|
1653
2732
|
}
|
|
2733
|
+
/** Remove the id (anything that is not an id is ignored); whether it was there. */
|
|
1654
2734
|
remove(value) {
|
|
1655
|
-
if (!isId(value)) return;
|
|
2735
|
+
if (!isId(value)) return false;
|
|
1656
2736
|
const key = value >>> 16;
|
|
1657
2737
|
const at = lowerBound2(this.#keys, key);
|
|
1658
|
-
if (this.#keys[at] !== key) return;
|
|
2738
|
+
if (this.#keys[at] !== key) return false;
|
|
1659
2739
|
const before = this.#conts[at];
|
|
1660
2740
|
const after = containerRemove(before, value & 65535);
|
|
1661
2741
|
if (after === null) {
|
|
1662
2742
|
this.#keys.splice(at, 1);
|
|
1663
2743
|
this.#conts.splice(at, 1);
|
|
1664
2744
|
this.#size -= before.card;
|
|
1665
|
-
return;
|
|
2745
|
+
return true;
|
|
1666
2746
|
}
|
|
1667
2747
|
this.#conts[at] = after;
|
|
1668
2748
|
this.#size += after.card - before.card;
|
|
2749
|
+
return after.card !== before.card;
|
|
2750
|
+
}
|
|
2751
|
+
/** Remove every id. Containers a clone shares are left to it. */
|
|
2752
|
+
clear() {
|
|
2753
|
+
this.#keys = [];
|
|
2754
|
+
this.#conts = [];
|
|
2755
|
+
this.#size = 0;
|
|
1669
2756
|
}
|
|
1670
2757
|
/** Remove the ids (anything that is not an id is ignored), grouped by key; the keys left empty go in one pass. */
|
|
1671
2758
|
removeMany(values) {
|
|
@@ -1725,6 +2812,90 @@ var TsBitmap = class _TsBitmap {
|
|
|
1725
2812
|
andNotInPlace(other) {
|
|
1726
2813
|
this.#combine(_TsBitmap.#of(other), AND_NOT);
|
|
1727
2814
|
}
|
|
2815
|
+
/** Flip the ids `other` holds, in one pass over the pair of each key. */
|
|
2816
|
+
xorInPlace(other) {
|
|
2817
|
+
this.#combine(_TsBitmap.#of(other), XOR);
|
|
2818
|
+
}
|
|
2819
|
+
/** How many ids both bitmaps hold, counted without building the intersection. */
|
|
2820
|
+
andCardinality(other) {
|
|
2821
|
+
const that = _TsBitmap.#of(other);
|
|
2822
|
+
const a = this.#keys;
|
|
2823
|
+
const b = that.#keys;
|
|
2824
|
+
let n = 0;
|
|
2825
|
+
let i = 0;
|
|
2826
|
+
let j = 0;
|
|
2827
|
+
while (i < a.length && j < b.length) {
|
|
2828
|
+
const ka = a[i];
|
|
2829
|
+
const kb = b[j];
|
|
2830
|
+
if (ka === kb) {
|
|
2831
|
+
n += containerAndCard(this.#conts[i++], that.#conts[j++]);
|
|
2832
|
+
} else if (ka < kb) {
|
|
2833
|
+
i = gallopKeys(a, kb, i + 1);
|
|
2834
|
+
} else {
|
|
2835
|
+
j = gallopKeys(b, ka, j + 1);
|
|
2836
|
+
}
|
|
2837
|
+
}
|
|
2838
|
+
return n;
|
|
2839
|
+
}
|
|
2840
|
+
/** How many ids either bitmap holds. */
|
|
2841
|
+
orCardinality(other) {
|
|
2842
|
+
return this.#size + _TsBitmap.#of(other).#size - this.andCardinality(other);
|
|
2843
|
+
}
|
|
2844
|
+
/** How many ids exactly one of the bitmaps holds. */
|
|
2845
|
+
xorCardinality(other) {
|
|
2846
|
+
return this.#size + _TsBitmap.#of(other).#size - 2 * this.andCardinality(other);
|
|
2847
|
+
}
|
|
2848
|
+
/** How many ids this bitmap holds that `other` lacks. */
|
|
2849
|
+
andNotCardinality(other) {
|
|
2850
|
+
return this.#size - this.andCardinality(other);
|
|
2851
|
+
}
|
|
2852
|
+
/** Whether the bitmaps share an id; stops at the first one found. */
|
|
2853
|
+
intersects(other) {
|
|
2854
|
+
const that = _TsBitmap.#of(other);
|
|
2855
|
+
const a = this.#keys;
|
|
2856
|
+
const b = that.#keys;
|
|
2857
|
+
let i = 0;
|
|
2858
|
+
let j = 0;
|
|
2859
|
+
while (i < a.length && j < b.length) {
|
|
2860
|
+
const ka = a[i];
|
|
2861
|
+
const kb = b[j];
|
|
2862
|
+
if (ka === kb) {
|
|
2863
|
+
if (containersIntersect(this.#conts[i++], that.#conts[j++])) {
|
|
2864
|
+
return true;
|
|
2865
|
+
}
|
|
2866
|
+
} else if (ka < kb) {
|
|
2867
|
+
i = gallopKeys(a, kb, i + 1);
|
|
2868
|
+
} else {
|
|
2869
|
+
j = gallopKeys(b, ka, j + 1);
|
|
2870
|
+
}
|
|
2871
|
+
}
|
|
2872
|
+
return false;
|
|
2873
|
+
}
|
|
2874
|
+
/** Whether every id of this bitmap is in `other`; stops at the first container that is not inside its partner. */
|
|
2875
|
+
isSubset(other) {
|
|
2876
|
+
const that = _TsBitmap.#of(other);
|
|
2877
|
+
if (this.#size > that.#size) return false;
|
|
2878
|
+
const a = this.#keys;
|
|
2879
|
+
const b = that.#keys;
|
|
2880
|
+
let j = 0;
|
|
2881
|
+
for (let i = 0; i < a.length; i++) {
|
|
2882
|
+
j = gallopKeys(b, a[i], j);
|
|
2883
|
+
if (j === b.length || b[j] !== a[i]) return false;
|
|
2884
|
+
const c = this.#conts[i];
|
|
2885
|
+
if (!containersSubset(c, that.#conts[j++])) return false;
|
|
2886
|
+
}
|
|
2887
|
+
return true;
|
|
2888
|
+
}
|
|
2889
|
+
/** Whether both hold the same ids, whatever the kinds of their containers. */
|
|
2890
|
+
isEqual(other) {
|
|
2891
|
+
const that = _TsBitmap.#of(other);
|
|
2892
|
+
if (this.#size !== that.#size || this.#keys.length !== that.#keys.length) return false;
|
|
2893
|
+
for (let i = 0; i < this.#keys.length; i++) {
|
|
2894
|
+
if (this.#keys[i] !== that.#keys[i]) return false;
|
|
2895
|
+
if (!containersEqual(this.#conts[i], that.#conts[i])) return false;
|
|
2896
|
+
}
|
|
2897
|
+
return true;
|
|
2898
|
+
}
|
|
1728
2899
|
[Symbol.iterator]() {
|
|
1729
2900
|
return new BitmapIterator(this.#keys, this.#conts);
|
|
1730
2901
|
}
|
|
@@ -1831,7 +3002,7 @@ var TsBitmap = class _TsBitmap {
|
|
|
1831
3002
|
} else if (op === AND) {
|
|
1832
3003
|
j = gallopKeys(b, ka, j + 1);
|
|
1833
3004
|
} else {
|
|
1834
|
-
if (op === OR) {
|
|
3005
|
+
if (op === OR || op === XOR) {
|
|
1835
3006
|
keys.push(kb);
|
|
1836
3007
|
conts.push(cloneContainer(cb[j]));
|
|
1837
3008
|
size += cb[j].card;
|
|
@@ -1846,7 +3017,7 @@ var TsBitmap = class _TsBitmap {
|
|
|
1846
3017
|
size += ca[i].card;
|
|
1847
3018
|
}
|
|
1848
3019
|
}
|
|
1849
|
-
if (op === OR) {
|
|
3020
|
+
if (op === OR || op === XOR) {
|
|
1850
3021
|
for (; j < b.length; j++) {
|
|
1851
3022
|
keys.push(b[j]);
|
|
1852
3023
|
conts.push(cloneContainer(cb[j]));
|
|
@@ -1857,7 +3028,122 @@ var TsBitmap = class _TsBitmap {
|
|
|
1857
3028
|
this.#conts = conts;
|
|
1858
3029
|
this.#size = size;
|
|
1859
3030
|
}
|
|
3031
|
+
/** The ids both bitmaps hold, as a new bitmap; neither operand changes and no container of either is kept. */
|
|
3032
|
+
static and(a, b) {
|
|
3033
|
+
return _TsBitmap.#fresh(_TsBitmap.#of(a), _TsBitmap.#of(b), AND);
|
|
3034
|
+
}
|
|
3035
|
+
/** The ids either holds, as a new bitmap; neither operand changes. */
|
|
3036
|
+
static or(a, b) {
|
|
3037
|
+
return _TsBitmap.#fresh(_TsBitmap.#of(a), _TsBitmap.#of(b), OR);
|
|
3038
|
+
}
|
|
3039
|
+
/**
|
|
3040
|
+
* The ids any of `bitmaps` holds, as a new bitmap that owns all its storage; no operand changes and none is flagged.
|
|
3041
|
+
* The containers of each key are gathered across the inputs and united in one pass (see {@link orManyContainers}),
|
|
3042
|
+
* counted once. A key only one input holds is copied as it is, a run included.
|
|
3043
|
+
*/
|
|
3044
|
+
static orMany(bitmaps) {
|
|
3045
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
3046
|
+
for (const input of bitmaps) {
|
|
3047
|
+
const that = _TsBitmap.#of(input);
|
|
3048
|
+
for (let i = 0; i < that.#keys.length; i++) {
|
|
3049
|
+
const key = that.#keys[i];
|
|
3050
|
+
const held = byKey.get(key);
|
|
3051
|
+
if (held === void 0) byKey.set(key, [that.#conts[i]]);
|
|
3052
|
+
else held.push(that.#conts[i]);
|
|
3053
|
+
}
|
|
3054
|
+
}
|
|
3055
|
+
const keys = Array.from(byKey.keys()).sort((x, y) => x - y);
|
|
3056
|
+
const conts = [];
|
|
3057
|
+
let size = 0;
|
|
3058
|
+
for (const key of keys) {
|
|
3059
|
+
const held = byKey.get(key);
|
|
3060
|
+
const c = held.length === 1 ? cloneContainer(held[0]) : orManyContainers(held);
|
|
3061
|
+
conts.push(c);
|
|
3062
|
+
size += c.card;
|
|
3063
|
+
}
|
|
3064
|
+
return new _TsBitmap(keys, conts, size);
|
|
3065
|
+
}
|
|
3066
|
+
/** The ids exactly one holds, as a new bitmap; neither operand changes. */
|
|
3067
|
+
static xor(a, b) {
|
|
3068
|
+
return _TsBitmap.#fresh(_TsBitmap.#of(a), _TsBitmap.#of(b), XOR);
|
|
3069
|
+
}
|
|
3070
|
+
/** The ids of `a` that `b` lacks, as a new bitmap; neither operand changes. */
|
|
3071
|
+
static andNot(a, b) {
|
|
3072
|
+
return _TsBitmap.#fresh(_TsBitmap.#of(a), _TsBitmap.#of(b), AND_NOT);
|
|
3073
|
+
}
|
|
3074
|
+
/**
|
|
3075
|
+
* The same walk as {@link TsBitmap.#combine}, building a new bitmap and leaving both operands whole. Where both hold
|
|
3076
|
+
* a key, the pair combines into a fresh container (the in-place form is never taken, so no storage of either operand
|
|
3077
|
+
* is written). A container only `x` holds is kept by reference and flagged shared, so a later write to `x` or to the
|
|
3078
|
+
* result copies it once; for an intersection nothing of `x` is kept, so nothing is flagged. A container only `y`
|
|
3079
|
+
* holds is copied in for a union or a symmetric difference.
|
|
3080
|
+
*/
|
|
3081
|
+
static #fresh(x, y, op) {
|
|
3082
|
+
const a = x.#keys;
|
|
3083
|
+
const b = y.#keys;
|
|
3084
|
+
const ca = x.#conts;
|
|
3085
|
+
const cb = y.#conts;
|
|
3086
|
+
const keys = [];
|
|
3087
|
+
const conts = [];
|
|
3088
|
+
let size = 0;
|
|
3089
|
+
let i = 0;
|
|
3090
|
+
let j = 0;
|
|
3091
|
+
while (i < a.length && j < b.length) {
|
|
3092
|
+
const ka = a[i];
|
|
3093
|
+
const kb = b[j];
|
|
3094
|
+
if (ka === kb) {
|
|
3095
|
+
const c = freshPair(op, ca[i++], cb[j++]);
|
|
3096
|
+
if (c !== null) {
|
|
3097
|
+
keys.push(ka);
|
|
3098
|
+
conts.push(c);
|
|
3099
|
+
size += c.card;
|
|
3100
|
+
}
|
|
3101
|
+
} else if (ka < kb) {
|
|
3102
|
+
if (op === AND) {
|
|
3103
|
+
i = gallopKeys(a, kb, i + 1);
|
|
3104
|
+
} else {
|
|
3105
|
+
const c = ca[i++];
|
|
3106
|
+
c.shared = true;
|
|
3107
|
+
keys.push(ka);
|
|
3108
|
+
conts.push(c);
|
|
3109
|
+
size += c.card;
|
|
3110
|
+
}
|
|
3111
|
+
} else if (op === AND) {
|
|
3112
|
+
j = gallopKeys(b, ka, j + 1);
|
|
3113
|
+
} else {
|
|
3114
|
+
if (op === OR || op === XOR) {
|
|
3115
|
+
keys.push(kb);
|
|
3116
|
+
conts.push(cloneContainer(cb[j]));
|
|
3117
|
+
size += cb[j].card;
|
|
3118
|
+
}
|
|
3119
|
+
j++;
|
|
3120
|
+
}
|
|
3121
|
+
}
|
|
3122
|
+
if (op !== AND) {
|
|
3123
|
+
for (; i < a.length; i++) {
|
|
3124
|
+
const c = ca[i];
|
|
3125
|
+
c.shared = true;
|
|
3126
|
+
keys.push(a[i]);
|
|
3127
|
+
conts.push(c);
|
|
3128
|
+
size += c.card;
|
|
3129
|
+
}
|
|
3130
|
+
}
|
|
3131
|
+
if (op === OR || op === XOR) {
|
|
3132
|
+
for (; j < b.length; j++) {
|
|
3133
|
+
keys.push(b[j]);
|
|
3134
|
+
conts.push(cloneContainer(cb[j]));
|
|
3135
|
+
size += cb[j].card;
|
|
3136
|
+
}
|
|
3137
|
+
}
|
|
3138
|
+
return new _TsBitmap(keys, conts, size);
|
|
3139
|
+
}
|
|
1860
3140
|
};
|
|
3141
|
+
function freshPair(op, a, b) {
|
|
3142
|
+
if (op === OR) return containerOr(a, b, false);
|
|
3143
|
+
if (op === AND) return containerAnd(a, b, false);
|
|
3144
|
+
if (op === AND_NOT) return containerAndNot(a, b, false);
|
|
3145
|
+
return containerXor(a, b, false);
|
|
3146
|
+
}
|
|
1861
3147
|
var EMPTIED = arrayContainer(new Uint16Array(0), 0);
|
|
1862
3148
|
var tsRoaringCodec = {
|
|
1863
3149
|
empty: () => TsBitmap.empty(),
|
|
@@ -2017,7 +3303,7 @@ import {
|
|
|
2017
3303
|
DEFAULT_RETRY_POLICY,
|
|
2018
3304
|
NOOP_METRICS,
|
|
2019
3305
|
RetryingStorageChunkSource,
|
|
2020
|
-
ValidationError as
|
|
3306
|
+
ValidationError as ValidationError3,
|
|
2021
3307
|
isStorageBackend
|
|
2022
3308
|
} from "@cloudbitmaps/core";
|
|
2023
3309
|
function resolveRetryPolicy(partial) {
|
|
@@ -2041,7 +3327,7 @@ function wireStore(options, clock, rng, metrics) {
|
|
|
2041
3327
|
if (options.retry !== false) {
|
|
2042
3328
|
const { onRetry: userOnRetry, ...ov } = options.retry ?? {};
|
|
2043
3329
|
if (userOnRetry !== void 0 && typeof userOnRetry !== "function") {
|
|
2044
|
-
throw new
|
|
3330
|
+
throw new ValidationError3("retry.onRetry must be a function");
|
|
2045
3331
|
}
|
|
2046
3332
|
retryOptions = {
|
|
2047
3333
|
clock,
|
|
@@ -2072,7 +3358,7 @@ function wireStore(options, clock, rng, metrics) {
|
|
|
2072
3358
|
function resolveStorageSource(options, clock) {
|
|
2073
3359
|
const storage = options.storage;
|
|
2074
3360
|
if (storage === null || typeof storage !== "object") {
|
|
2075
|
-
throw new
|
|
3361
|
+
throw new ValidationError3(
|
|
2076
3362
|
"`storage` must be a StorageBackend, an IStorageDriver, or a StorageChunkSource"
|
|
2077
3363
|
);
|
|
2078
3364
|
}
|
|
@@ -2082,14 +3368,14 @@ function resolveStorageSource(options, clock) {
|
|
|
2082
3368
|
const hasPutImmutable = typeof storage.putImmutable === "function";
|
|
2083
3369
|
const isBackend = isStorageBackend(storage);
|
|
2084
3370
|
if (isBackend && (hasGetChunk || hasPutImmutable)) {
|
|
2085
|
-
throw new
|
|
3371
|
+
throw new ValidationError3(
|
|
2086
3372
|
`\`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.`
|
|
2087
3373
|
);
|
|
2088
3374
|
}
|
|
2089
3375
|
const hasStorageHalf = isObject(asBackend.storage);
|
|
2090
3376
|
const hasRegistryHalf = isObject(asBackend.registry);
|
|
2091
3377
|
if (!isBackend && hasPutImmutable && hasRegistryHalf) {
|
|
2092
|
-
throw new
|
|
3378
|
+
throw new ValidationError3(
|
|
2093
3379
|
"`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`."
|
|
2094
3380
|
);
|
|
2095
3381
|
}
|
|
@@ -2098,11 +3384,11 @@ function resolveStorageSource(options, clock) {
|
|
|
2098
3384
|
const registryOk = typeof asBackend.registry.compareAndSwap === "function";
|
|
2099
3385
|
if (!storageOk || !registryOk) {
|
|
2100
3386
|
const bad = !storageOk ? "`storage` half is not an IStorageDriver (no `putImmutable`)" : "`registry` half is not an IRegistryDriver (no `compareAndSwap`)";
|
|
2101
|
-
throw new
|
|
3387
|
+
throw new ValidationError3(
|
|
2102
3388
|
"`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`."
|
|
2103
3389
|
);
|
|
2104
3390
|
}
|
|
2105
|
-
throw new
|
|
3391
|
+
throw new ValidationError3(
|
|
2106
3392
|
"`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."
|
|
2107
3393
|
);
|
|
2108
3394
|
}
|
|
@@ -2123,18 +3409,18 @@ function resolveStorageSource(options, clock) {
|
|
|
2123
3409
|
};
|
|
2124
3410
|
}
|
|
2125
3411
|
if (hasGetChunk && hasPutImmutable) {
|
|
2126
|
-
throw new
|
|
3412
|
+
throw new ValidationError3(
|
|
2127
3413
|
"`storage` exposes both `getChunk` and `putImmutable` \u2014 ambiguous; pass a StorageBackend, an IStorageDriver, or a StorageChunkSource, not a hybrid"
|
|
2128
3414
|
);
|
|
2129
3415
|
}
|
|
2130
3416
|
if (!hasGetChunk && !hasPutImmutable) {
|
|
2131
|
-
throw new
|
|
3417
|
+
throw new ValidationError3(
|
|
2132
3418
|
"`storage` must be a StorageBackend, an IStorageDriver, or a StorageChunkSource"
|
|
2133
3419
|
);
|
|
2134
3420
|
}
|
|
2135
3421
|
if (hasGetChunk) {
|
|
2136
3422
|
if (options.encryption?.keystore !== void 0 || options.encryption?.required === true) {
|
|
2137
|
-
throw new
|
|
3423
|
+
throw new ValidationError3(
|
|
2138
3424
|
"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"
|
|
2139
3425
|
);
|
|
2140
3426
|
}
|
|
@@ -2156,32 +3442,32 @@ function resolveStorageSource(options, clock) {
|
|
|
2156
3442
|
}
|
|
2157
3443
|
|
|
2158
3444
|
// src/options.ts
|
|
2159
|
-
import { ValidationError as
|
|
3445
|
+
import { ValidationError as ValidationError4 } from "@cloudbitmaps/core";
|
|
2160
3446
|
var keysOf = () => (keys) => keys;
|
|
2161
3447
|
var kindOf = (v) => v === null ? "null" : Array.isArray(v) ? "an array" : `a ${typeof v}`;
|
|
2162
3448
|
function optionsError(options, op, known, booleans = [], misplaced = []) {
|
|
2163
3449
|
if (options === void 0 || options === null) return void 0;
|
|
2164
3450
|
if (typeof options !== "object" || Array.isArray(options)) {
|
|
2165
|
-
return new
|
|
3451
|
+
return new ValidationError4(`${op}: options must be an object; got ${kindOf(options)}`);
|
|
2166
3452
|
}
|
|
2167
3453
|
const bag = options;
|
|
2168
3454
|
const unknown = Object.keys(bag).filter((k) => !known.includes(k) && bag[k] !== void 0);
|
|
2169
3455
|
for (const k of misplaced) if (!unknown.includes(k) && bag[k] !== void 0) unknown.push(k);
|
|
2170
3456
|
if (unknown.length > 0) {
|
|
2171
|
-
return new
|
|
3457
|
+
return new ValidationError4(
|
|
2172
3458
|
`${op}: unknown option${unknown.length > 1 ? "s" : ""} ${unknown.map((k) => `"${k}"`).join(", ")}; it takes { ${known.join(", ")} }`
|
|
2173
3459
|
);
|
|
2174
3460
|
}
|
|
2175
3461
|
const audit = bag.audit;
|
|
2176
3462
|
if (audit !== void 0 && audit !== null && typeof audit.onEvent !== "function") {
|
|
2177
|
-
return new
|
|
3463
|
+
return new ValidationError4(
|
|
2178
3464
|
`${op}: audit must be a sink with an onEvent(event) method, such as a RecordingAuditSink`
|
|
2179
3465
|
);
|
|
2180
3466
|
}
|
|
2181
3467
|
for (const name of booleans) {
|
|
2182
3468
|
const v = bag[name];
|
|
2183
3469
|
if (v !== void 0 && typeof v !== "boolean") {
|
|
2184
|
-
return new
|
|
3470
|
+
return new ValidationError4(`${op}: \`${name}\` must be a boolean; got ${kindOf(v)}`);
|
|
2185
3471
|
}
|
|
2186
3472
|
}
|
|
2187
3473
|
return void 0;
|
|
@@ -2206,7 +3492,7 @@ import {
|
|
|
2206
3492
|
excludingReservedRows as excludingReservedRows2,
|
|
2207
3493
|
readRetentionPolicy,
|
|
2208
3494
|
CloudRoaringError,
|
|
2209
|
-
ValidationError as
|
|
3495
|
+
ValidationError as ValidationError6,
|
|
2210
3496
|
WriteConflictError as WriteConflictError2,
|
|
2211
3497
|
IntegrityError as IntegrityError4,
|
|
2212
3498
|
NotFoundError as NotFoundError2,
|
|
@@ -2230,7 +3516,7 @@ var SystemRng = class {
|
|
|
2230
3516
|
};
|
|
2231
3517
|
function validateRef(ref, verb) {
|
|
2232
3518
|
if (typeof ref !== "object" || ref === null) {
|
|
2233
|
-
throw new
|
|
3519
|
+
throw new ValidationError5(
|
|
2234
3520
|
"a segment ref is an object such as { segment: 'name' }; store.segment() takes the bare name"
|
|
2235
3521
|
);
|
|
2236
3522
|
}
|
|
@@ -2251,7 +3537,7 @@ function validateConcurrency(concurrency) {
|
|
|
2251
3537
|
function requireScope(options, op) {
|
|
2252
3538
|
if (options.namespace !== void 0) {
|
|
2253
3539
|
if (typeof options.namespace !== "string") {
|
|
2254
|
-
throw new
|
|
3540
|
+
throw new ValidationError5(
|
|
2255
3541
|
`${op}: namespace must be a string; got ${kindOf(options.namespace)}`
|
|
2256
3542
|
);
|
|
2257
3543
|
}
|
|
@@ -2259,12 +3545,12 @@ function requireScope(options, op) {
|
|
|
2259
3545
|
}
|
|
2260
3546
|
refuseReservedNamespace(options.namespace);
|
|
2261
3547
|
if (options.namespace !== void 0 && options.allNamespaces === true) {
|
|
2262
|
-
throw new
|
|
3548
|
+
throw new ValidationError5(
|
|
2263
3549
|
`${op}: pass a namespace or { allNamespaces: true }, not both: with both, it is unclear whether to scan one namespace or every one`
|
|
2264
3550
|
);
|
|
2265
3551
|
}
|
|
2266
3552
|
if (options.namespace === void 0 && options.allNamespaces !== true) {
|
|
2267
|
-
throw new
|
|
3553
|
+
throw new ValidationError5(
|
|
2268
3554
|
`${op} scans the global id space across all namespaces \u2014 pass an explicit \`namespace\`, or \`{ allNamespaces: true }\` to intentionally sweep the whole fleet`
|
|
2269
3555
|
);
|
|
2270
3556
|
}
|
|
@@ -2286,6 +3572,29 @@ var CALL_KEYS = {
|
|
|
2286
3572
|
"allowAbsentOperands",
|
|
2287
3573
|
"exclude"
|
|
2288
3574
|
]),
|
|
3575
|
+
intersectCount: keysOf()([
|
|
3576
|
+
"after",
|
|
3577
|
+
"through",
|
|
3578
|
+
"concurrency",
|
|
3579
|
+
"budget",
|
|
3580
|
+
"allowAbsentOperands",
|
|
3581
|
+
"exclude"
|
|
3582
|
+
]),
|
|
3583
|
+
unionCount: keysOf()([
|
|
3584
|
+
"after",
|
|
3585
|
+
"through",
|
|
3586
|
+
"concurrency",
|
|
3587
|
+
"budget",
|
|
3588
|
+
"allowAbsentOperands",
|
|
3589
|
+
"exclude"
|
|
3590
|
+
]),
|
|
3591
|
+
andNotCount: keysOf()([
|
|
3592
|
+
"after",
|
|
3593
|
+
"through",
|
|
3594
|
+
"concurrency",
|
|
3595
|
+
"budget",
|
|
3596
|
+
"allowAbsentOperands"
|
|
3597
|
+
]),
|
|
2289
3598
|
into: keysOf()([
|
|
2290
3599
|
"after",
|
|
2291
3600
|
"through",
|
|
@@ -2363,6 +3672,9 @@ var MISPLACED = {
|
|
|
2363
3672
|
range: outside(CALL_KEYS.into, CALL_KEYS.range),
|
|
2364
3673
|
andNot: outside(CALL_KEYS.into, CALL_KEYS.andNot),
|
|
2365
3674
|
combine: outside(CALL_KEYS.into, CALL_KEYS.combine),
|
|
3675
|
+
intersectCount: outside(CALL_KEYS.into, CALL_KEYS.intersectCount),
|
|
3676
|
+
unionCount: outside(CALL_KEYS.into, CALL_KEYS.unionCount),
|
|
3677
|
+
andNotCount: outside(CALL_KEYS.into, CALL_KEYS.andNotCount),
|
|
2366
3678
|
andNotInto: outside(CALL_KEYS.into, CALL_KEYS.andNotInto),
|
|
2367
3679
|
exportSegments: ["codec"]
|
|
2368
3680
|
};
|
|
@@ -2372,16 +3684,16 @@ var originOf;
|
|
|
2372
3684
|
function assertOneStore(verb, role, h, origin) {
|
|
2373
3685
|
if (h instanceof Segment) {
|
|
2374
3686
|
if (originOf(h) === origin) return;
|
|
2375
|
-
throw new
|
|
3687
|
+
throw new ValidationError5(
|
|
2376
3688
|
`${verb}: ${role} belongs to another store; combine segments of one store: open each with this store's segment()`
|
|
2377
3689
|
);
|
|
2378
3690
|
}
|
|
2379
3691
|
if (typeof h === "object" && h !== null && h[SEGMENT_BRAND] === true) {
|
|
2380
|
-
throw new
|
|
3692
|
+
throw new ValidationError5(
|
|
2381
3693
|
`${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`
|
|
2382
3694
|
);
|
|
2383
3695
|
}
|
|
2384
|
-
throw new
|
|
3696
|
+
throw new ValidationError5(`${verb}: ${role} must be a segment from this store's segment()`);
|
|
2385
3697
|
}
|
|
2386
3698
|
var MATERIALIZE_MANY_KEYS = [
|
|
2387
3699
|
"operands",
|
|
@@ -2471,7 +3783,7 @@ var CloudRoaring = class _CloudRoaring {
|
|
|
2471
3783
|
*/
|
|
2472
3784
|
static rejectUnknownOptions(options) {
|
|
2473
3785
|
if (options === null || options === void 0 || typeof options !== "object") {
|
|
2474
|
-
throw new
|
|
3786
|
+
throw new ValidationError5(
|
|
2475
3787
|
"CloudRoaring needs an options object with a `storage` key \u2014 got " + (options === null ? "null" : typeof options)
|
|
2476
3788
|
);
|
|
2477
3789
|
}
|
|
@@ -2489,7 +3801,7 @@ var CloudRoaring = class _CloudRoaring {
|
|
|
2489
3801
|
const tag = Object.prototype.toString.call(value).slice(8, -1);
|
|
2490
3802
|
if (typeof value !== "object" || value === null || NOT_A_GROUP[tag] !== void 0) {
|
|
2491
3803
|
const got = typeof value !== "object" ? typeof value : NOT_A_GROUP[tag];
|
|
2492
|
-
throw new
|
|
3804
|
+
throw new ValidationError5(
|
|
2493
3805
|
`CloudRoaring's \`${group}\` must be an object${offOk ? " or `false`" : ""} \u2014 got ${got}`
|
|
2494
3806
|
);
|
|
2495
3807
|
}
|
|
@@ -2499,7 +3811,7 @@ var CloudRoaring = class _CloudRoaring {
|
|
|
2499
3811
|
if (unknown.length === 0) return;
|
|
2500
3812
|
const takes = (keys) => keys.map((k) => `\`${k}\``).join(", ");
|
|
2501
3813
|
const named = [...new Set(unknown.map((u) => u.group))];
|
|
2502
|
-
throw new
|
|
3814
|
+
throw new ValidationError5(
|
|
2503
3815
|
`CloudRoaring does not take ${takes(unknown.map((u) => u.group === null ? u.key : `${u.group}.${u.key}`))}. ` + named.map(
|
|
2504
3816
|
(g) => g === null ? `The store takes ${takes(OPTION_KEYS.top)}.` : `\`${g}\` takes ${takes(OPTION_KEYS[g])}.`
|
|
2505
3817
|
).join(" ") + " https://github.com/cloudbitmaps/cloudbitmaps/blob/main/docs/guide/api-reference.md#build-a-store--new-cloudroaringoptions"
|
|
@@ -2517,7 +3829,7 @@ var CloudRoaring = class _CloudRoaring {
|
|
|
2517
3829
|
];
|
|
2518
3830
|
const entropy = options.seams?.entropy;
|
|
2519
3831
|
if (entropy !== void 0 && typeof entropy !== "function") {
|
|
2520
|
-
throw new
|
|
3832
|
+
throw new ValidationError5(
|
|
2521
3833
|
"CloudRoaring's `seams.entropy` must be a function `(length) => Uint8Array` returning that many random bytes"
|
|
2522
3834
|
);
|
|
2523
3835
|
}
|
|
@@ -2525,7 +3837,7 @@ var CloudRoaring = class _CloudRoaring {
|
|
|
2525
3837
|
if (seam === void 0) continue;
|
|
2526
3838
|
const has = (m) => seam !== null && typeof seam[m] === "function";
|
|
2527
3839
|
if (seam === null || typeof seam !== "object" || !needs.every(has)) {
|
|
2528
|
-
throw new
|
|
3840
|
+
throw new ValidationError5(
|
|
2529
3841
|
`CloudRoaring's \`${name}\` must be an object with ${needs.map((m) => `\`${m}()\``).join(" and ")}`
|
|
2530
3842
|
);
|
|
2531
3843
|
}
|
|
@@ -2545,7 +3857,7 @@ var CloudRoaring = class _CloudRoaring {
|
|
|
2545
3857
|
requirePositiveInt("cache.readerMaxBytes", cache.readerMaxBytes);
|
|
2546
3858
|
const ttl = cache.ttlMs;
|
|
2547
3859
|
if (ttl !== void 0 && (typeof ttl !== "number" || !Number.isFinite(ttl) || ttl <= 0)) {
|
|
2548
|
-
throw new
|
|
3860
|
+
throw new ValidationError5(
|
|
2549
3861
|
`cache.ttlMs must be a finite number above 0 (milliseconds); got ${typeof ttl === "string" ? JSON.stringify(ttl) : String(ttl)}`
|
|
2550
3862
|
);
|
|
2551
3863
|
}
|
|
@@ -2637,17 +3949,17 @@ var CloudRoaring = class _CloudRoaring {
|
|
|
2637
3949
|
*/
|
|
2638
3950
|
segment(name, options) {
|
|
2639
3951
|
if (typeof name === "object" && name !== null) {
|
|
2640
|
-
throw new
|
|
3952
|
+
throw new ValidationError5(
|
|
2641
3953
|
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 })"
|
|
2642
3954
|
);
|
|
2643
3955
|
}
|
|
2644
3956
|
if (options !== void 0 && options !== null) {
|
|
2645
3957
|
if (typeof options !== "object" || Array.isArray(options)) {
|
|
2646
|
-
throw new
|
|
3958
|
+
throw new ValidationError5("segment: options must be an object such as { namespace }");
|
|
2647
3959
|
}
|
|
2648
3960
|
const proto = Object.getPrototypeOf(options);
|
|
2649
3961
|
if (proto !== null && Object.getPrototypeOf(proto) !== null) {
|
|
2650
|
-
throw new
|
|
3962
|
+
throw new ValidationError5(
|
|
2651
3963
|
"segment: options must be a plain object such as { namespace }, not a class instance or an object built on another"
|
|
2652
3964
|
);
|
|
2653
3965
|
}
|
|
@@ -2655,7 +3967,7 @@ var CloudRoaring = class _CloudRoaring {
|
|
|
2655
3967
|
(k) => k !== "namespace" && options[k] !== void 0
|
|
2656
3968
|
);
|
|
2657
3969
|
if (unknown.length > 0) {
|
|
2658
|
-
throw new
|
|
3970
|
+
throw new ValidationError5(
|
|
2659
3971
|
`segment: unknown option${unknown.length > 1 ? "s" : ""} ${unknown.map((k) => `"${k}"`).join(", ")}; a handle takes { namespace } only`
|
|
2660
3972
|
);
|
|
2661
3973
|
}
|
|
@@ -2765,20 +4077,20 @@ var CloudRoaring = class _CloudRoaring {
|
|
|
2765
4077
|
/** The one body of the forms above. */
|
|
2766
4078
|
async materializeMany(options) {
|
|
2767
4079
|
if (typeof options !== "object" || options === null) {
|
|
2768
|
-
throw new
|
|
4080
|
+
throw new ValidationError5(
|
|
2769
4081
|
"materializeMany needs an options object with `operands`, `outputs` and `keep`"
|
|
2770
4082
|
);
|
|
2771
4083
|
}
|
|
2772
4084
|
const epochAt = options.feed === void 0 ? 0 : this.epochNow();
|
|
2773
4085
|
const unknown = unknownManyKeys(options);
|
|
2774
4086
|
if (unknown.length > 0) {
|
|
2775
|
-
throw new
|
|
4087
|
+
throw new ValidationError5(
|
|
2776
4088
|
`materializeMany: unknown option${unknown.length > 1 ? "s" : ""} ${unknown.map((k) => `"${k}"`).join(", ")}`
|
|
2777
4089
|
);
|
|
2778
4090
|
}
|
|
2779
4091
|
const dryRunIn = options.dryRun;
|
|
2780
4092
|
if (dryRunIn !== void 0 && typeof dryRunIn !== "boolean") {
|
|
2781
|
-
throw new
|
|
4093
|
+
throw new ValidationError5("materializeMany: dryRun must be a boolean");
|
|
2782
4094
|
}
|
|
2783
4095
|
const dryRun = dryRunIn === true;
|
|
2784
4096
|
const operandsIn = options.operands;
|
|
@@ -2790,7 +4102,7 @@ var CloudRoaring = class _CloudRoaring {
|
|
|
2790
4102
|
const feedIn = options.feed;
|
|
2791
4103
|
const mayBeEmptyIn = options.mayBeEmpty;
|
|
2792
4104
|
if (feedIn !== void 0 && options.maxBufferedBytes === void 0) {
|
|
2793
|
-
throw new
|
|
4105
|
+
throw new ValidationError5(
|
|
2794
4106
|
"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"
|
|
2795
4107
|
);
|
|
2796
4108
|
}
|
|
@@ -2800,15 +4112,15 @@ var CloudRoaring = class _CloudRoaring {
|
|
|
2800
4112
|
const budgetOption = options.budget;
|
|
2801
4113
|
const allowAbsentOperands = options.allowAbsentOperands;
|
|
2802
4114
|
if (typeof pinOption !== "boolean")
|
|
2803
|
-
throw new
|
|
4115
|
+
throw new ValidationError5("materializeMany: pin must be a boolean");
|
|
2804
4116
|
if (allowAbsentOperands !== void 0 && typeof allowAbsentOperands !== "boolean") {
|
|
2805
|
-
throw new
|
|
4117
|
+
throw new ValidationError5("materializeMany: allowAbsentOperands must be a boolean");
|
|
2806
4118
|
}
|
|
2807
4119
|
if (typeof operandsIn !== "object" || operandsIn === null || Array.isArray(operandsIn)) {
|
|
2808
|
-
throw new
|
|
4120
|
+
throw new ValidationError5("materializeMany: operands must be an object of name to segment");
|
|
2809
4121
|
}
|
|
2810
4122
|
if (!Array.isArray(outputsIn) || outputsIn.length === 0) {
|
|
2811
|
-
throw new
|
|
4123
|
+
throw new ValidationError5("materializeMany: outputs must be a non-empty array");
|
|
2812
4124
|
}
|
|
2813
4125
|
const names = Object.keys(operandsIn);
|
|
2814
4126
|
const handles = /* @__PURE__ */ new Map();
|
|
@@ -2819,14 +4131,14 @@ var CloudRoaring = class _CloudRoaring {
|
|
|
2819
4131
|
}
|
|
2820
4132
|
if (mayBeEmptyIn !== void 0 && feedIn === void 0) {
|
|
2821
4133
|
if (!Array.isArray(mayBeEmptyIn)) {
|
|
2822
|
-
throw new
|
|
4134
|
+
throw new ValidationError5(
|
|
2823
4135
|
"materializeMany: mayBeEmpty must be an array of fed operand names"
|
|
2824
4136
|
);
|
|
2825
4137
|
}
|
|
2826
4138
|
if (mayBeEmptyIn.length > 0) {
|
|
2827
4139
|
const first = mayBeEmptyIn[0];
|
|
2828
4140
|
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`;
|
|
2829
|
-
throw new
|
|
4141
|
+
throw new ValidationError5(
|
|
2830
4142
|
`materializeMany: mayBeEmpty names ${what}; it names fed operands, and this call has no feed`
|
|
2831
4143
|
);
|
|
2832
4144
|
}
|
|
@@ -2836,13 +4148,13 @@ var CloudRoaring = class _CloudRoaring {
|
|
|
2836
4148
|
const destKeys = /* @__PURE__ */ new Set();
|
|
2837
4149
|
outputsIn.forEach((raw, i) => {
|
|
2838
4150
|
if (typeof raw !== "object" || raw === null) {
|
|
2839
|
-
throw new
|
|
4151
|
+
throw new ValidationError5(`outputs[${i}] must be an object`);
|
|
2840
4152
|
}
|
|
2841
4153
|
const bad = Object.keys(raw).filter(
|
|
2842
4154
|
(k) => !MATERIALIZE_MANY_OUTPUT_KEYS.includes(k)
|
|
2843
4155
|
);
|
|
2844
4156
|
if (bad.length > 0) {
|
|
2845
|
-
throw new
|
|
4157
|
+
throw new ValidationError5(
|
|
2846
4158
|
`outputs[${i}]: unknown option${bad.length > 1 ? "s" : ""} ${bad.map((k) => `"${k}"`).join(", ")}`
|
|
2847
4159
|
);
|
|
2848
4160
|
}
|
|
@@ -2850,12 +4162,12 @@ var CloudRoaring = class _CloudRoaring {
|
|
|
2850
4162
|
const dest = spec.dest;
|
|
2851
4163
|
assertOneStore("materializeMany", `outputs[${i}].dest`, dest, this.origin);
|
|
2852
4164
|
if (operandKeys.has(dest.key())) {
|
|
2853
|
-
throw new
|
|
4165
|
+
throw new ValidationError5(
|
|
2854
4166
|
`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`
|
|
2855
4167
|
);
|
|
2856
4168
|
}
|
|
2857
4169
|
if (destKeys.has(dest.key())) {
|
|
2858
|
-
throw new
|
|
4170
|
+
throw new ValidationError5(
|
|
2859
4171
|
`outputs[${i}].dest names a segment another output of the call writes`
|
|
2860
4172
|
);
|
|
2861
4173
|
}
|
|
@@ -2928,13 +4240,13 @@ var CloudRoaring = class _CloudRoaring {
|
|
|
2928
4240
|
held.set(key, { at, handle });
|
|
2929
4241
|
} else if (prior.at !== void 0 && at !== void 0) {
|
|
2930
4242
|
if (!samePin(prior.at, at)) {
|
|
2931
|
-
throw new
|
|
4243
|
+
throw new ValidationError5(
|
|
2932
4244
|
`materializeMany: operand "${name}" holds a segment another operand holds, ${twoPins(prior.at, at)}: one call reads a segment at one generation`
|
|
2933
4245
|
);
|
|
2934
4246
|
}
|
|
2935
4247
|
} else if (prior.at !== void 0 || at !== void 0) {
|
|
2936
4248
|
if (!pinOption) {
|
|
2937
|
-
throw new
|
|
4249
|
+
throw new ValidationError5(
|
|
2938
4250
|
`materializeMany: operand "${name}" holds a segment another operand holds, ${twoPins(prior.at, at)}: one call reads a segment at one generation`
|
|
2939
4251
|
);
|
|
2940
4252
|
}
|
|
@@ -3022,7 +4334,7 @@ var CloudRoaring = class _CloudRoaring {
|
|
|
3022
4334
|
/** A call's feed with the store's erasure counter: read once here, checked by the combine before any record is read. */
|
|
3023
4335
|
feedOf(feed, mayBeEmpty, epochAt) {
|
|
3024
4336
|
if (typeof feed !== "object" || feed === null || Array.isArray(feed)) {
|
|
3025
|
-
throw new
|
|
4337
|
+
throw new ValidationError5(
|
|
3026
4338
|
"materializeMany: feed must be an object with names, records and counts"
|
|
3027
4339
|
);
|
|
3028
4340
|
}
|
|
@@ -3466,8 +4778,8 @@ var CloudRoaring = class _CloudRoaring {
|
|
|
3466
4778
|
* with `serialize('portable')` such as `roaring`'s `RoaringBitmap32`, or `{ serialized }`, portable Roaring bytes.
|
|
3467
4779
|
* A bitmap is checked (size cap, structure, safe deserializer) before the first request, written from its own
|
|
3468
4780
|
* 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
|
|
3470
|
-
*
|
|
4781
|
+
* iterable with a `serialize` method (a `RoaringBitmap32`, another copy's bitmap, or a `RoaringBitmap`
|
|
4782
|
+
* of this package) passed as ids loads as `{ bitmap }` and is not iterated. A `Uint8Array` or `Buffer` passed as ids is
|
|
3471
4783
|
* refused with `ValidationError`, since each byte would load as an id, even when it has a `serialize` of its own:
|
|
3472
4784
|
* pass bytes as `{ serialized }`.
|
|
3473
4785
|
*
|
|
@@ -3570,7 +4882,7 @@ var CloudRoaring = class _CloudRoaring {
|
|
|
3570
4882
|
const sameBackend = reads !== void 0 && (reads.origin === this.origin || this.registry !== void 0 && REGISTRY_OF.get(reads.origin) === this.registry);
|
|
3571
4883
|
if (sameBackend && reads.keys.includes(segmentKey(ref))) {
|
|
3572
4884
|
const named = ref.namespace === void 0 ? ref.segment : `${ref.namespace}/${ref.segment}`;
|
|
3573
|
-
throw new
|
|
4885
|
+
throw new ValidationError5(
|
|
3574
4886
|
`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`
|
|
3575
4887
|
);
|
|
3576
4888
|
}
|
|
@@ -3634,7 +4946,7 @@ var CloudRoaring = class _CloudRoaring {
|
|
|
3634
4946
|
async dropSegment(ref, options) {
|
|
3635
4947
|
ref = validateRef(ref, "dropSegment");
|
|
3636
4948
|
if (options === void 0 || options === null) {
|
|
3637
|
-
throw new
|
|
4949
|
+
throw new ValidationError5("dropSegment: options { confirmSegment } are required");
|
|
3638
4950
|
}
|
|
3639
4951
|
checkOptions(options, "dropSegment", CALL_KEYS.dropSegment, ["dryRun"]);
|
|
3640
4952
|
const deps = this.lifecycleDeps("dropSegment");
|
|
@@ -3953,7 +5265,7 @@ var CloudRoaring = class _CloudRoaring {
|
|
|
3953
5265
|
if (held.has(key)) {
|
|
3954
5266
|
const before = held.get(key);
|
|
3955
5267
|
if (!samePin(before, at)) {
|
|
3956
|
-
throw new
|
|
5268
|
+
throw new ValidationError5(
|
|
3957
5269
|
`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 })\``
|
|
3958
5270
|
);
|
|
3959
5271
|
}
|
|
@@ -4073,7 +5385,7 @@ var CloudRoaring = class _CloudRoaring {
|
|
|
4073
5385
|
/**
|
|
4074
5386
|
* **Export ("eject") every registered segment's current generation** through the injected `sink`, using only
|
|
4075
5387
|
* public read APIs — so your data is readable **without CloudRoaring** (the exit path; see the README's "Your
|
|
4076
|
-
* data stays yours"). `format: 'roaring'` (default) writes one **portable
|
|
5388
|
+
* data stays yours"). `format: 'roaring'` (default) writes one **portable Roaring bitmap** per segment
|
|
4077
5389
|
* (loadable by any roaring library); `'ndjson'` writes newline-delimited ids (zero-dependency, streaming).
|
|
4078
5390
|
* Enumerates via the store's **own** registry (needs one — throws {@link UnsupportedError} otherwise) so the
|
|
4079
5391
|
* enumeration and the read path provably share one registry. Encrypted segments are decrypted transparently
|
|
@@ -4115,7 +5427,7 @@ var readOptions = (options) => ({
|
|
|
4115
5427
|
});
|
|
4116
5428
|
var NO_SEGMENTS = [];
|
|
4117
5429
|
function segmentList(list, what) {
|
|
4118
|
-
if (!Array.isArray(list)) throw new
|
|
5430
|
+
if (!Array.isArray(list)) throw new ValidationError5(`${what} must be an array of segments`);
|
|
4119
5431
|
return list;
|
|
4120
5432
|
}
|
|
4121
5433
|
var STREAM_SOURCES = /* @__PURE__ */ new WeakMap();
|
|
@@ -4128,8 +5440,8 @@ function operandsLabel(verb) {
|
|
|
4128
5440
|
return verb === "andNot" ? "andNot: `excludes`" : `${verb}: \`others\``;
|
|
4129
5441
|
}
|
|
4130
5442
|
function refuseNoOperands(verb) {
|
|
4131
|
-
throw new
|
|
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 })"
|
|
5443
|
+
throw new ValidationError5(
|
|
5444
|
+
verb === "intersect" ? "intersect requires at least one segment to intersect with; to read every id of one segment, use iterate()" : verb === "intersectCount" ? "intersectCount requires at least one segment to intersect with; to count one segment, use count()" : "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 })"
|
|
4133
5445
|
);
|
|
4134
5446
|
}
|
|
4135
5447
|
var AS_IDS = {
|
|
@@ -4209,7 +5521,7 @@ var Segment = class _Segment {
|
|
|
4209
5521
|
*/
|
|
4210
5522
|
constructor(parts) {
|
|
4211
5523
|
if (!minting) {
|
|
4212
|
-
throw new
|
|
5524
|
+
throw new ValidationError5(
|
|
4213
5525
|
"a Segment is not constructed directly; call `store.segment(name)`"
|
|
4214
5526
|
);
|
|
4215
5527
|
}
|
|
@@ -4323,11 +5635,11 @@ var Segment = class _Segment {
|
|
|
4323
5635
|
leaseUntilOf(op, options) {
|
|
4324
5636
|
if (options === void 0 || options === null) return void 0;
|
|
4325
5637
|
if (typeof options !== "object" || Array.isArray(options)) {
|
|
4326
|
-
throw new
|
|
5638
|
+
throw new ValidationError5(`${op}: options must be an object such as { leaseUntil }`);
|
|
4327
5639
|
}
|
|
4328
5640
|
const unknown = Object.keys(options).filter((k) => k !== "leaseUntil");
|
|
4329
5641
|
if (unknown.length > 0) {
|
|
4330
|
-
throw new
|
|
5642
|
+
throw new ValidationError5(
|
|
4331
5643
|
`${op}: unknown option${unknown.length > 1 ? "s" : ""} ${unknown.map((k) => `"${k}"`).join(", ")}; this version takes { leaseUntil } only`
|
|
4332
5644
|
);
|
|
4333
5645
|
}
|
|
@@ -4335,17 +5647,17 @@ var Segment = class _Segment {
|
|
|
4335
5647
|
if (until === void 0) return void 0;
|
|
4336
5648
|
const now = this.clock.now();
|
|
4337
5649
|
if (typeof until !== "number" || !Number.isSafeInteger(until)) {
|
|
4338
|
-
throw new
|
|
5650
|
+
throw new ValidationError5(
|
|
4339
5651
|
`${op}: leaseUntil must be an integer epoch-MILLISECONDS; got ${String(until)}`
|
|
4340
5652
|
);
|
|
4341
5653
|
}
|
|
4342
5654
|
if (until <= now) {
|
|
4343
|
-
throw new
|
|
5655
|
+
throw new ValidationError5(
|
|
4344
5656
|
`${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\``
|
|
4345
5657
|
);
|
|
4346
5658
|
}
|
|
4347
5659
|
if (until > now + MAX_LEASE_MS) {
|
|
4348
|
-
throw new
|
|
5660
|
+
throw new ValidationError5(
|
|
4349
5661
|
`${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`
|
|
4350
5662
|
);
|
|
4351
5663
|
}
|
|
@@ -4449,22 +5761,22 @@ var Segment = class _Segment {
|
|
|
4449
5761
|
const { generation, fingerprint, version } = at ?? {};
|
|
4450
5762
|
const unknown = typeof at === "object" && at !== null ? Object.keys(at).filter((k) => !["generation", "fingerprint", "version"].includes(k)) : [];
|
|
4451
5763
|
if (unknown.length > 0) {
|
|
4452
|
-
throw new
|
|
5764
|
+
throw new ValidationError5(
|
|
4453
5765
|
`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`
|
|
4454
5766
|
);
|
|
4455
5767
|
}
|
|
4456
5768
|
if (generation === null) {
|
|
4457
|
-
throw new
|
|
5769
|
+
throw new ValidationError5(
|
|
4458
5770
|
"pinAt: the pin named no generation (the segment had none when it was pinned), so there is nothing to reopen"
|
|
4459
5771
|
);
|
|
4460
5772
|
}
|
|
4461
5773
|
if (version !== void 0 && typeof version !== "string") {
|
|
4462
|
-
throw new
|
|
5774
|
+
throw new ValidationError5(
|
|
4463
5775
|
"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"
|
|
4464
5776
|
);
|
|
4465
5777
|
}
|
|
4466
5778
|
if (typeof generation !== "number" || !Number.isSafeInteger(generation) || generation < 0 || typeof fingerprint !== "string" || !/^\d+:\d+$/.test(fingerprint)) {
|
|
4467
|
-
throw new
|
|
5779
|
+
throw new ValidationError5(
|
|
4468
5780
|
"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"
|
|
4469
5781
|
);
|
|
4470
5782
|
}
|
|
@@ -4513,7 +5825,7 @@ var Segment = class _Segment {
|
|
|
4513
5825
|
if (role === void 0) return;
|
|
4514
5826
|
const { namespace, segment } = dest.ref;
|
|
4515
5827
|
const named = namespace === void 0 ? segment : `${namespace}/${segment}`;
|
|
4516
|
-
throw new
|
|
5828
|
+
throw new ValidationError5(
|
|
4517
5829
|
`${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`
|
|
4518
5830
|
);
|
|
4519
5831
|
}
|
|
@@ -4839,6 +6151,111 @@ var Segment = class _Segment {
|
|
|
4839
6151
|
);
|
|
4840
6152
|
return this.combineInto("andNotInto", dest, excludes, options);
|
|
4841
6153
|
}
|
|
6154
|
+
/**
|
|
6155
|
+
* How many ids `this ∩ others…` holds (minus `exclude`): the length of what {@link intersect} streams, without
|
|
6156
|
+
* streaming it. Every key all the operands hold is decoded and counted as the stream reads it, and a key only some
|
|
6157
|
+
* operands hold is not read, so the call makes the requests {@link intersect} makes and returns a number instead of
|
|
6158
|
+
* the ids. It is exact: it never answers a key from an index, so it trusts nothing {@link count} trusts.
|
|
6159
|
+
*
|
|
6160
|
+
* The range, `concurrency`, `budget`, `allowAbsentOperands` and `exclude` are {@link intersect}'s; a write option fails
|
|
6161
|
+
* the call with {@link ValidationError} before any request, and so does an empty `others` (to count one segment, use
|
|
6162
|
+
* {@link count}).
|
|
6163
|
+
*
|
|
6164
|
+
* Like a stream, a count that runs while a segment is erased or reloaded can describe two instants, within the bound
|
|
6165
|
+
* the streams state. A union or a difference, and an intersection with an `exclude`, looks at its operands'
|
|
6166
|
+
* generations every `concurrency` keys; an intersection with no `exclude` makes no such look, since it decodes every
|
|
6167
|
+
* key and so shows a move in the chunks it decodes, as its stream does. Either way it plans again above the last key
|
|
6168
|
+
* it took when one moved. A pinned handle counts the generation it pinned, and each pinned operand's object is
|
|
6169
|
+
* looked up once before the first key (one footer read each, which `budget` does not charge, and which the stream
|
|
6170
|
+
* does not make), and again at each look where there is one, so an erasure of what it pinned fails the count with
|
|
6171
|
+
* {@link NotFoundError}; a
|
|
6172
|
+
* fault the look meets other than a transient one, which is retried, is raised as it is. A call that involves a
|
|
6173
|
+
* handle whose lease has ended, or has ended by the next look, throws {@link LeaseExpiredError}.
|
|
6174
|
+
*/
|
|
6175
|
+
async intersectCount(others, options) {
|
|
6176
|
+
checkOptions(
|
|
6177
|
+
options,
|
|
6178
|
+
"intersectCount",
|
|
6179
|
+
CALL_KEYS.intersectCount,
|
|
6180
|
+
["allowAbsentOperands"],
|
|
6181
|
+
MISPLACED.intersectCount
|
|
6182
|
+
);
|
|
6183
|
+
return this.countCombine("intersect", others, options ?? void 0);
|
|
6184
|
+
}
|
|
6185
|
+
/**
|
|
6186
|
+
* How many ids `this ∪ others…` holds (minus `exclude`): the length of what {@link union} streams, without streaming
|
|
6187
|
+
* it. A chunk key only one operand holds, that no `exclude` holds and the range does not cut, is answered from that
|
|
6188
|
+
* operand's index, so a union of segments that mostly do not overlap reads little of them; every other key is
|
|
6189
|
+
* decoded and counted. On handles that are not pinned it makes no more requests than {@link union} does, and reads
|
|
6190
|
+
* fewer bytes when the shared keys are few. An empty `others`, with no `exclude` and no range, is {@link count} of
|
|
6191
|
+
* `this`, answered from the registry row when it can be; when that figure is 0 it adds one registry read, to refuse
|
|
6192
|
+
* a segment that does not exist as the stream does.
|
|
6193
|
+
*
|
|
6194
|
+
* What it trusts: the index, for each key it answers without decoding, as {@link count} does, so a party who can write
|
|
6195
|
+
* an object's index can make that key's figure wrong; a decoded key is exact. A source with no per-chunk counts
|
|
6196
|
+
* decodes every key. It takes the options {@link intersectCount} takes; the erasure bound, the lease checks and the
|
|
6197
|
+
* pinned handles are as for {@link intersectCount}, a pinned operand adding a footer read before the first key and at
|
|
6198
|
+
* each look. An empty `others` on a pinned handle is {@link count} of the pin, with no look.
|
|
6199
|
+
*/
|
|
6200
|
+
async unionCount(others, options) {
|
|
6201
|
+
checkOptions(
|
|
6202
|
+
options,
|
|
6203
|
+
"unionCount",
|
|
6204
|
+
CALL_KEYS.unionCount,
|
|
6205
|
+
["allowAbsentOperands"],
|
|
6206
|
+
MISPLACED.unionCount
|
|
6207
|
+
);
|
|
6208
|
+
return this.countCombine("union", others, options ?? void 0);
|
|
6209
|
+
}
|
|
6210
|
+
/**
|
|
6211
|
+
* How many ids `this \ (excludes…)` holds: the length of what {@link andNot} streams, without streaming it. A chunk
|
|
6212
|
+
* key of `this` that no exclude holds and the range does not cut is answered from its index and not read; a key an
|
|
6213
|
+
* exclude shares is decoded and counted. On handles that are not pinned it makes no more requests than {@link andNot}
|
|
6214
|
+
* does, and reads fewer bytes when the excludes overlap little of `this`. An empty `excludes`, with no range, is
|
|
6215
|
+
* {@link count} of `this` (the stream of it is the whole of `this`), answered from the registry row when it can be,
|
|
6216
|
+
* with one registry read added when that figure is 0.
|
|
6217
|
+
*
|
|
6218
|
+
* It takes the options {@link andNot} takes (every one of {@link intersectCount}'s but `exclude`, which a count of a
|
|
6219
|
+
* difference has no use for, since `excludes` is its subtraction) and trusts what {@link unionCount} trusts. The
|
|
6220
|
+
* erasure bound, the lease checks and the pinned handles are as for {@link intersectCount}.
|
|
6221
|
+
*/
|
|
6222
|
+
async andNotCount(excludes, options) {
|
|
6223
|
+
checkOptions(
|
|
6224
|
+
options,
|
|
6225
|
+
"andNotCount",
|
|
6226
|
+
CALL_KEYS.andNotCount,
|
|
6227
|
+
["allowAbsentOperands"],
|
|
6228
|
+
MISPLACED.andNotCount
|
|
6229
|
+
);
|
|
6230
|
+
return this.countCombine("andNot", excludes, options ?? void 0);
|
|
6231
|
+
}
|
|
6232
|
+
/** The one body of the three count methods, after each has checked its own options. */
|
|
6233
|
+
async countCombine(verb, operands, options) {
|
|
6234
|
+
const name = `${verb}Count`;
|
|
6235
|
+
const exclude = verb === "andNot" ? NO_SEGMENTS : this.excludesOf(options);
|
|
6236
|
+
const others = segmentList(
|
|
6237
|
+
operands,
|
|
6238
|
+
verb === "andNot" ? `${name}: \`excludes\`` : `${name}: \`others\``
|
|
6239
|
+
);
|
|
6240
|
+
if (verb === "intersect" && others.length === 0) refuseNoOperands("intersectCount");
|
|
6241
|
+
const handles = [this, ...others, ...exclude];
|
|
6242
|
+
this.assertSegments(name, verb === "andNot" ? "an exclude" : "an operand", others);
|
|
6243
|
+
this.assertSegments(name, "an exclude", exclude);
|
|
6244
|
+
this.assertLeases(handles);
|
|
6245
|
+
const engine = this.combineEngine(handles) ?? this.engine;
|
|
6246
|
+
const read = options == null ? void 0 : readOptions(options);
|
|
6247
|
+
const guard2 = handles.some((h) => h.leaseHold !== void 0) ? () => this.assertLeases(handles) : void 0;
|
|
6248
|
+
const opts = guard2 === void 0 ? read : { ...read, guard: guard2 };
|
|
6249
|
+
const refs = others.map((o) => o.ref);
|
|
6250
|
+
if (verb === "andNot") return engine.combineCount([this.ref], refs, "all", verb, opts);
|
|
6251
|
+
return engine.combineCount(
|
|
6252
|
+
[this.ref, ...refs],
|
|
6253
|
+
exclude.map((o) => o.ref),
|
|
6254
|
+
verb === "union" ? "any" : "all",
|
|
6255
|
+
verb,
|
|
6256
|
+
opts
|
|
6257
|
+
);
|
|
6258
|
+
}
|
|
4842
6259
|
/**
|
|
4843
6260
|
* The one body of the three combines, read as ids or as chunks. `operands` is `others` for `intersect` and
|
|
4844
6261
|
* `union`, and `excludes` for `andNot`, which takes no `exclude` option.
|
|
@@ -4943,25 +6360,25 @@ function parseConfig(env) {
|
|
|
4943
6360
|
);
|
|
4944
6361
|
if (unknown.length > 0) {
|
|
4945
6362
|
const which = unknown.length > 1 ? `${unknown.join(", ")} are not settings export-segments takes.` : `${unknown[0]} is not a setting export-segments takes.`;
|
|
4946
|
-
throw new
|
|
6363
|
+
throw new ValidationError6(
|
|
4947
6364
|
`${which} It takes ${EXPORT_VARIABLES.join(", ")}; run export-segments --help`
|
|
4948
6365
|
);
|
|
4949
6366
|
}
|
|
4950
6367
|
const root = env.CR_EXPORT_ROOT;
|
|
4951
6368
|
if (root === void 0 || root === "") {
|
|
4952
|
-
throw new
|
|
6369
|
+
throw new ValidationError6(
|
|
4953
6370
|
"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"
|
|
4954
6371
|
);
|
|
4955
6372
|
}
|
|
4956
6373
|
const out = env.CR_EXPORT_OUT;
|
|
4957
6374
|
if (out === void 0 || out === "") {
|
|
4958
|
-
throw new
|
|
6375
|
+
throw new ValidationError6(
|
|
4959
6376
|
"CR_EXPORT_OUT is not set: the directory to write the dump to. export-segments also needs CR_EXPORT_ROOT; run export-segments --help"
|
|
4960
6377
|
);
|
|
4961
6378
|
}
|
|
4962
6379
|
const format = env.CR_EXPORT_FORMAT || "roaring";
|
|
4963
6380
|
if (format !== "roaring" && format !== "ndjson") {
|
|
4964
|
-
throw new
|
|
6381
|
+
throw new ValidationError6(`CR_EXPORT_FORMAT must be "roaring" or "ndjson"; got ${format}`);
|
|
4965
6382
|
}
|
|
4966
6383
|
const namespace = env.CR_EXPORT_NAMESPACE || void 0;
|
|
4967
6384
|
return { root, out, format, namespace };
|
|
@@ -4976,7 +6393,7 @@ async function ensureOwnDirectory(out, dir) {
|
|
|
4976
6393
|
}
|
|
4977
6394
|
const found = await lstat(dir);
|
|
4978
6395
|
const refuse = (why) => {
|
|
4979
|
-
throw new
|
|
6396
|
+
throw new ValidationError6(`the export directory is not one this tool made: ${why}`);
|
|
4980
6397
|
};
|
|
4981
6398
|
if (found.isSymbolicLink()) refuse("a namespace directory is a symbolic link");
|
|
4982
6399
|
if (!found.isDirectory()) refuse("a namespace path is not a directory");
|
|
@@ -4991,7 +6408,7 @@ function fsSink(out) {
|
|
|
4991
6408
|
async open(ref, ext) {
|
|
4992
6409
|
const part = namespacePathPart(ref.namespace);
|
|
4993
6410
|
if (part.toLowerCase() === MANIFEST_NAME) {
|
|
4994
|
-
throw new
|
|
6411
|
+
throw new ValidationError6(
|
|
4995
6412
|
`a namespace named ${MANIFEST_NAME} (in any letter case) cannot be exported to a directory: its folder would be the manifest's path`
|
|
4996
6413
|
);
|
|
4997
6414
|
}
|
|
@@ -5036,10 +6453,10 @@ async function requireStoreRoot(root) {
|
|
|
5036
6453
|
try {
|
|
5037
6454
|
entries = await readdir(root);
|
|
5038
6455
|
} catch {
|
|
5039
|
-
throw new
|
|
6456
|
+
throw new ValidationError6("CR_EXPORT_ROOT does not name a directory that can be read");
|
|
5040
6457
|
}
|
|
5041
6458
|
if (entries.length === 0) {
|
|
5042
|
-
throw new
|
|
6459
|
+
throw new ValidationError6(
|
|
5043
6460
|
"CR_EXPORT_ROOT is empty: it holds no store (an unmounted volume, or the wrong directory)"
|
|
5044
6461
|
);
|
|
5045
6462
|
}
|
|
@@ -5055,7 +6472,7 @@ async function main(env = process.env, now = () => Date.now()) {
|
|
|
5055
6472
|
const store = new CloudRoaring({ storage });
|
|
5056
6473
|
const priorManifest = await lstat(join(config.out, MANIFEST_NAME)).catch(() => null);
|
|
5057
6474
|
if (priorManifest?.isDirectory() === true) {
|
|
5058
|
-
throw new
|
|
6475
|
+
throw new ValidationError6(
|
|
5059
6476
|
`${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`
|
|
5060
6477
|
);
|
|
5061
6478
|
}
|