@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
package/dist/index.js
CHANGED
|
@@ -119,14 +119,99 @@ function refuseReservedNamespace(namespace) {
|
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
-
// src/roaring-codec.ts
|
|
123
|
-
import { ValidationError as ValidationError3, decodeSerialized } from "@cloudbitmaps/core";
|
|
124
|
-
|
|
125
122
|
// src/ts-roaring/bitmap.ts
|
|
126
|
-
import { IntegrityError as IntegrityError3, ValidationError as ValidationError2 } from "@cloudbitmaps/core";
|
|
123
|
+
import { IntegrityError as IntegrityError3, ValidationError as ValidationError2, refusalOfId } from "@cloudbitmaps/core";
|
|
127
124
|
|
|
128
125
|
// src/portable/layout.ts
|
|
129
126
|
import { IntegrityError } from "@cloudbitmaps/core";
|
|
127
|
+
|
|
128
|
+
// src/portable/popcount.ts
|
|
129
|
+
var BITSET_WORDS = 2048;
|
|
130
|
+
function popcount32(word) {
|
|
131
|
+
let w = word - (word >>> 1 & 1431655765);
|
|
132
|
+
w = (w & 858993459) + (w >>> 2 & 858993459);
|
|
133
|
+
return Math.imul(w + (w >>> 4) & 252645135, 16843009) >>> 24;
|
|
134
|
+
}
|
|
135
|
+
function popcountWords(d) {
|
|
136
|
+
let total = 0;
|
|
137
|
+
let ones = 0;
|
|
138
|
+
let twos = 0;
|
|
139
|
+
let fours = 0;
|
|
140
|
+
let eights = 0;
|
|
141
|
+
for (let i = 0; i < BITSET_WORDS; i += 16) {
|
|
142
|
+
let u;
|
|
143
|
+
let twosA;
|
|
144
|
+
let twosB;
|
|
145
|
+
let foursA;
|
|
146
|
+
let foursB;
|
|
147
|
+
let x = d[i];
|
|
148
|
+
let y = d[i + 1];
|
|
149
|
+
u = ones ^ x;
|
|
150
|
+
twosA = ones & x | u & y;
|
|
151
|
+
ones = u ^ y;
|
|
152
|
+
x = d[i + 2];
|
|
153
|
+
y = d[i + 3];
|
|
154
|
+
u = ones ^ x;
|
|
155
|
+
twosB = ones & x | u & y;
|
|
156
|
+
ones = u ^ y;
|
|
157
|
+
u = twos ^ twosA;
|
|
158
|
+
foursA = twos & twosA | u & twosB;
|
|
159
|
+
twos = u ^ twosB;
|
|
160
|
+
x = d[i + 4];
|
|
161
|
+
y = d[i + 5];
|
|
162
|
+
u = ones ^ x;
|
|
163
|
+
twosA = ones & x | u & y;
|
|
164
|
+
ones = u ^ y;
|
|
165
|
+
x = d[i + 6];
|
|
166
|
+
y = d[i + 7];
|
|
167
|
+
u = ones ^ x;
|
|
168
|
+
twosB = ones & x | u & y;
|
|
169
|
+
ones = u ^ y;
|
|
170
|
+
u = twos ^ twosA;
|
|
171
|
+
foursB = twos & twosA | u & twosB;
|
|
172
|
+
twos = u ^ twosB;
|
|
173
|
+
u = fours ^ foursA;
|
|
174
|
+
const eightsA = fours & foursA | u & foursB;
|
|
175
|
+
fours = u ^ foursB;
|
|
176
|
+
x = d[i + 8];
|
|
177
|
+
y = d[i + 9];
|
|
178
|
+
u = ones ^ x;
|
|
179
|
+
twosA = ones & x | u & y;
|
|
180
|
+
ones = u ^ y;
|
|
181
|
+
x = d[i + 10];
|
|
182
|
+
y = d[i + 11];
|
|
183
|
+
u = ones ^ x;
|
|
184
|
+
twosB = ones & x | u & y;
|
|
185
|
+
ones = u ^ y;
|
|
186
|
+
u = twos ^ twosA;
|
|
187
|
+
foursA = twos & twosA | u & twosB;
|
|
188
|
+
twos = u ^ twosB;
|
|
189
|
+
x = d[i + 12];
|
|
190
|
+
y = d[i + 13];
|
|
191
|
+
u = ones ^ x;
|
|
192
|
+
twosA = ones & x | u & y;
|
|
193
|
+
ones = u ^ y;
|
|
194
|
+
x = d[i + 14];
|
|
195
|
+
y = d[i + 15];
|
|
196
|
+
u = ones ^ x;
|
|
197
|
+
twosB = ones & x | u & y;
|
|
198
|
+
ones = u ^ y;
|
|
199
|
+
u = twos ^ twosA;
|
|
200
|
+
foursB = twos & twosA | u & twosB;
|
|
201
|
+
twos = u ^ twosB;
|
|
202
|
+
u = fours ^ foursA;
|
|
203
|
+
const eightsB = fours & foursA | u & foursB;
|
|
204
|
+
fours = u ^ foursB;
|
|
205
|
+
u = eights ^ eightsA;
|
|
206
|
+
const sixteens = eights & eightsA | u & eightsB;
|
|
207
|
+
eights = u ^ eightsB;
|
|
208
|
+
total += popcount32(sixteens);
|
|
209
|
+
}
|
|
210
|
+
return 16 * total + 8 * popcount32(eights) + 4 * popcount32(fours) + 2 * popcount32(twos) + popcount32(ones);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// src/portable/layout.ts
|
|
214
|
+
var LITTLE_ENDIAN = new Uint8Array(Uint16Array.of(1).buffer)[0] === 1;
|
|
130
215
|
var SERIAL_COOKIE_NO_RUNCONTAINER = 12346;
|
|
131
216
|
var SERIAL_COOKIE = 12347;
|
|
132
217
|
var NO_OFFSET_THRESHOLD = 4;
|
|
@@ -191,7 +276,7 @@ function walk(bytes, out) {
|
|
|
191
276
|
const key = view.getUint16(descriptiveAt + i * 4, true);
|
|
192
277
|
if (key <= previousKey) {
|
|
193
278
|
throw new IntegrityError(
|
|
194
|
-
`portable roaring: container keys are not strictly ascending
|
|
279
|
+
`portable roaring: container keys are not strictly ascending at index ${i}`
|
|
195
280
|
);
|
|
196
281
|
}
|
|
197
282
|
previousKey = key;
|
|
@@ -224,7 +309,7 @@ function checkContainer(bytes, view, pos, kind, cardinality, i) {
|
|
|
224
309
|
if (pos + BITMAP_CONTAINER_BYTES > length) {
|
|
225
310
|
throw overrun(bytes, pos, BITMAP_CONTAINER_BYTES, `container ${i} (bitmap)`);
|
|
226
311
|
}
|
|
227
|
-
const bits =
|
|
312
|
+
const bits = bitsetBits(bytes, pos);
|
|
228
313
|
if (bits !== cardinality) {
|
|
229
314
|
throw new IntegrityError(
|
|
230
315
|
`portable roaring: container ${i} (bitmap) holds ${bits} values, but its header says ${cardinality}`
|
|
@@ -284,25 +369,22 @@ function checkRuns(view, at, runs, index) {
|
|
|
284
369
|
}
|
|
285
370
|
return covered;
|
|
286
371
|
}
|
|
287
|
-
function
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
w = (w & 858993459) + (w >>> 2 & 858993459);
|
|
293
|
-
bits += Math.imul(w + (w >>> 4) & 252645135, 16843009) >>> 24;
|
|
294
|
-
}
|
|
295
|
-
return bits;
|
|
372
|
+
function bitsetBits(bytes, at) {
|
|
373
|
+
const offset = bytes.byteOffset + at;
|
|
374
|
+
if ((offset & 3) === 0) return popcountWords(new Uint32Array(bytes.buffer, offset, BITSET_WORDS));
|
|
375
|
+
scratchBytes.set(bytes.subarray(at, at + BITMAP_CONTAINER_BYTES));
|
|
376
|
+
return popcountWords(scratchWords);
|
|
296
377
|
}
|
|
378
|
+
var scratchWords = new Uint32Array(BITSET_WORDS);
|
|
379
|
+
var scratchBytes = new Uint8Array(scratchWords.buffer);
|
|
297
380
|
|
|
298
381
|
// src/ts-roaring/containers.ts
|
|
299
382
|
var ARRAY2 = 0;
|
|
300
383
|
var BITSET = 1;
|
|
301
384
|
var RUN2 = 2;
|
|
302
|
-
var WORDS =
|
|
385
|
+
var WORDS = BITSET_WORDS;
|
|
303
386
|
var BITSET_BYTES = 8192;
|
|
304
387
|
var GALLOP_SKEW = 16;
|
|
305
|
-
var LITTLE_ENDIAN = new Uint8Array(Uint16Array.of(1).buffer)[0] === 1;
|
|
306
388
|
var Container = class {
|
|
307
389
|
constructor(kind, data, off, len, card, shared) {
|
|
308
390
|
this.kind = kind;
|
|
@@ -352,12 +434,7 @@ function pairs16(n) {
|
|
|
352
434
|
function arrayOfScratch(scratch, n) {
|
|
353
435
|
return n === 0 ? null : arrayContainer(scratch.slice(0, n), n);
|
|
354
436
|
}
|
|
355
|
-
function
|
|
356
|
-
let w = word - (word >>> 1 & 1431655765);
|
|
357
|
-
w = (w & 858993459) + (w >>> 2 & 858993459);
|
|
358
|
-
return Math.imul(w + (w >>> 4) & 252645135, 16843009) >>> 24;
|
|
359
|
-
}
|
|
360
|
-
function popcountWords(d) {
|
|
437
|
+
function popcountAnd(d, e) {
|
|
361
438
|
let total = 0;
|
|
362
439
|
let ones = 0;
|
|
363
440
|
let twos = 0;
|
|
@@ -369,26 +446,26 @@ function popcountWords(d) {
|
|
|
369
446
|
let twosB;
|
|
370
447
|
let foursA;
|
|
371
448
|
let foursB;
|
|
372
|
-
let x = d[i];
|
|
373
|
-
let y = d[i + 1];
|
|
449
|
+
let x = d[i] & e[i];
|
|
450
|
+
let y = d[i + 1] & e[i + 1];
|
|
374
451
|
u = ones ^ x;
|
|
375
452
|
twosA = ones & x | u & y;
|
|
376
453
|
ones = u ^ y;
|
|
377
|
-
x = d[i + 2];
|
|
378
|
-
y = d[i + 3];
|
|
454
|
+
x = d[i + 2] & e[i + 2];
|
|
455
|
+
y = d[i + 3] & e[i + 3];
|
|
379
456
|
u = ones ^ x;
|
|
380
457
|
twosB = ones & x | u & y;
|
|
381
458
|
ones = u ^ y;
|
|
382
459
|
u = twos ^ twosA;
|
|
383
460
|
foursA = twos & twosA | u & twosB;
|
|
384
461
|
twos = u ^ twosB;
|
|
385
|
-
x = d[i + 4];
|
|
386
|
-
y = d[i + 5];
|
|
462
|
+
x = d[i + 4] & e[i + 4];
|
|
463
|
+
y = d[i + 5] & e[i + 5];
|
|
387
464
|
u = ones ^ x;
|
|
388
465
|
twosA = ones & x | u & y;
|
|
389
466
|
ones = u ^ y;
|
|
390
|
-
x = d[i + 6];
|
|
391
|
-
y = d[i + 7];
|
|
467
|
+
x = d[i + 6] & e[i + 6];
|
|
468
|
+
y = d[i + 7] & e[i + 7];
|
|
392
469
|
u = ones ^ x;
|
|
393
470
|
twosB = ones & x | u & y;
|
|
394
471
|
ones = u ^ y;
|
|
@@ -398,26 +475,26 @@ function popcountWords(d) {
|
|
|
398
475
|
u = fours ^ foursA;
|
|
399
476
|
const eightsA = fours & foursA | u & foursB;
|
|
400
477
|
fours = u ^ foursB;
|
|
401
|
-
x = d[i + 8];
|
|
402
|
-
y = d[i + 9];
|
|
478
|
+
x = d[i + 8] & e[i + 8];
|
|
479
|
+
y = d[i + 9] & e[i + 9];
|
|
403
480
|
u = ones ^ x;
|
|
404
481
|
twosA = ones & x | u & y;
|
|
405
482
|
ones = u ^ y;
|
|
406
|
-
x = d[i + 10];
|
|
407
|
-
y = d[i + 11];
|
|
483
|
+
x = d[i + 10] & e[i + 10];
|
|
484
|
+
y = d[i + 11] & e[i + 11];
|
|
408
485
|
u = ones ^ x;
|
|
409
486
|
twosB = ones & x | u & y;
|
|
410
487
|
ones = u ^ y;
|
|
411
488
|
u = twos ^ twosA;
|
|
412
489
|
foursA = twos & twosA | u & twosB;
|
|
413
490
|
twos = u ^ twosB;
|
|
414
|
-
x = d[i + 12];
|
|
415
|
-
y = d[i + 13];
|
|
491
|
+
x = d[i + 12] & e[i + 12];
|
|
492
|
+
y = d[i + 13] & e[i + 13];
|
|
416
493
|
u = ones ^ x;
|
|
417
494
|
twosA = ones & x | u & y;
|
|
418
495
|
ones = u ^ y;
|
|
419
|
-
x = d[i + 14];
|
|
420
|
-
y = d[i + 15];
|
|
496
|
+
x = d[i + 14] & e[i + 14];
|
|
497
|
+
y = d[i + 15] & e[i + 15];
|
|
421
498
|
u = ones ^ x;
|
|
422
499
|
twosB = ones & x | u & y;
|
|
423
500
|
ones = u ^ y;
|
|
@@ -460,6 +537,19 @@ function clearRange(words, start, end) {
|
|
|
460
537
|
for (let i = first + 1; i < last; i++) words[i] = 0;
|
|
461
538
|
words[last] = words[last] & ~tail;
|
|
462
539
|
}
|
|
540
|
+
function flipRange(words, start, end) {
|
|
541
|
+
const first = start >>> 5;
|
|
542
|
+
const last = end >>> 5;
|
|
543
|
+
const head = 4294967295 << (start & 31) >>> 0;
|
|
544
|
+
const tail = 4294967295 >>> 31 - (end & 31);
|
|
545
|
+
if (first === last) {
|
|
546
|
+
words[first] = words[first] ^ head & tail;
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
549
|
+
words[first] = words[first] ^ head;
|
|
550
|
+
for (let i = first + 1; i < last; i++) words[i] = ~words[i];
|
|
551
|
+
words[last] = words[last] ^ tail;
|
|
552
|
+
}
|
|
463
553
|
function fromSortedIds(ids, from, to) {
|
|
464
554
|
const n = to - from;
|
|
465
555
|
if (n <= ARRAY_MAX_CARDINALITY) {
|
|
@@ -515,11 +605,12 @@ function writeLows(c, out) {
|
|
|
515
605
|
}
|
|
516
606
|
}
|
|
517
607
|
}
|
|
608
|
+
var SMALL_IDS = 32;
|
|
518
609
|
function appendIds(c, out, at, base) {
|
|
519
610
|
if (c.kind === ARRAY2) {
|
|
520
611
|
const u162 = lows16(c);
|
|
521
612
|
const end = c.off + c.len;
|
|
522
|
-
if (base === 0) {
|
|
613
|
+
if (base === 0 && c.len >= SMALL_IDS) {
|
|
523
614
|
out.set(u162.subarray(c.off, end), at);
|
|
524
615
|
return at + c.len;
|
|
525
616
|
}
|
|
@@ -542,14 +633,15 @@ function appendIds(c, out, at, base) {
|
|
|
542
633
|
const u16 = lows16(c);
|
|
543
634
|
for (let r = 0; r < c.len; r++) {
|
|
544
635
|
const start = u16[c.off + 2 * r];
|
|
545
|
-
const
|
|
546
|
-
if (
|
|
547
|
-
|
|
636
|
+
const length = u16[c.off + 2 * r + 1];
|
|
637
|
+
if (length < LONG_RUN) {
|
|
638
|
+
const last = base + start + length;
|
|
639
|
+
for (let v = base + start; v <= last; v++) out[at++] = v;
|
|
548
640
|
continue;
|
|
549
641
|
}
|
|
550
642
|
const from = at;
|
|
551
|
-
out.set(iota().subarray(start,
|
|
552
|
-
at +=
|
|
643
|
+
out.set(iota().subarray(start, start + length + 1), at);
|
|
644
|
+
at += length + 1;
|
|
553
645
|
if (base !== 0) for (let i = from; i < at; i++) out[i] = out[i] + base;
|
|
554
646
|
}
|
|
555
647
|
return at;
|
|
@@ -635,31 +727,130 @@ function containerHas(c, low) {
|
|
|
635
727
|
const r = c.off + 2 * (after - 1);
|
|
636
728
|
return low <= u16[r] + u16[r + 1];
|
|
637
729
|
}
|
|
730
|
+
function runsAfter(data, off, from, len, value) {
|
|
731
|
+
let step = 1;
|
|
732
|
+
let lo = from;
|
|
733
|
+
let hi = from;
|
|
734
|
+
while (hi < len && data[off + 2 * hi] <= value) {
|
|
735
|
+
lo = hi + 1;
|
|
736
|
+
hi += step;
|
|
737
|
+
step *= 2;
|
|
738
|
+
}
|
|
739
|
+
if (hi > len) hi = len;
|
|
740
|
+
while (lo < hi) {
|
|
741
|
+
const mid = lo + hi >>> 1;
|
|
742
|
+
if (data[off + 2 * mid] <= value) lo = mid + 1;
|
|
743
|
+
else hi = mid;
|
|
744
|
+
}
|
|
745
|
+
return lo;
|
|
746
|
+
}
|
|
747
|
+
function runsOrPlain(pairs, runs, card, copy) {
|
|
748
|
+
const plain = card <= ARRAY_MAX_CARDINALITY ? 2 * card : BITSET_BYTES;
|
|
749
|
+
if (2 + 4 * runs < plain) {
|
|
750
|
+
return runContainer(copy ? pairs.slice(0, 2 * runs) : pairs, runs, card);
|
|
751
|
+
}
|
|
752
|
+
return fromRunPairs(pairs, runs, card);
|
|
753
|
+
}
|
|
754
|
+
function addToRuns(c, low) {
|
|
755
|
+
const u16 = lows16(c);
|
|
756
|
+
const next = runsAfter(u16, c.off, 0, c.len, low);
|
|
757
|
+
const prev = next - 1;
|
|
758
|
+
const joinPrev = prev >= 0 && u16[c.off + 2 * prev] + u16[c.off + 2 * prev + 1] + 1 === low;
|
|
759
|
+
const joinNext = next < c.len && u16[c.off + 2 * next] === low + 1;
|
|
760
|
+
const runs = c.len + 1 - (joinPrev ? 1 : 0) - (joinNext ? 1 : 0);
|
|
761
|
+
const out = new Uint16Array(2 * runs);
|
|
762
|
+
const head = joinPrev ? prev : next;
|
|
763
|
+
out.set(u16.subarray(c.off, c.off + 2 * head));
|
|
764
|
+
let at = 2 * head;
|
|
765
|
+
if (joinPrev && joinNext) {
|
|
766
|
+
out[at++] = u16[c.off + 2 * prev];
|
|
767
|
+
out[at++] = u16[c.off + 2 * next] + u16[c.off + 2 * next + 1] - u16[c.off + 2 * prev];
|
|
768
|
+
} else if (joinPrev) {
|
|
769
|
+
out[at++] = u16[c.off + 2 * prev];
|
|
770
|
+
out[at++] = u16[c.off + 2 * prev + 1] + 1;
|
|
771
|
+
} else if (joinNext) {
|
|
772
|
+
out[at++] = low;
|
|
773
|
+
out[at++] = u16[c.off + 2 * next + 1] + 1;
|
|
774
|
+
} else {
|
|
775
|
+
out[at++] = low;
|
|
776
|
+
out[at++] = 0;
|
|
777
|
+
}
|
|
778
|
+
const rest = joinNext ? next + 1 : next;
|
|
779
|
+
out.set(u16.subarray(c.off + 2 * rest, c.off + 2 * c.len), at);
|
|
780
|
+
return runsOrPlain(out, runs, c.card + 1, false);
|
|
781
|
+
}
|
|
638
782
|
function containerAdd(c, low) {
|
|
639
783
|
if (containerHas(c, low)) return c;
|
|
640
|
-
|
|
641
|
-
if (
|
|
642
|
-
const words = writableWords(
|
|
784
|
+
if (c.kind === RUN2) return addToRuns(c, low);
|
|
785
|
+
if (c.kind === BITSET) {
|
|
786
|
+
const words = writableWords(c);
|
|
643
787
|
words[low >>> 5] = words[low >>> 5] | 1 << (low & 31);
|
|
644
|
-
return bitsetContainer(words,
|
|
788
|
+
return bitsetContainer(words, c.card + 1);
|
|
645
789
|
}
|
|
646
|
-
if (
|
|
647
|
-
const words = toWords(
|
|
790
|
+
if (c.card === ARRAY_MAX_CARDINALITY) {
|
|
791
|
+
const words = toWords(c);
|
|
648
792
|
words[low >>> 5] = words[low >>> 5] | 1 << (low & 31);
|
|
649
|
-
return bitsetContainer(words,
|
|
793
|
+
return bitsetContainer(words, c.card + 1);
|
|
650
794
|
}
|
|
651
|
-
const old = lows16(
|
|
652
|
-
const at = lowerBound(old,
|
|
795
|
+
const old = lows16(c);
|
|
796
|
+
const at = lowerBound(old, c.off, c.len, low, 1);
|
|
653
797
|
let u16 = old;
|
|
654
|
-
if (!
|
|
655
|
-
u16.copyWithin(at + 1, at,
|
|
798
|
+
if (!c.shared && c.off === 0 && old.length > c.len) {
|
|
799
|
+
u16.copyWithin(at + 1, at, c.len);
|
|
656
800
|
} else {
|
|
657
|
-
u16 = new Uint16Array(Math.min(ARRAY_MAX_CARDINALITY, Math.max(8,
|
|
658
|
-
u16.set(old.subarray(
|
|
659
|
-
u16.set(old.subarray(
|
|
801
|
+
u16 = new Uint16Array(Math.min(ARRAY_MAX_CARDINALITY, Math.max(8, c.len * 2)));
|
|
802
|
+
u16.set(old.subarray(c.off, c.off + at));
|
|
803
|
+
u16.set(old.subarray(c.off + at, c.off + c.len), at + 1);
|
|
660
804
|
}
|
|
661
805
|
u16[at] = low;
|
|
662
|
-
return arrayContainer(u16,
|
|
806
|
+
return arrayContainer(u16, c.card + 1);
|
|
807
|
+
}
|
|
808
|
+
function addFewToRuns(c, ids, from, to) {
|
|
809
|
+
const x = lows16(c);
|
|
810
|
+
let data = x;
|
|
811
|
+
let base = c.off;
|
|
812
|
+
let out = null;
|
|
813
|
+
let n = c.len;
|
|
814
|
+
let added = 0;
|
|
815
|
+
for (let k = from; k < to; k++) {
|
|
816
|
+
const low = ids[k] & 65535;
|
|
817
|
+
const next = runsAfter(data, base, 0, n, low);
|
|
818
|
+
const prev = next - 1;
|
|
819
|
+
const prevEnd = prev >= 0 ? data[base + 2 * prev] + data[base + 2 * prev + 1] : -2;
|
|
820
|
+
if (prevEnd >= low) continue;
|
|
821
|
+
if (out === null) {
|
|
822
|
+
out = new Uint16Array(2 * (c.len + to - from));
|
|
823
|
+
out.set(x.subarray(c.off, c.off + 2 * c.len));
|
|
824
|
+
data = out;
|
|
825
|
+
base = 0;
|
|
826
|
+
}
|
|
827
|
+
const joinPrev = prevEnd + 1 === low;
|
|
828
|
+
const joinNext = next < n && out[2 * next] === low + 1;
|
|
829
|
+
if (joinPrev && joinNext) {
|
|
830
|
+
out[2 * prev + 1] = out[2 * next] + out[2 * next + 1] - out[2 * prev];
|
|
831
|
+
out.copyWithin(2 * next, 2 * next + 2, 2 * n);
|
|
832
|
+
n--;
|
|
833
|
+
} else if (joinPrev) {
|
|
834
|
+
out[2 * prev + 1] = out[2 * prev + 1] + 1;
|
|
835
|
+
} else if (joinNext) {
|
|
836
|
+
out[2 * next] = low;
|
|
837
|
+
out[2 * next + 1] = out[2 * next + 1] + 1;
|
|
838
|
+
} else {
|
|
839
|
+
out.copyWithin(2 * next + 2, 2 * next, 2 * n);
|
|
840
|
+
out[2 * next] = low;
|
|
841
|
+
out[2 * next + 1] = 0;
|
|
842
|
+
n++;
|
|
843
|
+
}
|
|
844
|
+
added++;
|
|
845
|
+
}
|
|
846
|
+
if (out === null) return c;
|
|
847
|
+
return runsOrPlain(out, n, c.card + added, true);
|
|
848
|
+
}
|
|
849
|
+
function containerAddSorted(c, ids, from, to) {
|
|
850
|
+
if (c.kind === RUN2) return addFewToRuns(c, ids, from, to);
|
|
851
|
+
let cur = c;
|
|
852
|
+
for (let k = from; k < to; k++) cur = containerAdd(cur, ids[k] & 65535);
|
|
853
|
+
return cur;
|
|
663
854
|
}
|
|
664
855
|
function containerRemove(c, low) {
|
|
665
856
|
if (!containerHas(c, low)) return c;
|
|
@@ -681,6 +872,15 @@ function containerRemove(c, low) {
|
|
|
681
872
|
u16.set(old.subarray(plain.off + at + 1, plain.off + plain.len), at);
|
|
682
873
|
return arrayContainer(u16, plain.card - 1);
|
|
683
874
|
}
|
|
875
|
+
function containerMin(c) {
|
|
876
|
+
if (c.kind === ARRAY2 || c.kind === RUN2) return c.data[c.off];
|
|
877
|
+
const words = words32(c);
|
|
878
|
+
for (let i = 0; i < WORDS; i++) {
|
|
879
|
+
const w = words[i];
|
|
880
|
+
if (w !== 0) return i * 32 + 31 - Math.clz32(w & -w);
|
|
881
|
+
}
|
|
882
|
+
throw new RangeError("a bitset container holds no bits");
|
|
883
|
+
}
|
|
684
884
|
function containerMax(c) {
|
|
685
885
|
if (c.kind === ARRAY2) return c.data[c.off + c.len - 1];
|
|
686
886
|
if (c.kind === RUN2) {
|
|
@@ -775,6 +975,7 @@ function skewed(shorter, longer) {
|
|
|
775
975
|
return longer >= GALLOP_SKEW * shorter;
|
|
776
976
|
}
|
|
777
977
|
var PROBE_MIN = 32;
|
|
978
|
+
var MERGE_FIRST = 64;
|
|
778
979
|
var probeWords = new Uint32Array(WORDS);
|
|
779
980
|
function andArrays(a, b) {
|
|
780
981
|
const small = a.len <= b.len ? a : b;
|
|
@@ -949,6 +1150,70 @@ function orArrays(a, b) {
|
|
|
949
1150
|
while (j < je) out[n++] = y[j++];
|
|
950
1151
|
return arrayOfScratch(out, n);
|
|
951
1152
|
}
|
|
1153
|
+
function andWords(out, x, y) {
|
|
1154
|
+
for (let i = 0; i < WORDS; i += 4) {
|
|
1155
|
+
const X0 = x[i];
|
|
1156
|
+
const Y0 = y[i];
|
|
1157
|
+
const X1 = x[i + 1];
|
|
1158
|
+
const Y1 = y[i + 1];
|
|
1159
|
+
const X2 = x[i + 2];
|
|
1160
|
+
const Y2 = y[i + 2];
|
|
1161
|
+
const X3 = x[i + 3];
|
|
1162
|
+
const Y3 = y[i + 3];
|
|
1163
|
+
out[i] = X0 & Y0;
|
|
1164
|
+
out[i + 1] = X1 & Y1;
|
|
1165
|
+
out[i + 2] = X2 & Y2;
|
|
1166
|
+
out[i + 3] = X3 & Y3;
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
function orWords(out, x, y) {
|
|
1170
|
+
for (let i = 0; i < WORDS; i += 4) {
|
|
1171
|
+
const X0 = x[i];
|
|
1172
|
+
const Y0 = y[i];
|
|
1173
|
+
const X1 = x[i + 1];
|
|
1174
|
+
const Y1 = y[i + 1];
|
|
1175
|
+
const X2 = x[i + 2];
|
|
1176
|
+
const Y2 = y[i + 2];
|
|
1177
|
+
const X3 = x[i + 3];
|
|
1178
|
+
const Y3 = y[i + 3];
|
|
1179
|
+
out[i] = X0 | Y0;
|
|
1180
|
+
out[i + 1] = X1 | Y1;
|
|
1181
|
+
out[i + 2] = X2 | Y2;
|
|
1182
|
+
out[i + 3] = X3 | Y3;
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
function xorWords(out, x, y) {
|
|
1186
|
+
for (let i = 0; i < WORDS; i += 4) {
|
|
1187
|
+
const X0 = x[i];
|
|
1188
|
+
const Y0 = y[i];
|
|
1189
|
+
const X1 = x[i + 1];
|
|
1190
|
+
const Y1 = y[i + 1];
|
|
1191
|
+
const X2 = x[i + 2];
|
|
1192
|
+
const Y2 = y[i + 2];
|
|
1193
|
+
const X3 = x[i + 3];
|
|
1194
|
+
const Y3 = y[i + 3];
|
|
1195
|
+
out[i] = X0 ^ Y0;
|
|
1196
|
+
out[i + 1] = X1 ^ Y1;
|
|
1197
|
+
out[i + 2] = X2 ^ Y2;
|
|
1198
|
+
out[i + 3] = X3 ^ Y3;
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
function andNotWords(out, x, y) {
|
|
1202
|
+
for (let i = 0; i < WORDS; i += 4) {
|
|
1203
|
+
const X0 = x[i];
|
|
1204
|
+
const Y0 = y[i];
|
|
1205
|
+
const X1 = x[i + 1];
|
|
1206
|
+
const Y1 = y[i + 1];
|
|
1207
|
+
const X2 = x[i + 2];
|
|
1208
|
+
const Y2 = y[i + 2];
|
|
1209
|
+
const X3 = x[i + 3];
|
|
1210
|
+
const Y3 = y[i + 3];
|
|
1211
|
+
out[i] = X0 & ~Y0;
|
|
1212
|
+
out[i + 1] = X1 & ~Y1;
|
|
1213
|
+
out[i + 2] = X2 & ~Y2;
|
|
1214
|
+
out[i + 3] = X3 & ~Y3;
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
952
1217
|
function orIntoBitset(dest, other, inPlace) {
|
|
953
1218
|
const words = inPlace ? words32(dest) : words32(dest).slice();
|
|
954
1219
|
if (other.kind === ARRAY2) {
|
|
@@ -966,8 +1231,7 @@ function orIntoBitset(dest, other, inPlace) {
|
|
|
966
1231
|
return bitsetContainer(words, card);
|
|
967
1232
|
}
|
|
968
1233
|
if (other.kind === BITSET) {
|
|
969
|
-
|
|
970
|
-
for (let i = 0; i < WORDS; i++) words[i] = words[i] | o[i];
|
|
1234
|
+
orWords(words, words, words32(other));
|
|
971
1235
|
} else {
|
|
972
1236
|
const pairs = lows16(other);
|
|
973
1237
|
for (let r = 0; r < other.len; r++) {
|
|
@@ -977,6 +1241,81 @@ function orIntoBitset(dest, other, inPlace) {
|
|
|
977
1241
|
}
|
|
978
1242
|
return bitsetContainer(words, popcountWords(words));
|
|
979
1243
|
}
|
|
1244
|
+
function orBitsetWords(list) {
|
|
1245
|
+
const bits = [];
|
|
1246
|
+
for (const c of list) if (c.kind === BITSET) bits.push(words32(c));
|
|
1247
|
+
const n = bits.length;
|
|
1248
|
+
if (n === 0) return new Uint32Array(WORDS);
|
|
1249
|
+
let k;
|
|
1250
|
+
let words;
|
|
1251
|
+
if (n >= 4) {
|
|
1252
|
+
const a = bits[0];
|
|
1253
|
+
const b = bits[1];
|
|
1254
|
+
const c = bits[2];
|
|
1255
|
+
const d = bits[3];
|
|
1256
|
+
words = new Uint32Array(WORDS);
|
|
1257
|
+
for (let i = 0; i < WORDS; i++)
|
|
1258
|
+
words[i] = a[i] | b[i] | c[i] | d[i];
|
|
1259
|
+
k = 4;
|
|
1260
|
+
} else {
|
|
1261
|
+
words = bits[0].slice();
|
|
1262
|
+
k = 1;
|
|
1263
|
+
}
|
|
1264
|
+
for (; k + 4 <= n; k += 4) {
|
|
1265
|
+
const a = bits[k];
|
|
1266
|
+
const b = bits[k + 1];
|
|
1267
|
+
const c = bits[k + 2];
|
|
1268
|
+
const d = bits[k + 3];
|
|
1269
|
+
for (let i = 0; i < WORDS; i++) {
|
|
1270
|
+
words[i] = words[i] | a[i] | b[i] | c[i] | d[i];
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
for (; k < n; k++) {
|
|
1274
|
+
const o = bits[k];
|
|
1275
|
+
for (let i = 0; i < WORDS; i++) words[i] = words[i] | o[i];
|
|
1276
|
+
}
|
|
1277
|
+
return words;
|
|
1278
|
+
}
|
|
1279
|
+
function orManyContainers(list) {
|
|
1280
|
+
let total = 0;
|
|
1281
|
+
let allArrays = true;
|
|
1282
|
+
for (const c of list) {
|
|
1283
|
+
total += c.card;
|
|
1284
|
+
if (c.kind !== ARRAY2) allArrays = false;
|
|
1285
|
+
}
|
|
1286
|
+
if (allArrays && total <= ARRAY_MAX_CARDINALITY) {
|
|
1287
|
+
const out = values16(total);
|
|
1288
|
+
let n = 0;
|
|
1289
|
+
for (const c of list) {
|
|
1290
|
+
out.set(lows16(c).subarray(c.off, c.off + c.len), n);
|
|
1291
|
+
n += c.len;
|
|
1292
|
+
}
|
|
1293
|
+
const sorted = out.subarray(0, n).sort();
|
|
1294
|
+
let distinct = 0;
|
|
1295
|
+
for (let i = 0; i < n; i++) {
|
|
1296
|
+
const v = sorted[i];
|
|
1297
|
+
if (i === 0 || v !== sorted[distinct - 1]) sorted[distinct++] = v;
|
|
1298
|
+
}
|
|
1299
|
+
return arrayContainer(sorted.slice(0, distinct), distinct);
|
|
1300
|
+
}
|
|
1301
|
+
const words = orBitsetWords(list);
|
|
1302
|
+
for (const c of list) {
|
|
1303
|
+
if (c.kind === ARRAY2) {
|
|
1304
|
+
const u16 = lows16(c);
|
|
1305
|
+
for (let i = c.off; i < c.off + c.len; i++) {
|
|
1306
|
+
const v = u16[i];
|
|
1307
|
+
words[v >>> 5] = words[v >>> 5] | 1 << (v & 31);
|
|
1308
|
+
}
|
|
1309
|
+
} else if (c.kind === RUN2) {
|
|
1310
|
+
const pairs = lows16(c);
|
|
1311
|
+
for (let r = 0; r < c.len; r++) {
|
|
1312
|
+
const start = pairs[c.off + 2 * r];
|
|
1313
|
+
setRange(words, start, start + pairs[c.off + 2 * r + 1]);
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
return fromWordsCard(words, popcountWords(words));
|
|
1318
|
+
}
|
|
980
1319
|
function fromRunPairs(pairs, runs, card) {
|
|
981
1320
|
if (card === 0) return null;
|
|
982
1321
|
if (card <= ARRAY_MAX_CARDINALITY) {
|
|
@@ -1020,7 +1359,7 @@ function andRuns(a, b) {
|
|
|
1020
1359
|
if (ae < be) i++;
|
|
1021
1360
|
else j++;
|
|
1022
1361
|
}
|
|
1023
|
-
return
|
|
1362
|
+
return card === 0 ? null : runsOrPlain(out, runs, card, true);
|
|
1024
1363
|
}
|
|
1025
1364
|
function orRuns(a, b) {
|
|
1026
1365
|
const x = lows16(a);
|
|
@@ -1060,7 +1399,7 @@ function orRuns(a, b) {
|
|
|
1060
1399
|
}
|
|
1061
1400
|
}
|
|
1062
1401
|
flush();
|
|
1063
|
-
return
|
|
1402
|
+
return runsOrPlain(out, runs, card, true);
|
|
1064
1403
|
}
|
|
1065
1404
|
function andNotRuns(a, b) {
|
|
1066
1405
|
const x = lows16(a);
|
|
@@ -1094,7 +1433,7 @@ function andNotRuns(a, b) {
|
|
|
1094
1433
|
k++;
|
|
1095
1434
|
}
|
|
1096
1435
|
}
|
|
1097
|
-
return
|
|
1436
|
+
return card === 0 ? null : runsOrPlain(out, runs, card, true);
|
|
1098
1437
|
}
|
|
1099
1438
|
function bitsetInRuns(a, b) {
|
|
1100
1439
|
const words = words32(a);
|
|
@@ -1146,7 +1485,7 @@ function containerAnd(a, b, inPlace = false) {
|
|
|
1146
1485
|
const x = words32(a);
|
|
1147
1486
|
const y = words32(b);
|
|
1148
1487
|
const out = inPlace ? x : new Uint32Array(WORDS);
|
|
1149
|
-
|
|
1488
|
+
andWords(out, x, y);
|
|
1150
1489
|
return fromWordsCard(out, popcountWords(out));
|
|
1151
1490
|
}
|
|
1152
1491
|
if (a.kind > b.kind) return containerAnd(b, a);
|
|
@@ -1161,16 +1500,162 @@ function containerOr(a, b, inPlace = false) {
|
|
|
1161
1500
|
if (b.kind === BITSET) return orIntoBitset(b, a, false);
|
|
1162
1501
|
if (a.kind === ARRAY2 && b.kind === ARRAY2) return orArrays(a, b);
|
|
1163
1502
|
if (a.kind === RUN2 && b.kind === RUN2) return orRuns(a, b);
|
|
1164
|
-
|
|
1165
|
-
return orIntoBitsetWords(words, a.kind === RUN2 ? b : a);
|
|
1503
|
+
return a.kind === RUN2 ? orRunArray(a, b, inPlace) : orRunArray(b, a, false);
|
|
1166
1504
|
}
|
|
1167
|
-
|
|
1168
|
-
|
|
1505
|
+
var EXPAND_MIN_STEPS = 1024;
|
|
1506
|
+
function expandsRunArray(runs, array) {
|
|
1507
|
+
return expandsRunSteps(runs, array.len);
|
|
1508
|
+
}
|
|
1509
|
+
function expandsRunSteps(runs, values) {
|
|
1510
|
+
const steps = runs.len + values;
|
|
1511
|
+
if (steps < EXPAND_MIN_STEPS) return false;
|
|
1512
|
+
const cardMax = runs.card + values;
|
|
1513
|
+
const plainMax = cardMax <= ARRAY_MAX_CARDINALITY ? 2 * cardMax : BITSET_BYTES;
|
|
1514
|
+
return 2 + 4 * steps >= plainMax;
|
|
1515
|
+
}
|
|
1516
|
+
function walksRunIds(runs, count) {
|
|
1517
|
+
return runs.kind === RUN2 && !expandsRunSteps(runs, count);
|
|
1518
|
+
}
|
|
1519
|
+
function orRunArrayExpand(runs, array, keep) {
|
|
1520
|
+
const words = toWords(runs);
|
|
1521
|
+
const v = lows16(array);
|
|
1522
|
+
let added = 0;
|
|
1169
1523
|
for (let i = array.off; i < array.off + array.len; i++) {
|
|
1170
|
-
const
|
|
1171
|
-
|
|
1524
|
+
const value = v[i];
|
|
1525
|
+
const word = words[value >>> 5];
|
|
1526
|
+
const bit = 1 << (value & 31);
|
|
1527
|
+
if ((word & bit) === 0) {
|
|
1528
|
+
words[value >>> 5] = word | bit;
|
|
1529
|
+
added++;
|
|
1530
|
+
}
|
|
1172
1531
|
}
|
|
1173
|
-
|
|
1532
|
+
if (added === 0 && keep) return runs;
|
|
1533
|
+
return optimize(fromWordsCard(words, runs.card + added));
|
|
1534
|
+
}
|
|
1535
|
+
function orRunArray(runs, array, keep) {
|
|
1536
|
+
return expandsRunArray(runs, array) ? orRunArrayExpand(runs, array, keep) : orRunArrayWalk(runs, array, keep);
|
|
1537
|
+
}
|
|
1538
|
+
function orRunArrayWalk(runs, array, keep) {
|
|
1539
|
+
const x = lows16(runs);
|
|
1540
|
+
const v = lows16(array);
|
|
1541
|
+
const out = pairs16(2 * (runs.len + array.len));
|
|
1542
|
+
const runEnd = runs.off + 2 * runs.len;
|
|
1543
|
+
const valueEnd = array.off + array.len;
|
|
1544
|
+
let r = runs.off;
|
|
1545
|
+
let vi = array.off;
|
|
1546
|
+
let at = 0;
|
|
1547
|
+
let from = 0;
|
|
1548
|
+
let to = -2;
|
|
1549
|
+
let added = 0;
|
|
1550
|
+
while (vi < valueEnd) {
|
|
1551
|
+
const value = v[vi++];
|
|
1552
|
+
while (r < runEnd && x[r] <= value) {
|
|
1553
|
+
const start = x[r];
|
|
1554
|
+
const end = start + x[r + 1];
|
|
1555
|
+
r += 2;
|
|
1556
|
+
if (start <= to + 1) {
|
|
1557
|
+
if (end > to) to = end;
|
|
1558
|
+
} else {
|
|
1559
|
+
if (to >= 0) {
|
|
1560
|
+
out[at++] = from;
|
|
1561
|
+
out[at++] = to - from;
|
|
1562
|
+
}
|
|
1563
|
+
from = start;
|
|
1564
|
+
to = end;
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1567
|
+
if (value <= to) continue;
|
|
1568
|
+
added++;
|
|
1569
|
+
if (value === to + 1) {
|
|
1570
|
+
to = value;
|
|
1571
|
+
} else {
|
|
1572
|
+
if (to >= 0) {
|
|
1573
|
+
out[at++] = from;
|
|
1574
|
+
out[at++] = to - from;
|
|
1575
|
+
}
|
|
1576
|
+
from = value;
|
|
1577
|
+
to = value;
|
|
1578
|
+
}
|
|
1579
|
+
}
|
|
1580
|
+
while (r < runEnd) {
|
|
1581
|
+
const start = x[r];
|
|
1582
|
+
const end = start + x[r + 1];
|
|
1583
|
+
r += 2;
|
|
1584
|
+
if (start <= to + 1) {
|
|
1585
|
+
if (end > to) to = end;
|
|
1586
|
+
} else {
|
|
1587
|
+
if (to >= 0) {
|
|
1588
|
+
out[at++] = from;
|
|
1589
|
+
out[at++] = to - from;
|
|
1590
|
+
}
|
|
1591
|
+
from = start;
|
|
1592
|
+
to = end;
|
|
1593
|
+
}
|
|
1594
|
+
}
|
|
1595
|
+
out[at++] = from;
|
|
1596
|
+
out[at++] = to - from;
|
|
1597
|
+
if (added === 0 && keep) return runs;
|
|
1598
|
+
return runsOrPlain(out, at >>> 1, runs.card + added, true);
|
|
1599
|
+
}
|
|
1600
|
+
function orRunIdsWalk(runs, ids, from, to) {
|
|
1601
|
+
const x = lows16(runs);
|
|
1602
|
+
const out = pairs16(2 * (runs.len + to - from));
|
|
1603
|
+
const runEnd = runs.off + 2 * runs.len;
|
|
1604
|
+
let r = runs.off;
|
|
1605
|
+
let vi = from;
|
|
1606
|
+
let at = 0;
|
|
1607
|
+
let start = 0;
|
|
1608
|
+
let last = -2;
|
|
1609
|
+
let added = 0;
|
|
1610
|
+
while (vi < to) {
|
|
1611
|
+
const value = ids[vi++] & 65535;
|
|
1612
|
+
while (r < runEnd && x[r] <= value) {
|
|
1613
|
+
const s = x[r];
|
|
1614
|
+
const end = s + x[r + 1];
|
|
1615
|
+
r += 2;
|
|
1616
|
+
if (s <= last + 1) {
|
|
1617
|
+
if (end > last) last = end;
|
|
1618
|
+
} else {
|
|
1619
|
+
if (last >= 0) {
|
|
1620
|
+
out[at++] = start;
|
|
1621
|
+
out[at++] = last - start;
|
|
1622
|
+
}
|
|
1623
|
+
start = s;
|
|
1624
|
+
last = end;
|
|
1625
|
+
}
|
|
1626
|
+
}
|
|
1627
|
+
if (value <= last) continue;
|
|
1628
|
+
added++;
|
|
1629
|
+
if (value === last + 1) {
|
|
1630
|
+
last = value;
|
|
1631
|
+
} else {
|
|
1632
|
+
if (last >= 0) {
|
|
1633
|
+
out[at++] = start;
|
|
1634
|
+
out[at++] = last - start;
|
|
1635
|
+
}
|
|
1636
|
+
start = value;
|
|
1637
|
+
last = value;
|
|
1638
|
+
}
|
|
1639
|
+
}
|
|
1640
|
+
while (r < runEnd) {
|
|
1641
|
+
const s = x[r];
|
|
1642
|
+
const end = s + x[r + 1];
|
|
1643
|
+
r += 2;
|
|
1644
|
+
if (s <= last + 1) {
|
|
1645
|
+
if (end > last) last = end;
|
|
1646
|
+
} else {
|
|
1647
|
+
if (last >= 0) {
|
|
1648
|
+
out[at++] = start;
|
|
1649
|
+
out[at++] = last - start;
|
|
1650
|
+
}
|
|
1651
|
+
start = s;
|
|
1652
|
+
last = end;
|
|
1653
|
+
}
|
|
1654
|
+
}
|
|
1655
|
+
out[at++] = start;
|
|
1656
|
+
out[at++] = last - start;
|
|
1657
|
+
if (added === 0) return runs;
|
|
1658
|
+
return runsOrPlain(out, at >>> 1, runs.card + added, true);
|
|
1174
1659
|
}
|
|
1175
1660
|
function containerAndNot(a, b, inPlace = false) {
|
|
1176
1661
|
if (a.kind === ARRAY2) {
|
|
@@ -1186,8 +1671,7 @@ function containerAndNot(a, b, inPlace = false) {
|
|
|
1186
1671
|
words[v >>> 5] = words[v >>> 5] & ~(1 << (v & 31));
|
|
1187
1672
|
}
|
|
1188
1673
|
} else if (b.kind === BITSET) {
|
|
1189
|
-
|
|
1190
|
-
for (let i = 0; i < WORDS; i++) words[i] = words[i] & ~y[i];
|
|
1674
|
+
andNotWords(words, words, words32(b));
|
|
1191
1675
|
} else {
|
|
1192
1676
|
const pairs = lows16(b);
|
|
1193
1677
|
for (let r = 0; r < b.len; r++) {
|
|
@@ -1197,38 +1681,583 @@ function containerAndNot(a, b, inPlace = false) {
|
|
|
1197
1681
|
}
|
|
1198
1682
|
return fromWordsCard(words, popcountWords(words));
|
|
1199
1683
|
}
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1684
|
+
function xorArrays(a, b) {
|
|
1685
|
+
const x = lows16(a);
|
|
1686
|
+
const y = lows16(b);
|
|
1687
|
+
const ie = a.off + a.len;
|
|
1688
|
+
const je = b.off + b.len;
|
|
1689
|
+
const out = values16(a.len + b.len);
|
|
1690
|
+
let n = 0;
|
|
1691
|
+
let i = a.off;
|
|
1692
|
+
let j = b.off;
|
|
1693
|
+
while (i < ie && j < je) {
|
|
1694
|
+
const p = x[i];
|
|
1695
|
+
const q = y[j];
|
|
1696
|
+
out[n] = p < q ? p : q;
|
|
1697
|
+
n += p === q ? 0 : 1;
|
|
1698
|
+
i += p <= q ? 1 : 0;
|
|
1699
|
+
j += p >= q ? 1 : 0;
|
|
1700
|
+
}
|
|
1701
|
+
while (i < ie) out[n++] = x[i++];
|
|
1702
|
+
while (j < je) out[n++] = y[j++];
|
|
1703
|
+
if (n <= ARRAY_MAX_CARDINALITY) return arrayOfScratch(out, n);
|
|
1704
|
+
const words = new Uint32Array(WORDS);
|
|
1705
|
+
for (let k = 0; k < n; k++) {
|
|
1706
|
+
const v = out[k];
|
|
1707
|
+
words[v >>> 5] = words[v >>> 5] | 1 << (v & 31);
|
|
1708
|
+
}
|
|
1709
|
+
return bitsetContainer(words, n);
|
|
1710
|
+
}
|
|
1711
|
+
function xorRuns(a, b) {
|
|
1712
|
+
const x = lows16(a);
|
|
1713
|
+
const y = lows16(b);
|
|
1714
|
+
const na = 2 * a.len;
|
|
1715
|
+
const nb = 2 * b.len;
|
|
1716
|
+
const out = pairs16(2 * (a.len + b.len));
|
|
1717
|
+
const NONE = 2147483647;
|
|
1718
|
+
let i = 0;
|
|
1719
|
+
let j = 0;
|
|
1720
|
+
let pa = na > 0 ? boundary(x, a.off, 0) : NONE;
|
|
1721
|
+
let pb = nb > 0 ? boundary(y, b.off, 0) : NONE;
|
|
1722
|
+
let open = -1;
|
|
1723
|
+
let runs = 0;
|
|
1724
|
+
let card = 0;
|
|
1725
|
+
while (i < na || j < nb) {
|
|
1726
|
+
let p;
|
|
1727
|
+
if (pa === pb) {
|
|
1728
|
+
i++;
|
|
1729
|
+
j++;
|
|
1730
|
+
pa = i < na ? boundary(x, a.off, i) : NONE;
|
|
1731
|
+
pb = j < nb ? boundary(y, b.off, j) : NONE;
|
|
1732
|
+
continue;
|
|
1733
|
+
}
|
|
1734
|
+
if (pa < pb) {
|
|
1735
|
+
p = pa;
|
|
1736
|
+
i++;
|
|
1737
|
+
pa = i < na ? boundary(x, a.off, i) : NONE;
|
|
1738
|
+
} else {
|
|
1739
|
+
p = pb;
|
|
1740
|
+
j++;
|
|
1741
|
+
pb = j < nb ? boundary(y, b.off, j) : NONE;
|
|
1742
|
+
}
|
|
1743
|
+
if (open < 0) {
|
|
1744
|
+
open = p;
|
|
1745
|
+
} else {
|
|
1746
|
+
out[2 * runs] = open;
|
|
1747
|
+
out[2 * runs + 1] = p - 1 - open;
|
|
1748
|
+
runs++;
|
|
1749
|
+
card += p - open;
|
|
1750
|
+
open = -1;
|
|
1751
|
+
}
|
|
1752
|
+
}
|
|
1753
|
+
return card === 0 ? null : runsOrPlain(out, runs, card, true);
|
|
1754
|
+
}
|
|
1755
|
+
function boundary(u16, off, k) {
|
|
1756
|
+
const at = off + (k & ~1);
|
|
1757
|
+
return u16[at] + ((k & 1) === 0 ? 0 : u16[at + 1] + 1);
|
|
1758
|
+
}
|
|
1759
|
+
function containerXor(a, b, inPlace = false) {
|
|
1760
|
+
if (a.kind === BITSET || b.kind === BITSET) {
|
|
1761
|
+
const base = a.kind === BITSET ? a : b;
|
|
1762
|
+
const other = base === a ? b : a;
|
|
1763
|
+
if (other.kind === BITSET) {
|
|
1764
|
+
const x = words32(a);
|
|
1765
|
+
const y = words32(b);
|
|
1766
|
+
const out = inPlace ? x : new Uint32Array(WORDS);
|
|
1767
|
+
xorWords(out, x, y);
|
|
1768
|
+
return fromWordsCard(out, popcountWords(out));
|
|
1769
|
+
}
|
|
1770
|
+
const words2 = inPlace && base === a ? words32(base) : words32(base).slice();
|
|
1771
|
+
if (other.kind === ARRAY2) {
|
|
1772
|
+
return fromWordsCard(words2, flipValues(words2, other, base.card));
|
|
1773
|
+
}
|
|
1774
|
+
const pairs = lows16(other);
|
|
1775
|
+
for (let r = 0; r < other.len; r++) {
|
|
1776
|
+
const start = pairs[other.off + 2 * r];
|
|
1777
|
+
flipRange(words2, start, start + pairs[other.off + 2 * r + 1]);
|
|
1778
|
+
}
|
|
1779
|
+
return fromWordsCard(words2, popcountWords(words2));
|
|
1780
|
+
}
|
|
1781
|
+
if (a.kind === ARRAY2 && b.kind === ARRAY2) return xorArrays(a, b);
|
|
1782
|
+
if (a.kind === RUN2 && b.kind === RUN2) return xorRuns(a, b);
|
|
1783
|
+
const runs = a.kind === RUN2 ? a : b;
|
|
1784
|
+
const array = runs === a ? b : a;
|
|
1785
|
+
const words = toWords(runs);
|
|
1786
|
+
return fromWordsCard(words, flipValues(words, array, runs.card));
|
|
1787
|
+
}
|
|
1788
|
+
function flipValues(words, array, card) {
|
|
1789
|
+
const u16 = lows16(array);
|
|
1790
|
+
let n = card;
|
|
1791
|
+
for (let i = array.off; i < array.off + array.len; i++) {
|
|
1792
|
+
const v = u16[i];
|
|
1793
|
+
const w = words[v >>> 5];
|
|
1794
|
+
words[v >>> 5] = w ^ 1 << (v & 31);
|
|
1795
|
+
n += 1 - 2 * (w >>> (v & 31) & 1);
|
|
1796
|
+
}
|
|
1797
|
+
return n;
|
|
1798
|
+
}
|
|
1799
|
+
function bitsInRange(words, start, end) {
|
|
1800
|
+
const first = start >>> 5;
|
|
1801
|
+
const last = end >>> 5;
|
|
1802
|
+
const head = 4294967295 << (start & 31) >>> 0;
|
|
1803
|
+
const tail = 4294967295 >>> 31 - (end & 31);
|
|
1804
|
+
if (first === last) return popcount32(words[first] & head & tail);
|
|
1805
|
+
let n = popcount32(words[first] & head) + popcount32(words[last] & tail);
|
|
1806
|
+
for (let i = first + 1; i < last; i++) n += popcount32(words[i]);
|
|
1807
|
+
return n;
|
|
1808
|
+
}
|
|
1809
|
+
function andCountArrays(a, b) {
|
|
1810
|
+
const small = a.len <= b.len ? a : b;
|
|
1811
|
+
const big = small === a ? b : a;
|
|
1812
|
+
const s = lows16(small);
|
|
1813
|
+
const l = lows16(big);
|
|
1814
|
+
const se = small.off + small.len;
|
|
1815
|
+
const le = big.off + big.len;
|
|
1816
|
+
let n = 0;
|
|
1817
|
+
if (skewed(small.len, big.len)) {
|
|
1818
|
+
let at = big.off;
|
|
1819
|
+
for (let i2 = small.off; i2 < se; i2++) {
|
|
1820
|
+
const v = s[i2];
|
|
1821
|
+
at = gallop(l, 0, at, le, v);
|
|
1822
|
+
if (at === le) break;
|
|
1823
|
+
if (l[at] === v) n++;
|
|
1824
|
+
}
|
|
1825
|
+
return n;
|
|
1826
|
+
}
|
|
1827
|
+
if (small.len >= PROBE_MIN) {
|
|
1828
|
+
const first = s[small.off];
|
|
1829
|
+
const last = s[se - 1];
|
|
1830
|
+
if (last < l[big.off] || first > l[le - 1]) return 0;
|
|
1831
|
+
const from = gallop(l, 0, big.off, le, first);
|
|
1832
|
+
const to = gallop(l, 0, from, le, last + 1);
|
|
1833
|
+
const words = probeWords;
|
|
1834
|
+
for (let i2 = small.off; i2 < se; i2++) {
|
|
1835
|
+
const v = s[i2];
|
|
1836
|
+
words[v >>> 5] = words[v >>> 5] | 1 << (v & 31);
|
|
1837
|
+
}
|
|
1838
|
+
for (let j2 = from; j2 < to; j2++) {
|
|
1839
|
+
const v = l[j2];
|
|
1840
|
+
n += words[v >>> 5] >>> (v & 31) & 1;
|
|
1841
|
+
}
|
|
1842
|
+
for (let i2 = small.off; i2 < se; i2++) words[s[i2] >>> 5] = 0;
|
|
1843
|
+
return n;
|
|
1844
|
+
}
|
|
1845
|
+
let i = small.off;
|
|
1846
|
+
let j = big.off;
|
|
1847
|
+
while (i < se && j < le) {
|
|
1848
|
+
const x = s[i];
|
|
1849
|
+
const y = l[j];
|
|
1850
|
+
n += x === y ? 1 : 0;
|
|
1851
|
+
i += x <= y ? 1 : 0;
|
|
1852
|
+
j += x >= y ? 1 : 0;
|
|
1853
|
+
}
|
|
1854
|
+
return n;
|
|
1855
|
+
}
|
|
1856
|
+
function andCountArrayBitset(a, b) {
|
|
1857
|
+
const u16 = lows16(a);
|
|
1858
|
+
const words = words32(b);
|
|
1859
|
+
let n = 0;
|
|
1860
|
+
for (let i = a.off; i < a.off + a.len; i++) {
|
|
1861
|
+
const v = u16[i];
|
|
1862
|
+
n += words[v >>> 5] >>> (v & 31) & 1;
|
|
1863
|
+
}
|
|
1864
|
+
return n;
|
|
1865
|
+
}
|
|
1866
|
+
function andCountArrayRuns(a, b) {
|
|
1867
|
+
const u16 = lows16(a);
|
|
1868
|
+
const pairs = lows16(b);
|
|
1869
|
+
const ae = a.off + a.len;
|
|
1870
|
+
let n = 0;
|
|
1871
|
+
if (skewed(a.len, b.len)) {
|
|
1872
|
+
for (let i2 = a.off; i2 < ae; i2++) {
|
|
1873
|
+
const v = u16[i2];
|
|
1874
|
+
const after = lowerBound(pairs, b.off, b.len, v + 1, 2);
|
|
1875
|
+
if (after === 0) continue;
|
|
1876
|
+
const r = b.off + 2 * (after - 1);
|
|
1877
|
+
if (v <= pairs[r] + pairs[r + 1]) n++;
|
|
1878
|
+
}
|
|
1879
|
+
return n;
|
|
1880
|
+
}
|
|
1881
|
+
let i = a.off;
|
|
1882
|
+
for (let r = 0; r < b.len && i < ae; r++) {
|
|
1883
|
+
const start = pairs[b.off + 2 * r];
|
|
1884
|
+
const end = start + pairs[b.off + 2 * r + 1];
|
|
1885
|
+
while (i < ae && u16[i] < start) i++;
|
|
1886
|
+
while (i < ae && u16[i] <= end) {
|
|
1887
|
+
n++;
|
|
1888
|
+
i++;
|
|
1889
|
+
}
|
|
1890
|
+
}
|
|
1891
|
+
return n;
|
|
1892
|
+
}
|
|
1893
|
+
function andCountBitsetRuns(a, b) {
|
|
1894
|
+
const words = words32(a);
|
|
1895
|
+
const pairs = lows16(b);
|
|
1896
|
+
let n = 0;
|
|
1897
|
+
for (let r = 0; r < b.len; r++) {
|
|
1898
|
+
const start = pairs[b.off + 2 * r];
|
|
1899
|
+
n += bitsInRange(words, start, start + pairs[b.off + 2 * r + 1]);
|
|
1900
|
+
}
|
|
1901
|
+
return n;
|
|
1902
|
+
}
|
|
1903
|
+
function andCountRuns(a, b) {
|
|
1904
|
+
const x = lows16(a);
|
|
1905
|
+
const y = lows16(b);
|
|
1906
|
+
let n = 0;
|
|
1907
|
+
let i = 0;
|
|
1908
|
+
let j = 0;
|
|
1909
|
+
while (i < a.len && j < b.len) {
|
|
1910
|
+
const as = x[a.off + 2 * i];
|
|
1911
|
+
const ae = as + x[a.off + 2 * i + 1];
|
|
1912
|
+
const bs = y[b.off + 2 * j];
|
|
1913
|
+
const be = bs + y[b.off + 2 * j + 1];
|
|
1914
|
+
const lo = as > bs ? as : bs;
|
|
1915
|
+
const hi = ae < be ? ae : be;
|
|
1916
|
+
if (lo <= hi) n += hi - lo + 1;
|
|
1917
|
+
if (ae < be) i++;
|
|
1918
|
+
else j++;
|
|
1919
|
+
}
|
|
1920
|
+
return n;
|
|
1921
|
+
}
|
|
1922
|
+
function containerAndCard(a, b) {
|
|
1923
|
+
if (a.kind === BITSET && b.kind === BITSET) {
|
|
1924
|
+
return popcountAnd(words32(a), words32(b));
|
|
1925
|
+
}
|
|
1926
|
+
if (a.kind > b.kind) return containerAndCard(b, a);
|
|
1927
|
+
if (a.kind === ARRAY2) {
|
|
1928
|
+
if (b.kind === ARRAY2) return andCountArrays(a, b);
|
|
1929
|
+
return b.kind === BITSET ? andCountArrayBitset(a, b) : andCountArrayRuns(a, b);
|
|
1930
|
+
}
|
|
1931
|
+
return b.kind === RUN2 && a.kind === RUN2 ? andCountRuns(a, b) : andCountBitsetRuns(a, b);
|
|
1932
|
+
}
|
|
1933
|
+
function anyBitInRange(words, start, end) {
|
|
1934
|
+
const first = start >>> 5;
|
|
1935
|
+
const last = end >>> 5;
|
|
1936
|
+
const head = 4294967295 << (start & 31) >>> 0;
|
|
1937
|
+
const tail = 4294967295 >>> 31 - (end & 31);
|
|
1938
|
+
if (first === last) return (words[first] & head & tail) !== 0;
|
|
1939
|
+
if ((words[first] & head) !== 0 || (words[last] & tail) !== 0)
|
|
1940
|
+
return true;
|
|
1941
|
+
for (let i = first + 1; i < last; i++) if (words[i] !== 0) return true;
|
|
1942
|
+
return false;
|
|
1943
|
+
}
|
|
1944
|
+
function allBitsInRange(words, start, end) {
|
|
1945
|
+
const first = start >>> 5;
|
|
1946
|
+
const last = end >>> 5;
|
|
1947
|
+
const head = 4294967295 << (start & 31) >>> 0;
|
|
1948
|
+
const tail = 4294967295 >>> 31 - (end & 31);
|
|
1949
|
+
if (first === last) return (~words[first] & head & tail) === 0;
|
|
1950
|
+
if ((~words[first] & head) !== 0 || (~words[last] & tail) !== 0)
|
|
1951
|
+
return false;
|
|
1952
|
+
for (let i = first + 1; i < last; i++) if (words[i] !== 4294967295) return false;
|
|
1953
|
+
return true;
|
|
1954
|
+
}
|
|
1955
|
+
function subsetArrays(a, b) {
|
|
1956
|
+
const x = lows16(a);
|
|
1957
|
+
const y = lows16(b);
|
|
1958
|
+
const ie = a.off + a.len;
|
|
1959
|
+
const je = b.off + b.len;
|
|
1960
|
+
let j = b.off;
|
|
1961
|
+
if (skewed(a.len, b.len)) {
|
|
1962
|
+
for (let i2 = a.off; i2 < ie; i2++) {
|
|
1963
|
+
const v = x[i2];
|
|
1964
|
+
j = gallop(y, 0, j, je, v);
|
|
1965
|
+
if (j === je || y[j] !== v) return false;
|
|
1966
|
+
}
|
|
1967
|
+
return true;
|
|
1968
|
+
}
|
|
1969
|
+
let i = a.off;
|
|
1970
|
+
while (i < ie && j < je) {
|
|
1971
|
+
const p = x[i];
|
|
1972
|
+
const q = y[j];
|
|
1973
|
+
if (p < q) return false;
|
|
1974
|
+
i += p === q ? 1 : 0;
|
|
1975
|
+
j++;
|
|
1976
|
+
}
|
|
1977
|
+
return i === ie;
|
|
1978
|
+
}
|
|
1979
|
+
function subsetArrayRuns(a, b) {
|
|
1980
|
+
const u16 = lows16(a);
|
|
1981
|
+
const pairs = lows16(b);
|
|
1982
|
+
let r = 0;
|
|
1983
|
+
for (let i = a.off; i < a.off + a.len; i++) {
|
|
1984
|
+
const v = u16[i];
|
|
1985
|
+
while (r < b.len && pairs[b.off + 2 * r] + pairs[b.off + 2 * r + 1] < v)
|
|
1986
|
+
r++;
|
|
1987
|
+
if (r === b.len || pairs[b.off + 2 * r] > v) return false;
|
|
1988
|
+
}
|
|
1989
|
+
return true;
|
|
1990
|
+
}
|
|
1991
|
+
function subsetRunsArray(a, b) {
|
|
1992
|
+
const pairs = lows16(a);
|
|
1993
|
+
const y = lows16(b);
|
|
1994
|
+
const je = b.off + b.len;
|
|
1995
|
+
let j = b.off;
|
|
1996
|
+
for (let r = 0; r < a.len; r++) {
|
|
1997
|
+
const start = pairs[a.off + 2 * r];
|
|
1998
|
+
const last = start + pairs[a.off + 2 * r + 1];
|
|
1999
|
+
j = gallop(y, 0, j, je, start);
|
|
2000
|
+
const end = j + (last - start);
|
|
2001
|
+
if (end >= je || y[j] !== start || y[end] !== last) return false;
|
|
2002
|
+
j = end + 1;
|
|
2003
|
+
}
|
|
2004
|
+
return true;
|
|
2005
|
+
}
|
|
2006
|
+
function subsetRuns(a, b) {
|
|
2007
|
+
const x = lows16(a);
|
|
2008
|
+
const y = lows16(b);
|
|
2009
|
+
let j = 0;
|
|
2010
|
+
for (let i = 0; i < a.len; i++) {
|
|
2011
|
+
const start = x[a.off + 2 * i];
|
|
2012
|
+
const last = start + x[a.off + 2 * i + 1];
|
|
2013
|
+
while (j < b.len && y[b.off + 2 * j] + y[b.off + 2 * j + 1] < start)
|
|
2014
|
+
j++;
|
|
2015
|
+
if (j === b.len || y[b.off + 2 * j] > start) return false;
|
|
2016
|
+
if (y[b.off + 2 * j] + y[b.off + 2 * j + 1] < last) return false;
|
|
2017
|
+
}
|
|
2018
|
+
return true;
|
|
2019
|
+
}
|
|
2020
|
+
function subsetBitsetRuns(a, b) {
|
|
2021
|
+
const words = words32(a);
|
|
2022
|
+
const pairs = lows16(b);
|
|
2023
|
+
let from = 0;
|
|
2024
|
+
for (let r = 0; r < b.len; r++) {
|
|
2025
|
+
const start = pairs[b.off + 2 * r];
|
|
2026
|
+
if (start > from && anyBitInRange(words, from, start - 1)) return false;
|
|
2027
|
+
from = start + pairs[b.off + 2 * r + 1] + 1;
|
|
2028
|
+
}
|
|
2029
|
+
return from > 65535 || !anyBitInRange(words, from, 65535);
|
|
2030
|
+
}
|
|
2031
|
+
function containersSubset(a, b) {
|
|
2032
|
+
if (a.card > b.card) return false;
|
|
2033
|
+
if (a.kind === ARRAY2) {
|
|
2034
|
+
if (b.kind === ARRAY2) return subsetArrays(a, b);
|
|
2035
|
+
if (b.kind === RUN2) return subsetArrayRuns(a, b);
|
|
2036
|
+
const u16 = lows16(a);
|
|
2037
|
+
const words2 = words32(b);
|
|
2038
|
+
for (let i = a.off; i < a.off + a.len; i++) {
|
|
2039
|
+
const v = u16[i];
|
|
2040
|
+
if ((words2[v >>> 5] >>> (v & 31) & 1) === 0) return false;
|
|
2041
|
+
}
|
|
2042
|
+
return true;
|
|
2043
|
+
}
|
|
2044
|
+
if (a.kind === BITSET) {
|
|
2045
|
+
if (b.kind === BITSET) {
|
|
2046
|
+
const x = words32(a);
|
|
2047
|
+
const y = words32(b);
|
|
2048
|
+
for (let i = 0; i < WORDS; i += 8) {
|
|
2049
|
+
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];
|
|
2050
|
+
if (lack !== 0) return false;
|
|
2051
|
+
}
|
|
2052
|
+
return true;
|
|
2053
|
+
}
|
|
2054
|
+
if (b.kind === RUN2) return subsetBitsetRuns(a, b);
|
|
2055
|
+
return containerAndCard(a, b) === a.card;
|
|
2056
|
+
}
|
|
2057
|
+
if (b.kind === ARRAY2) return subsetRunsArray(a, b);
|
|
2058
|
+
if (b.kind === RUN2) return subsetRuns(a, b);
|
|
2059
|
+
const words = words32(b);
|
|
2060
|
+
const pairs = lows16(a);
|
|
2061
|
+
for (let r = 0; r < a.len; r++) {
|
|
2062
|
+
const start = pairs[a.off + 2 * r];
|
|
2063
|
+
if (!allBitsInRange(words, start, start + pairs[a.off + 2 * r + 1])) return false;
|
|
2064
|
+
}
|
|
2065
|
+
return true;
|
|
2066
|
+
}
|
|
2067
|
+
function containersEqual(a, b) {
|
|
2068
|
+
if (a.card !== b.card) return false;
|
|
2069
|
+
if (a.kind !== b.kind) return containerAndCard(a, b) === a.card;
|
|
2070
|
+
if (a.kind === BITSET) return equalWords(words32(a), 0, words32(b), 0, WORDS);
|
|
2071
|
+
if (a.len !== b.len) return false;
|
|
2072
|
+
const x = lows16(a);
|
|
2073
|
+
const y = lows16(b);
|
|
2074
|
+
const n = a.kind === ARRAY2 ? a.len : 2 * a.len;
|
|
2075
|
+
if (n < EQUAL_VIEW_MIN) {
|
|
2076
|
+
if (a.off === 0 && b.off === 0) return equalU16(x, 0, y, 0, n);
|
|
2077
|
+
return equalU16(x, a.off, y, b.off, n);
|
|
2078
|
+
}
|
|
2079
|
+
const xb = x.byteOffset + 2 * a.off;
|
|
2080
|
+
const yb = y.byteOffset + 2 * b.off;
|
|
2081
|
+
if (usesEqualView(n, xb, yb)) {
|
|
2082
|
+
const m = n >>> 1;
|
|
2083
|
+
if (!equalWords(new Uint32Array(x.buffer, xb, m), 0, new Uint32Array(y.buffer, yb, m), 0, m))
|
|
2084
|
+
return false;
|
|
2085
|
+
return (n & 1) === 0 || x[a.off + n - 1] === y[b.off + n - 1];
|
|
2086
|
+
}
|
|
2087
|
+
return equalU16(x, a.off, y, b.off, n);
|
|
2088
|
+
}
|
|
2089
|
+
var EQUAL_VIEW_MIN = 512;
|
|
2090
|
+
function usesEqualView(n, xb, yb) {
|
|
2091
|
+
return n >= EQUAL_VIEW_MIN && (xb & 3) === 0 && (yb & 3) === 0;
|
|
2092
|
+
}
|
|
2093
|
+
function equalWords(x, xo, y, yo, n) {
|
|
2094
|
+
let i = 0;
|
|
2095
|
+
for (const end = n - 7; i < end; i += 8) {
|
|
2096
|
+
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];
|
|
2097
|
+
if (d !== 0) return false;
|
|
2098
|
+
}
|
|
2099
|
+
for (; i < n; i++) if (x[xo + i] !== y[yo + i]) return false;
|
|
2100
|
+
return true;
|
|
2101
|
+
}
|
|
2102
|
+
function equalU16(x, xo, y, yo, n) {
|
|
2103
|
+
let i = 0;
|
|
2104
|
+
for (const end = n - 7; i < end; i += 8) {
|
|
2105
|
+
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];
|
|
2106
|
+
if (d !== 0) return false;
|
|
2107
|
+
}
|
|
2108
|
+
for (; i < n; i++) if (x[xo + i] !== y[yo + i]) return false;
|
|
2109
|
+
return true;
|
|
2110
|
+
}
|
|
2111
|
+
function intersectsArrays(a, b) {
|
|
2112
|
+
const small = a.len <= b.len ? a : b;
|
|
2113
|
+
const big = small === a ? b : a;
|
|
2114
|
+
const s = lows16(small);
|
|
2115
|
+
const l = lows16(big);
|
|
2116
|
+
const se = small.off + small.len;
|
|
2117
|
+
const le = big.off + big.len;
|
|
2118
|
+
if (s[se - 1] < l[big.off] || s[small.off] > l[le - 1]) {
|
|
2119
|
+
return false;
|
|
2120
|
+
}
|
|
2121
|
+
if (skewed(small.len, big.len)) {
|
|
2122
|
+
let at = big.off;
|
|
2123
|
+
for (let i2 = small.off; i2 < se; i2++) {
|
|
2124
|
+
const v = s[i2];
|
|
2125
|
+
at = gallop(l, 0, at, le, v);
|
|
2126
|
+
if (at === le) return false;
|
|
2127
|
+
if (l[at] === v) return true;
|
|
2128
|
+
}
|
|
2129
|
+
return false;
|
|
2130
|
+
}
|
|
2131
|
+
let i = small.off;
|
|
2132
|
+
let j = big.off;
|
|
2133
|
+
if (small.len >= PROBE_MIN) {
|
|
2134
|
+
for (let step = 0; step < MERGE_FIRST && i < se && j < le; step++) {
|
|
2135
|
+
const x = s[i];
|
|
2136
|
+
const y = l[j];
|
|
2137
|
+
if (x === y) return true;
|
|
2138
|
+
if (x < y) i++;
|
|
2139
|
+
else j++;
|
|
2140
|
+
}
|
|
2141
|
+
if (i === se || j === le) return false;
|
|
2142
|
+
const left = i;
|
|
2143
|
+
const from = gallop(l, 0, j, le, s[left]);
|
|
2144
|
+
const to = gallop(l, 0, from, le, s[se - 1] + 1);
|
|
2145
|
+
const words = probeWords;
|
|
2146
|
+
for (let k = left; k < se; k++) {
|
|
2147
|
+
const v = s[k];
|
|
2148
|
+
words[v >>> 5] = words[v >>> 5] | 1 << (v & 31);
|
|
2149
|
+
}
|
|
2150
|
+
let hit = false;
|
|
2151
|
+
for (let k = from; k < to; k++) {
|
|
2152
|
+
const v = l[k];
|
|
2153
|
+
if ((words[v >>> 5] >>> (v & 31) & 1) === 1) {
|
|
2154
|
+
hit = true;
|
|
2155
|
+
break;
|
|
2156
|
+
}
|
|
2157
|
+
}
|
|
2158
|
+
for (let k = left; k < se; k++) words[s[k] >>> 5] = 0;
|
|
2159
|
+
return hit;
|
|
2160
|
+
}
|
|
2161
|
+
while (i < se && j < le) {
|
|
2162
|
+
const x = s[i];
|
|
2163
|
+
const y = l[j];
|
|
2164
|
+
if (x === y) return true;
|
|
2165
|
+
if (x < y) i++;
|
|
2166
|
+
else j++;
|
|
2167
|
+
}
|
|
2168
|
+
return false;
|
|
2169
|
+
}
|
|
2170
|
+
function intersectsArrayRuns(a, b) {
|
|
2171
|
+
const u16 = lows16(a);
|
|
2172
|
+
const pairs = lows16(b);
|
|
2173
|
+
let r = 0;
|
|
2174
|
+
for (let i = a.off; i < a.off + a.len; i++) {
|
|
2175
|
+
const v = u16[i];
|
|
2176
|
+
while (r < b.len && pairs[b.off + 2 * r] + pairs[b.off + 2 * r + 1] < v) {
|
|
2177
|
+
r++;
|
|
2178
|
+
}
|
|
2179
|
+
if (r === b.len) return false;
|
|
2180
|
+
if (pairs[b.off + 2 * r] <= v) return true;
|
|
2181
|
+
}
|
|
2182
|
+
return false;
|
|
2183
|
+
}
|
|
2184
|
+
function containersIntersect(a, b) {
|
|
2185
|
+
if (a.kind > b.kind) return containersIntersect(b, a);
|
|
2186
|
+
if (a.kind === ARRAY2) {
|
|
2187
|
+
if (b.kind === ARRAY2) return intersectsArrays(a, b);
|
|
2188
|
+
if (b.kind === RUN2) return intersectsArrayRuns(a, b);
|
|
2189
|
+
const u16 = lows16(a);
|
|
2190
|
+
const words = words32(b);
|
|
2191
|
+
for (let i2 = a.off; i2 < a.off + a.len; i2++) {
|
|
2192
|
+
const v = u16[i2];
|
|
2193
|
+
if ((words[v >>> 5] >>> (v & 31) & 1) === 1) return true;
|
|
2194
|
+
}
|
|
2195
|
+
return false;
|
|
2196
|
+
}
|
|
2197
|
+
if (a.kind === BITSET) {
|
|
2198
|
+
const x2 = words32(a);
|
|
2199
|
+
if (b.kind === BITSET) {
|
|
2200
|
+
const y2 = words32(b);
|
|
2201
|
+
for (let i2 = 0; i2 < WORDS; i2 += 8) {
|
|
2202
|
+
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];
|
|
2203
|
+
if (both !== 0) return true;
|
|
2204
|
+
}
|
|
2205
|
+
return false;
|
|
2206
|
+
}
|
|
2207
|
+
const pairs = lows16(b);
|
|
2208
|
+
for (let r = 0; r < b.len; r++) {
|
|
2209
|
+
const start = pairs[b.off + 2 * r];
|
|
2210
|
+
if (anyBitInRange(x2, start, start + pairs[b.off + 2 * r + 1])) return true;
|
|
2211
|
+
}
|
|
2212
|
+
return false;
|
|
2213
|
+
}
|
|
2214
|
+
const x = lows16(a);
|
|
2215
|
+
const y = lows16(b);
|
|
2216
|
+
let i = 0;
|
|
2217
|
+
let j = 0;
|
|
2218
|
+
while (i < a.len && j < b.len) {
|
|
2219
|
+
const as = x[a.off + 2 * i];
|
|
2220
|
+
const ae = as + x[a.off + 2 * i + 1];
|
|
2221
|
+
const bs = y[b.off + 2 * j];
|
|
2222
|
+
const be = bs + y[b.off + 2 * j + 1];
|
|
2223
|
+
if ((as > bs ? as : bs) <= (ae < be ? ae : be)) return true;
|
|
2224
|
+
if (ae < be) i++;
|
|
2225
|
+
else j++;
|
|
2226
|
+
}
|
|
2227
|
+
return false;
|
|
2228
|
+
}
|
|
2229
|
+
|
|
2230
|
+
// src/ts-roaring/iterator.ts
|
|
2231
|
+
var DONE = { done: true, value: void 0 };
|
|
2232
|
+
var BitmapIterator = class {
|
|
2233
|
+
#keys;
|
|
2234
|
+
#conts;
|
|
2235
|
+
/** The container being walked, as an index into `#conts`, and its kind, storage and offset. */
|
|
2236
|
+
#at = -1;
|
|
2237
|
+
#kind = ARRAY2;
|
|
2238
|
+
#u16 = new Uint16Array(0);
|
|
2239
|
+
#words = new Uint32Array(0);
|
|
2240
|
+
#off = 0;
|
|
2241
|
+
/** Added to every remainder: the container's key times 65,536. */
|
|
2242
|
+
#base = 0;
|
|
2243
|
+
/** An array: the next index and one past the last. A run container: the next run's index and the run count. A bitset: the word index. */
|
|
2244
|
+
#pos = 0;
|
|
2245
|
+
#end = 0;
|
|
2246
|
+
/** A run container: the next value and the last of the current run. A bitset: what is left of the current word. */
|
|
2247
|
+
#next = 0;
|
|
2248
|
+
#last = -1;
|
|
2249
|
+
constructor(keys, conts) {
|
|
2250
|
+
this.#keys = keys;
|
|
2251
|
+
this.#conts = conts;
|
|
2252
|
+
}
|
|
2253
|
+
[Symbol.iterator]() {
|
|
2254
|
+
return this;
|
|
2255
|
+
}
|
|
2256
|
+
next() {
|
|
2257
|
+
for (; ; ) {
|
|
2258
|
+
if (this.#kind === ARRAY2) {
|
|
2259
|
+
if (this.#pos < this.#end) {
|
|
2260
|
+
return { done: false, value: this.#base + this.#u16[this.#pos++] };
|
|
1232
2261
|
}
|
|
1233
2262
|
} else if (this.#kind === BITSET) {
|
|
1234
2263
|
let w = this.#next;
|
|
@@ -1292,7 +2321,16 @@ function bodySize(c) {
|
|
|
1292
2321
|
if (c.kind === BITSET) return BITSET_BYTES;
|
|
1293
2322
|
return 2 + 4 * c.len;
|
|
1294
2323
|
}
|
|
2324
|
+
var SMALL_BODY = 64;
|
|
1295
2325
|
function putU16s(out, at, src, from, count) {
|
|
2326
|
+
if (count < SMALL_BODY) {
|
|
2327
|
+
for (let i = 0; i < count; i++) {
|
|
2328
|
+
const v = src[from + i];
|
|
2329
|
+
out[at++] = v & 255;
|
|
2330
|
+
out[at++] = v >>> 8;
|
|
2331
|
+
}
|
|
2332
|
+
return;
|
|
2333
|
+
}
|
|
1296
2334
|
if (LITTLE_ENDIAN) {
|
|
1297
2335
|
out.set(new Uint8Array(src.buffer, src.byteOffset + 2 * from, 2 * count), at);
|
|
1298
2336
|
return;
|
|
@@ -1347,7 +2385,7 @@ function serializeContainers(keys, conts) {
|
|
|
1347
2385
|
}
|
|
1348
2386
|
return out;
|
|
1349
2387
|
}
|
|
1350
|
-
function decodeContainers(input) {
|
|
2388
|
+
function decodeContainers(input, detached = false) {
|
|
1351
2389
|
const bytes = Uint8Array.prototype.slice.call(input);
|
|
1352
2390
|
const layout = parsePortableLayout(bytes);
|
|
1353
2391
|
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
@@ -1357,18 +2395,21 @@ function decodeContainers(input) {
|
|
|
1357
2395
|
let end = bytes.byteLength === 0 ? 0 : 8;
|
|
1358
2396
|
let slabLength = 0;
|
|
1359
2397
|
let small = 0;
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
2398
|
+
if (!detached) {
|
|
2399
|
+
for (const { cardinality, kind, offset } of layout) {
|
|
2400
|
+
if (kind === ARRAY) {
|
|
2401
|
+
slabLength += cardinality;
|
|
2402
|
+
small++;
|
|
2403
|
+
} else if (kind !== BITMAP) {
|
|
2404
|
+
slabLength += 2 * view.getUint16(offset, true);
|
|
2405
|
+
small++;
|
|
2406
|
+
}
|
|
1367
2407
|
}
|
|
1368
2408
|
}
|
|
1369
2409
|
const own = LITTLE_ENDIAN && bytes.byteOffset === 0 && bytes.buffer instanceof ArrayBuffer && bytes.buffer.byteLength === bytes.byteLength;
|
|
1370
|
-
const alias = own && small === 1;
|
|
1371
|
-
const
|
|
2410
|
+
const alias = !detached && own && small === 1;
|
|
2411
|
+
const solo = alias || detached;
|
|
2412
|
+
const slab = solo ? NO_U16 : new Uint16Array(slabLength);
|
|
1372
2413
|
let used = 0;
|
|
1373
2414
|
for (const { key, cardinality, kind, offset } of layout) {
|
|
1374
2415
|
keys[n] = key;
|
|
@@ -1377,22 +2418,22 @@ function decodeContainers(input) {
|
|
|
1377
2418
|
const values = new Uint16Array(bytes.buffer, offset, cardinality);
|
|
1378
2419
|
conts[n++] = new Container(ARRAY2, values, 0, cardinality, cardinality, false);
|
|
1379
2420
|
} else {
|
|
1380
|
-
const into =
|
|
1381
|
-
getU16s(bytes, view, offset, into,
|
|
2421
|
+
const into = solo ? new Uint16Array(cardinality) : slab;
|
|
2422
|
+
getU16s(bytes, view, offset, into, solo ? 0 : used, cardinality);
|
|
1382
2423
|
conts[n++] = new Container(
|
|
1383
2424
|
ARRAY2,
|
|
1384
2425
|
into,
|
|
1385
|
-
|
|
2426
|
+
solo ? 0 : used,
|
|
1386
2427
|
cardinality,
|
|
1387
2428
|
cardinality,
|
|
1388
|
-
small > 1
|
|
2429
|
+
!solo && small > 1
|
|
1389
2430
|
);
|
|
1390
2431
|
used += cardinality;
|
|
1391
2432
|
}
|
|
1392
2433
|
end = offset + 2 * cardinality;
|
|
1393
2434
|
} else if (kind === BITMAP) {
|
|
1394
2435
|
let words;
|
|
1395
|
-
if (own && offset % 4 === 0) {
|
|
2436
|
+
if (!detached && own && offset % 4 === 0) {
|
|
1396
2437
|
words = new Uint32Array(bytes.buffer, offset, WORDS);
|
|
1397
2438
|
} else {
|
|
1398
2439
|
words = new Uint32Array(WORDS);
|
|
@@ -1410,9 +2451,16 @@ function decodeContainers(input) {
|
|
|
1410
2451
|
const pairs = new Uint16Array(bytes.buffer, offset + 2, 2 * runs);
|
|
1411
2452
|
conts[n++] = new Container(RUN2, pairs, 0, runs, cardinality, false);
|
|
1412
2453
|
} else {
|
|
1413
|
-
const into =
|
|
1414
|
-
getU16s(bytes, view, offset + 2, into,
|
|
1415
|
-
conts[n++] = new Container(
|
|
2454
|
+
const into = solo ? new Uint16Array(2 * runs) : slab;
|
|
2455
|
+
getU16s(bytes, view, offset + 2, into, solo ? 0 : used, 2 * runs);
|
|
2456
|
+
conts[n++] = new Container(
|
|
2457
|
+
RUN2,
|
|
2458
|
+
into,
|
|
2459
|
+
solo ? 0 : used,
|
|
2460
|
+
runs,
|
|
2461
|
+
cardinality,
|
|
2462
|
+
!solo && small > 1
|
|
2463
|
+
);
|
|
1416
2464
|
used += 2 * runs;
|
|
1417
2465
|
}
|
|
1418
2466
|
end = offset + 2 + 4 * runs;
|
|
@@ -1439,11 +2487,8 @@ var MAX_ID = 4294967295;
|
|
|
1439
2487
|
function isId(value) {
|
|
1440
2488
|
return Number.isInteger(value) && value >= 0 && value <= MAX_ID;
|
|
1441
2489
|
}
|
|
1442
|
-
function badId(value) {
|
|
1443
|
-
return new ValidationError2(`${String(value)} is not an integer from 0 to ${MAX_ID}`);
|
|
1444
|
-
}
|
|
1445
2490
|
function checkedId(value) {
|
|
1446
|
-
if (!isId(value)) throw
|
|
2491
|
+
if (!isId(value)) throw refusalOfId(value);
|
|
1447
2492
|
return value;
|
|
1448
2493
|
}
|
|
1449
2494
|
function collect(values) {
|
|
@@ -1451,10 +2496,17 @@ function collect(values) {
|
|
|
1451
2496
|
if (Array.isArray(values)) {
|
|
1452
2497
|
const list = values;
|
|
1453
2498
|
const out2 = new Uint32Array(list.length);
|
|
1454
|
-
|
|
2499
|
+
let i = 0;
|
|
2500
|
+
try {
|
|
2501
|
+
for (; i < list.length; i++) {
|
|
2502
|
+
const v = list[i];
|
|
2503
|
+
if (v >>> 0 !== v) throw refusalOfId(v);
|
|
2504
|
+
out2[i] = v;
|
|
2505
|
+
}
|
|
2506
|
+
} catch (error) {
|
|
1455
2507
|
const v = list[i];
|
|
1456
|
-
if (v
|
|
1457
|
-
|
|
2508
|
+
if (typeof v !== "number") throw refusalOfId(v);
|
|
2509
|
+
throw error;
|
|
1458
2510
|
}
|
|
1459
2511
|
return out2;
|
|
1460
2512
|
}
|
|
@@ -1471,6 +2523,7 @@ function collect(values) {
|
|
|
1471
2523
|
return out.subarray(0, n);
|
|
1472
2524
|
}
|
|
1473
2525
|
function collectLenient(values) {
|
|
2526
|
+
if (values instanceof Uint32Array) return values.slice();
|
|
1474
2527
|
const list = Array.isArray(values) ? values : Array.from(values);
|
|
1475
2528
|
const out = new Uint32Array(list.length);
|
|
1476
2529
|
let n = 0;
|
|
@@ -1480,6 +2533,11 @@ function collectLenient(values) {
|
|
|
1480
2533
|
}
|
|
1481
2534
|
return out.subarray(0, n);
|
|
1482
2535
|
}
|
|
2536
|
+
var FEW_IDS = 4;
|
|
2537
|
+
function groupPath(before, count) {
|
|
2538
|
+
if (count <= FEW_IDS) return "few";
|
|
2539
|
+
return walksRunIds(before, count) ? "walk" : "merge";
|
|
2540
|
+
}
|
|
1483
2541
|
function sortedIds(ids, owned) {
|
|
1484
2542
|
for (let i = 1; i < ids.length; i++) {
|
|
1485
2543
|
if (ids[i - 1] > ids[i]) return (owned ? ids : ids.slice()).sort();
|
|
@@ -1520,9 +2578,11 @@ function lowerBoundIn(keys, key, from, to) {
|
|
|
1520
2578
|
var OR = 0;
|
|
1521
2579
|
var AND = 1;
|
|
1522
2580
|
var AND_NOT = 2;
|
|
2581
|
+
var XOR = 3;
|
|
1523
2582
|
function combineContainers(op, a, b) {
|
|
1524
|
-
if (op === OR) return containerOr(a, b, !a.shared);
|
|
2583
|
+
if (op === OR) return containerOr(a, b, !a.shared || a.kind === RUN2);
|
|
1525
2584
|
if (op === AND) return containerAnd(a, b, !a.shared);
|
|
2585
|
+
if (op === XOR) return containerXor(a, b, !a.shared);
|
|
1526
2586
|
return containerAndNot(a, b, !a.shared);
|
|
1527
2587
|
}
|
|
1528
2588
|
var TsBitmap = class _TsBitmap {
|
|
@@ -1544,7 +2604,9 @@ var TsBitmap = class _TsBitmap {
|
|
|
1544
2604
|
}
|
|
1545
2605
|
/**
|
|
1546
2606
|
* Cap the size, check the structure, then build the containers. With `whole`, bytes after the last container are
|
|
1547
|
-
* refused too; without it they are ignored.
|
|
2607
|
+
* refused too; without it they are ignored. With `detached`, every container gets storage of its own, copied out of
|
|
2608
|
+
* the input, so nothing the result holds is a view of one shared buffer: a bitmap that is kept and then reduced
|
|
2609
|
+
* does not keep the whole input alive.
|
|
1548
2610
|
*
|
|
1549
2611
|
* @throws {IntegrityError} if the input exceeds `maxBytes`, is not a well-formed portable bitmap, or (with `whole`)
|
|
1550
2612
|
* has bytes after it.
|
|
@@ -1553,7 +2615,7 @@ var TsBitmap = class _TsBitmap {
|
|
|
1553
2615
|
if (bytes.length > maxBytes) {
|
|
1554
2616
|
throw new IntegrityError3(`serialized bitmap is ${bytes.length}B, exceeds cap ${maxBytes}B`);
|
|
1555
2617
|
}
|
|
1556
|
-
const { keys, conts, end } = decodeContainers(bytes);
|
|
2618
|
+
const { keys, conts, end } = decodeContainers(bytes, options.detached === true);
|
|
1557
2619
|
if (options.whole === true && end !== bytes.byteLength) {
|
|
1558
2620
|
throw trailingBytes(bytes.byteLength, end);
|
|
1559
2621
|
}
|
|
@@ -1569,6 +2631,12 @@ var TsBitmap = class _TsBitmap {
|
|
|
1569
2631
|
const conts = this.#conts;
|
|
1570
2632
|
for (let i = 0; i < conts.length; i++) conts[i] = optimize(conts[i]);
|
|
1571
2633
|
}
|
|
2634
|
+
/** Whether at least one container is held as runs. */
|
|
2635
|
+
hasRunContainer() {
|
|
2636
|
+
for (let i = 0; i < this.#conts.length; i++)
|
|
2637
|
+
if (this.#conts[i].kind === RUN2) return true;
|
|
2638
|
+
return false;
|
|
2639
|
+
}
|
|
1572
2640
|
/**
|
|
1573
2641
|
* The set as storage chunks: each payload is the portable bytes of a one-container bitmap holding that chunk's low 16
|
|
1574
2642
|
* bits, optimized the way {@link optimize} does. Nothing is built until a chunk is asked for, so a writer that yields
|
|
@@ -1593,6 +2661,11 @@ var TsBitmap = class _TsBitmap {
|
|
|
1593
2661
|
}
|
|
1594
2662
|
};
|
|
1595
2663
|
}
|
|
2664
|
+
/** The smallest id, or `undefined` when the bitmap is empty. */
|
|
2665
|
+
minimum() {
|
|
2666
|
+
if (this.#conts.length === 0) return void 0;
|
|
2667
|
+
return this.#keys[0] * 65536 + containerMin(this.#conts[0]);
|
|
2668
|
+
}
|
|
1596
2669
|
maximum() {
|
|
1597
2670
|
const last = this.#conts.length - 1;
|
|
1598
2671
|
if (last < 0) return void 0;
|
|
@@ -1626,36 +2699,50 @@ var TsBitmap = class _TsBitmap {
|
|
|
1626
2699
|
const key = ids[i] >>> 16;
|
|
1627
2700
|
let end = i + 1;
|
|
1628
2701
|
while (end < ids.length && ids[end] >>> 16 === key) end++;
|
|
1629
|
-
const
|
|
2702
|
+
const first = i;
|
|
1630
2703
|
i = end;
|
|
1631
2704
|
at = gallopKeys(this.#keys, key, at);
|
|
1632
2705
|
if (this.#keys[at] === key) {
|
|
1633
2706
|
const before = this.#conts[at];
|
|
1634
|
-
const
|
|
2707
|
+
const path = groupPath(before, end - first);
|
|
2708
|
+
const after = path === "few" ? containerAddSorted(before, ids, first, end) : path === "walk" ? orRunIdsWalk(before, ids, first, end) : containerOr(
|
|
2709
|
+
before,
|
|
2710
|
+
fromSortedIds(ids, first, end),
|
|
2711
|
+
!before.shared || before.kind === RUN2
|
|
2712
|
+
);
|
|
1635
2713
|
this.#conts[at] = after;
|
|
1636
2714
|
this.#size += after.card - before.card;
|
|
1637
2715
|
} else {
|
|
2716
|
+
const group = fromSortedIds(ids, first, end);
|
|
1638
2717
|
fresh.push({ key, group });
|
|
1639
2718
|
this.#size += group.card;
|
|
1640
2719
|
}
|
|
1641
2720
|
}
|
|
1642
2721
|
if (fresh.length > 0) this.#insertAll(fresh);
|
|
1643
2722
|
}
|
|
2723
|
+
/** Remove the id (anything that is not an id is ignored); whether it was there. */
|
|
1644
2724
|
remove(value) {
|
|
1645
|
-
if (!isId(value)) return;
|
|
2725
|
+
if (!isId(value)) return false;
|
|
1646
2726
|
const key = value >>> 16;
|
|
1647
2727
|
const at = lowerBound2(this.#keys, key);
|
|
1648
|
-
if (this.#keys[at] !== key) return;
|
|
2728
|
+
if (this.#keys[at] !== key) return false;
|
|
1649
2729
|
const before = this.#conts[at];
|
|
1650
2730
|
const after = containerRemove(before, value & 65535);
|
|
1651
2731
|
if (after === null) {
|
|
1652
2732
|
this.#keys.splice(at, 1);
|
|
1653
2733
|
this.#conts.splice(at, 1);
|
|
1654
2734
|
this.#size -= before.card;
|
|
1655
|
-
return;
|
|
2735
|
+
return true;
|
|
1656
2736
|
}
|
|
1657
2737
|
this.#conts[at] = after;
|
|
1658
2738
|
this.#size += after.card - before.card;
|
|
2739
|
+
return after.card !== before.card;
|
|
2740
|
+
}
|
|
2741
|
+
/** Remove every id. Containers a clone shares are left to it. */
|
|
2742
|
+
clear() {
|
|
2743
|
+
this.#keys = [];
|
|
2744
|
+
this.#conts = [];
|
|
2745
|
+
this.#size = 0;
|
|
1659
2746
|
}
|
|
1660
2747
|
/** Remove the ids (anything that is not an id is ignored), grouped by key; the keys left empty go in one pass. */
|
|
1661
2748
|
removeMany(values) {
|
|
@@ -1715,6 +2802,90 @@ var TsBitmap = class _TsBitmap {
|
|
|
1715
2802
|
andNotInPlace(other) {
|
|
1716
2803
|
this.#combine(_TsBitmap.#of(other), AND_NOT);
|
|
1717
2804
|
}
|
|
2805
|
+
/** Flip the ids `other` holds, in one pass over the pair of each key. */
|
|
2806
|
+
xorInPlace(other) {
|
|
2807
|
+
this.#combine(_TsBitmap.#of(other), XOR);
|
|
2808
|
+
}
|
|
2809
|
+
/** How many ids both bitmaps hold, counted without building the intersection. */
|
|
2810
|
+
andCardinality(other) {
|
|
2811
|
+
const that = _TsBitmap.#of(other);
|
|
2812
|
+
const a = this.#keys;
|
|
2813
|
+
const b = that.#keys;
|
|
2814
|
+
let n = 0;
|
|
2815
|
+
let i = 0;
|
|
2816
|
+
let j = 0;
|
|
2817
|
+
while (i < a.length && j < b.length) {
|
|
2818
|
+
const ka = a[i];
|
|
2819
|
+
const kb = b[j];
|
|
2820
|
+
if (ka === kb) {
|
|
2821
|
+
n += containerAndCard(this.#conts[i++], that.#conts[j++]);
|
|
2822
|
+
} else if (ka < kb) {
|
|
2823
|
+
i = gallopKeys(a, kb, i + 1);
|
|
2824
|
+
} else {
|
|
2825
|
+
j = gallopKeys(b, ka, j + 1);
|
|
2826
|
+
}
|
|
2827
|
+
}
|
|
2828
|
+
return n;
|
|
2829
|
+
}
|
|
2830
|
+
/** How many ids either bitmap holds. */
|
|
2831
|
+
orCardinality(other) {
|
|
2832
|
+
return this.#size + _TsBitmap.#of(other).#size - this.andCardinality(other);
|
|
2833
|
+
}
|
|
2834
|
+
/** How many ids exactly one of the bitmaps holds. */
|
|
2835
|
+
xorCardinality(other) {
|
|
2836
|
+
return this.#size + _TsBitmap.#of(other).#size - 2 * this.andCardinality(other);
|
|
2837
|
+
}
|
|
2838
|
+
/** How many ids this bitmap holds that `other` lacks. */
|
|
2839
|
+
andNotCardinality(other) {
|
|
2840
|
+
return this.#size - this.andCardinality(other);
|
|
2841
|
+
}
|
|
2842
|
+
/** Whether the bitmaps share an id; stops at the first one found. */
|
|
2843
|
+
intersects(other) {
|
|
2844
|
+
const that = _TsBitmap.#of(other);
|
|
2845
|
+
const a = this.#keys;
|
|
2846
|
+
const b = that.#keys;
|
|
2847
|
+
let i = 0;
|
|
2848
|
+
let j = 0;
|
|
2849
|
+
while (i < a.length && j < b.length) {
|
|
2850
|
+
const ka = a[i];
|
|
2851
|
+
const kb = b[j];
|
|
2852
|
+
if (ka === kb) {
|
|
2853
|
+
if (containersIntersect(this.#conts[i++], that.#conts[j++])) {
|
|
2854
|
+
return true;
|
|
2855
|
+
}
|
|
2856
|
+
} else if (ka < kb) {
|
|
2857
|
+
i = gallopKeys(a, kb, i + 1);
|
|
2858
|
+
} else {
|
|
2859
|
+
j = gallopKeys(b, ka, j + 1);
|
|
2860
|
+
}
|
|
2861
|
+
}
|
|
2862
|
+
return false;
|
|
2863
|
+
}
|
|
2864
|
+
/** Whether every id of this bitmap is in `other`; stops at the first container that is not inside its partner. */
|
|
2865
|
+
isSubset(other) {
|
|
2866
|
+
const that = _TsBitmap.#of(other);
|
|
2867
|
+
if (this.#size > that.#size) return false;
|
|
2868
|
+
const a = this.#keys;
|
|
2869
|
+
const b = that.#keys;
|
|
2870
|
+
let j = 0;
|
|
2871
|
+
for (let i = 0; i < a.length; i++) {
|
|
2872
|
+
j = gallopKeys(b, a[i], j);
|
|
2873
|
+
if (j === b.length || b[j] !== a[i]) return false;
|
|
2874
|
+
const c = this.#conts[i];
|
|
2875
|
+
if (!containersSubset(c, that.#conts[j++])) return false;
|
|
2876
|
+
}
|
|
2877
|
+
return true;
|
|
2878
|
+
}
|
|
2879
|
+
/** Whether both hold the same ids, whatever the kinds of their containers. */
|
|
2880
|
+
isEqual(other) {
|
|
2881
|
+
const that = _TsBitmap.#of(other);
|
|
2882
|
+
if (this.#size !== that.#size || this.#keys.length !== that.#keys.length) return false;
|
|
2883
|
+
for (let i = 0; i < this.#keys.length; i++) {
|
|
2884
|
+
if (this.#keys[i] !== that.#keys[i]) return false;
|
|
2885
|
+
if (!containersEqual(this.#conts[i], that.#conts[i])) return false;
|
|
2886
|
+
}
|
|
2887
|
+
return true;
|
|
2888
|
+
}
|
|
1718
2889
|
[Symbol.iterator]() {
|
|
1719
2890
|
return new BitmapIterator(this.#keys, this.#conts);
|
|
1720
2891
|
}
|
|
@@ -1804,7 +2975,114 @@ var TsBitmap = class _TsBitmap {
|
|
|
1804
2975
|
const ka = a[i];
|
|
1805
2976
|
const kb = b[j];
|
|
1806
2977
|
if (ka === kb) {
|
|
1807
|
-
const c = combineContainers(op, ca[i++], cb[j++]);
|
|
2978
|
+
const c = combineContainers(op, ca[i++], cb[j++]);
|
|
2979
|
+
if (c !== null) {
|
|
2980
|
+
keys.push(ka);
|
|
2981
|
+
conts.push(c);
|
|
2982
|
+
size += c.card;
|
|
2983
|
+
}
|
|
2984
|
+
} else if (ka < kb) {
|
|
2985
|
+
if (op === AND) {
|
|
2986
|
+
i = gallopKeys(a, kb, i + 1);
|
|
2987
|
+
} else {
|
|
2988
|
+
keys.push(ka);
|
|
2989
|
+
conts.push(ca[i]);
|
|
2990
|
+
size += ca[i++].card;
|
|
2991
|
+
}
|
|
2992
|
+
} else if (op === AND) {
|
|
2993
|
+
j = gallopKeys(b, ka, j + 1);
|
|
2994
|
+
} else {
|
|
2995
|
+
if (op === OR || op === XOR) {
|
|
2996
|
+
keys.push(kb);
|
|
2997
|
+
conts.push(cloneContainer(cb[j]));
|
|
2998
|
+
size += cb[j].card;
|
|
2999
|
+
}
|
|
3000
|
+
j++;
|
|
3001
|
+
}
|
|
3002
|
+
}
|
|
3003
|
+
if (op !== AND) {
|
|
3004
|
+
for (; i < a.length; i++) {
|
|
3005
|
+
keys.push(a[i]);
|
|
3006
|
+
conts.push(ca[i]);
|
|
3007
|
+
size += ca[i].card;
|
|
3008
|
+
}
|
|
3009
|
+
}
|
|
3010
|
+
if (op === OR || op === XOR) {
|
|
3011
|
+
for (; j < b.length; j++) {
|
|
3012
|
+
keys.push(b[j]);
|
|
3013
|
+
conts.push(cloneContainer(cb[j]));
|
|
3014
|
+
size += cb[j].card;
|
|
3015
|
+
}
|
|
3016
|
+
}
|
|
3017
|
+
this.#keys = keys;
|
|
3018
|
+
this.#conts = conts;
|
|
3019
|
+
this.#size = size;
|
|
3020
|
+
}
|
|
3021
|
+
/** The ids both bitmaps hold, as a new bitmap; neither operand changes and no container of either is kept. */
|
|
3022
|
+
static and(a, b) {
|
|
3023
|
+
return _TsBitmap.#fresh(_TsBitmap.#of(a), _TsBitmap.#of(b), AND);
|
|
3024
|
+
}
|
|
3025
|
+
/** The ids either holds, as a new bitmap; neither operand changes. */
|
|
3026
|
+
static or(a, b) {
|
|
3027
|
+
return _TsBitmap.#fresh(_TsBitmap.#of(a), _TsBitmap.#of(b), OR);
|
|
3028
|
+
}
|
|
3029
|
+
/**
|
|
3030
|
+
* The ids any of `bitmaps` holds, as a new bitmap that owns all its storage; no operand changes and none is flagged.
|
|
3031
|
+
* The containers of each key are gathered across the inputs and united in one pass (see {@link orManyContainers}),
|
|
3032
|
+
* counted once. A key only one input holds is copied as it is, a run included.
|
|
3033
|
+
*/
|
|
3034
|
+
static orMany(bitmaps) {
|
|
3035
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
3036
|
+
for (const input of bitmaps) {
|
|
3037
|
+
const that = _TsBitmap.#of(input);
|
|
3038
|
+
for (let i = 0; i < that.#keys.length; i++) {
|
|
3039
|
+
const key = that.#keys[i];
|
|
3040
|
+
const held = byKey.get(key);
|
|
3041
|
+
if (held === void 0) byKey.set(key, [that.#conts[i]]);
|
|
3042
|
+
else held.push(that.#conts[i]);
|
|
3043
|
+
}
|
|
3044
|
+
}
|
|
3045
|
+
const keys = Array.from(byKey.keys()).sort((x, y) => x - y);
|
|
3046
|
+
const conts = [];
|
|
3047
|
+
let size = 0;
|
|
3048
|
+
for (const key of keys) {
|
|
3049
|
+
const held = byKey.get(key);
|
|
3050
|
+
const c = held.length === 1 ? cloneContainer(held[0]) : orManyContainers(held);
|
|
3051
|
+
conts.push(c);
|
|
3052
|
+
size += c.card;
|
|
3053
|
+
}
|
|
3054
|
+
return new _TsBitmap(keys, conts, size);
|
|
3055
|
+
}
|
|
3056
|
+
/** The ids exactly one holds, as a new bitmap; neither operand changes. */
|
|
3057
|
+
static xor(a, b) {
|
|
3058
|
+
return _TsBitmap.#fresh(_TsBitmap.#of(a), _TsBitmap.#of(b), XOR);
|
|
3059
|
+
}
|
|
3060
|
+
/** The ids of `a` that `b` lacks, as a new bitmap; neither operand changes. */
|
|
3061
|
+
static andNot(a, b) {
|
|
3062
|
+
return _TsBitmap.#fresh(_TsBitmap.#of(a), _TsBitmap.#of(b), AND_NOT);
|
|
3063
|
+
}
|
|
3064
|
+
/**
|
|
3065
|
+
* The same walk as {@link TsBitmap.#combine}, building a new bitmap and leaving both operands whole. Where both hold
|
|
3066
|
+
* a key, the pair combines into a fresh container (the in-place form is never taken, so no storage of either operand
|
|
3067
|
+
* is written). A container only `x` holds is kept by reference and flagged shared, so a later write to `x` or to the
|
|
3068
|
+
* result copies it once; for an intersection nothing of `x` is kept, so nothing is flagged. A container only `y`
|
|
3069
|
+
* holds is copied in for a union or a symmetric difference.
|
|
3070
|
+
*/
|
|
3071
|
+
static #fresh(x, y, op) {
|
|
3072
|
+
const a = x.#keys;
|
|
3073
|
+
const b = y.#keys;
|
|
3074
|
+
const ca = x.#conts;
|
|
3075
|
+
const cb = y.#conts;
|
|
3076
|
+
const keys = [];
|
|
3077
|
+
const conts = [];
|
|
3078
|
+
let size = 0;
|
|
3079
|
+
let i = 0;
|
|
3080
|
+
let j = 0;
|
|
3081
|
+
while (i < a.length && j < b.length) {
|
|
3082
|
+
const ka = a[i];
|
|
3083
|
+
const kb = b[j];
|
|
3084
|
+
if (ka === kb) {
|
|
3085
|
+
const c = freshPair(op, ca[i++], cb[j++]);
|
|
1808
3086
|
if (c !== null) {
|
|
1809
3087
|
keys.push(ka);
|
|
1810
3088
|
conts.push(c);
|
|
@@ -1814,14 +3092,16 @@ var TsBitmap = class _TsBitmap {
|
|
|
1814
3092
|
if (op === AND) {
|
|
1815
3093
|
i = gallopKeys(a, kb, i + 1);
|
|
1816
3094
|
} else {
|
|
3095
|
+
const c = ca[i++];
|
|
3096
|
+
c.shared = true;
|
|
1817
3097
|
keys.push(ka);
|
|
1818
|
-
conts.push(
|
|
1819
|
-
size +=
|
|
3098
|
+
conts.push(c);
|
|
3099
|
+
size += c.card;
|
|
1820
3100
|
}
|
|
1821
3101
|
} else if (op === AND) {
|
|
1822
3102
|
j = gallopKeys(b, ka, j + 1);
|
|
1823
3103
|
} else {
|
|
1824
|
-
if (op === OR) {
|
|
3104
|
+
if (op === OR || op === XOR) {
|
|
1825
3105
|
keys.push(kb);
|
|
1826
3106
|
conts.push(cloneContainer(cb[j]));
|
|
1827
3107
|
size += cb[j].card;
|
|
@@ -1831,23 +3111,29 @@ var TsBitmap = class _TsBitmap {
|
|
|
1831
3111
|
}
|
|
1832
3112
|
if (op !== AND) {
|
|
1833
3113
|
for (; i < a.length; i++) {
|
|
3114
|
+
const c = ca[i];
|
|
3115
|
+
c.shared = true;
|
|
1834
3116
|
keys.push(a[i]);
|
|
1835
|
-
conts.push(
|
|
1836
|
-
size +=
|
|
3117
|
+
conts.push(c);
|
|
3118
|
+
size += c.card;
|
|
1837
3119
|
}
|
|
1838
3120
|
}
|
|
1839
|
-
if (op === OR) {
|
|
3121
|
+
if (op === OR || op === XOR) {
|
|
1840
3122
|
for (; j < b.length; j++) {
|
|
1841
3123
|
keys.push(b[j]);
|
|
1842
3124
|
conts.push(cloneContainer(cb[j]));
|
|
1843
3125
|
size += cb[j].card;
|
|
1844
3126
|
}
|
|
1845
3127
|
}
|
|
1846
|
-
|
|
1847
|
-
this.#conts = conts;
|
|
1848
|
-
this.#size = size;
|
|
3128
|
+
return new _TsBitmap(keys, conts, size);
|
|
1849
3129
|
}
|
|
1850
3130
|
};
|
|
3131
|
+
function freshPair(op, a, b) {
|
|
3132
|
+
if (op === OR) return containerOr(a, b, false);
|
|
3133
|
+
if (op === AND) return containerAnd(a, b, false);
|
|
3134
|
+
if (op === AND_NOT) return containerAndNot(a, b, false);
|
|
3135
|
+
return containerXor(a, b, false);
|
|
3136
|
+
}
|
|
1851
3137
|
var EMPTIED = arrayContainer(new Uint16Array(0), 0);
|
|
1852
3138
|
var tsRoaringCodec = {
|
|
1853
3139
|
empty: () => TsBitmap.empty(),
|
|
@@ -1868,34 +3154,6 @@ var activeCodec = tsRoaringCodec;
|
|
|
1868
3154
|
function flagshipCodec() {
|
|
1869
3155
|
return activeCodec;
|
|
1870
3156
|
}
|
|
1871
|
-
var ReadonlyRoaringView = class {
|
|
1872
|
-
#bitmap;
|
|
1873
|
-
constructor(bitmap) {
|
|
1874
|
-
this.#bitmap = bitmap;
|
|
1875
|
-
}
|
|
1876
|
-
get size() {
|
|
1877
|
-
return this.#bitmap.size;
|
|
1878
|
-
}
|
|
1879
|
-
has(id) {
|
|
1880
|
-
return this.#bitmap.has(id);
|
|
1881
|
-
}
|
|
1882
|
-
[Symbol.iterator]() {
|
|
1883
|
-
return this.#bitmap[Symbol.iterator]();
|
|
1884
|
-
}
|
|
1885
|
-
/** The portable bytes, for exactly the argument `'portable'`; any other call is a `ValidationError`. */
|
|
1886
|
-
serialize(...args) {
|
|
1887
|
-
if (args.length !== 1 || args[0] !== "portable") {
|
|
1888
|
-
const got = args.length === 0 ? "no argument" : args.map((a) => typeof a === "string" ? `'${a}'` : typeof a).join(", ");
|
|
1889
|
-
throw new ValidationError3(
|
|
1890
|
-
`a decoded bitmap serializes only as serialize('portable'); got ${got}`
|
|
1891
|
-
);
|
|
1892
|
-
}
|
|
1893
|
-
return this.#bitmap.serialize();
|
|
1894
|
-
}
|
|
1895
|
-
};
|
|
1896
|
-
function deserializePortable(bytes) {
|
|
1897
|
-
return new ReadonlyRoaringView(decodeSerialized(bytes, flagshipCodec()));
|
|
1898
|
-
}
|
|
1899
3157
|
|
|
1900
3158
|
// src/system-clock.ts
|
|
1901
3159
|
var SystemClock = class {
|
|
@@ -2035,7 +3293,7 @@ import {
|
|
|
2035
3293
|
DEFAULT_RETRY_POLICY,
|
|
2036
3294
|
NOOP_METRICS,
|
|
2037
3295
|
RetryingStorageChunkSource,
|
|
2038
|
-
ValidationError as
|
|
3296
|
+
ValidationError as ValidationError3,
|
|
2039
3297
|
isStorageBackend
|
|
2040
3298
|
} from "@cloudbitmaps/core";
|
|
2041
3299
|
function resolveRetryPolicy(partial) {
|
|
@@ -2059,7 +3317,7 @@ function wireStore(options, clock, rng, metrics) {
|
|
|
2059
3317
|
if (options.retry !== false) {
|
|
2060
3318
|
const { onRetry: userOnRetry, ...ov } = options.retry ?? {};
|
|
2061
3319
|
if (userOnRetry !== void 0 && typeof userOnRetry !== "function") {
|
|
2062
|
-
throw new
|
|
3320
|
+
throw new ValidationError3("retry.onRetry must be a function");
|
|
2063
3321
|
}
|
|
2064
3322
|
retryOptions = {
|
|
2065
3323
|
clock,
|
|
@@ -2090,7 +3348,7 @@ function wireStore(options, clock, rng, metrics) {
|
|
|
2090
3348
|
function resolveStorageSource(options, clock) {
|
|
2091
3349
|
const storage = options.storage;
|
|
2092
3350
|
if (storage === null || typeof storage !== "object") {
|
|
2093
|
-
throw new
|
|
3351
|
+
throw new ValidationError3(
|
|
2094
3352
|
"`storage` must be a StorageBackend, an IStorageDriver, or a StorageChunkSource"
|
|
2095
3353
|
);
|
|
2096
3354
|
}
|
|
@@ -2100,14 +3358,14 @@ function resolveStorageSource(options, clock) {
|
|
|
2100
3358
|
const hasPutImmutable = typeof storage.putImmutable === "function";
|
|
2101
3359
|
const isBackend = isStorageBackend(storage);
|
|
2102
3360
|
if (isBackend && (hasGetChunk || hasPutImmutable)) {
|
|
2103
|
-
throw new
|
|
3361
|
+
throw new ValidationError3(
|
|
2104
3362
|
`\`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.`
|
|
2105
3363
|
);
|
|
2106
3364
|
}
|
|
2107
3365
|
const hasStorageHalf = isObject(asBackend.storage);
|
|
2108
3366
|
const hasRegistryHalf = isObject(asBackend.registry);
|
|
2109
3367
|
if (!isBackend && hasPutImmutable && hasRegistryHalf) {
|
|
2110
|
-
throw new
|
|
3368
|
+
throw new ValidationError3(
|
|
2111
3369
|
"`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`."
|
|
2112
3370
|
);
|
|
2113
3371
|
}
|
|
@@ -2116,11 +3374,11 @@ function resolveStorageSource(options, clock) {
|
|
|
2116
3374
|
const registryOk = typeof asBackend.registry.compareAndSwap === "function";
|
|
2117
3375
|
if (!storageOk || !registryOk) {
|
|
2118
3376
|
const bad = !storageOk ? "`storage` half is not an IStorageDriver (no `putImmutable`)" : "`registry` half is not an IRegistryDriver (no `compareAndSwap`)";
|
|
2119
|
-
throw new
|
|
3377
|
+
throw new ValidationError3(
|
|
2120
3378
|
"`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`."
|
|
2121
3379
|
);
|
|
2122
3380
|
}
|
|
2123
|
-
throw new
|
|
3381
|
+
throw new ValidationError3(
|
|
2124
3382
|
"`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."
|
|
2125
3383
|
);
|
|
2126
3384
|
}
|
|
@@ -2141,18 +3399,18 @@ function resolveStorageSource(options, clock) {
|
|
|
2141
3399
|
};
|
|
2142
3400
|
}
|
|
2143
3401
|
if (hasGetChunk && hasPutImmutable) {
|
|
2144
|
-
throw new
|
|
3402
|
+
throw new ValidationError3(
|
|
2145
3403
|
"`storage` exposes both `getChunk` and `putImmutable` \u2014 ambiguous; pass a StorageBackend, an IStorageDriver, or a StorageChunkSource, not a hybrid"
|
|
2146
3404
|
);
|
|
2147
3405
|
}
|
|
2148
3406
|
if (!hasGetChunk && !hasPutImmutable) {
|
|
2149
|
-
throw new
|
|
3407
|
+
throw new ValidationError3(
|
|
2150
3408
|
"`storage` must be a StorageBackend, an IStorageDriver, or a StorageChunkSource"
|
|
2151
3409
|
);
|
|
2152
3410
|
}
|
|
2153
3411
|
if (hasGetChunk) {
|
|
2154
3412
|
if (options.encryption?.keystore !== void 0 || options.encryption?.required === true) {
|
|
2155
|
-
throw new
|
|
3413
|
+
throw new ValidationError3(
|
|
2156
3414
|
"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"
|
|
2157
3415
|
);
|
|
2158
3416
|
}
|
|
@@ -2174,32 +3432,32 @@ function resolveStorageSource(options, clock) {
|
|
|
2174
3432
|
}
|
|
2175
3433
|
|
|
2176
3434
|
// src/options.ts
|
|
2177
|
-
import { ValidationError as
|
|
3435
|
+
import { ValidationError as ValidationError4 } from "@cloudbitmaps/core";
|
|
2178
3436
|
var keysOf = () => (keys) => keys;
|
|
2179
3437
|
var kindOf = (v) => v === null ? "null" : Array.isArray(v) ? "an array" : `a ${typeof v}`;
|
|
2180
3438
|
function optionsError(options, op, known, booleans = [], misplaced = []) {
|
|
2181
3439
|
if (options === void 0 || options === null) return void 0;
|
|
2182
3440
|
if (typeof options !== "object" || Array.isArray(options)) {
|
|
2183
|
-
return new
|
|
3441
|
+
return new ValidationError4(`${op}: options must be an object; got ${kindOf(options)}`);
|
|
2184
3442
|
}
|
|
2185
3443
|
const bag = options;
|
|
2186
3444
|
const unknown = Object.keys(bag).filter((k) => !known.includes(k) && bag[k] !== void 0);
|
|
2187
3445
|
for (const k of misplaced) if (!unknown.includes(k) && bag[k] !== void 0) unknown.push(k);
|
|
2188
3446
|
if (unknown.length > 0) {
|
|
2189
|
-
return new
|
|
3447
|
+
return new ValidationError4(
|
|
2190
3448
|
`${op}: unknown option${unknown.length > 1 ? "s" : ""} ${unknown.map((k) => `"${k}"`).join(", ")}; it takes { ${known.join(", ")} }`
|
|
2191
3449
|
);
|
|
2192
3450
|
}
|
|
2193
3451
|
const audit = bag.audit;
|
|
2194
3452
|
if (audit !== void 0 && audit !== null && typeof audit.onEvent !== "function") {
|
|
2195
|
-
return new
|
|
3453
|
+
return new ValidationError4(
|
|
2196
3454
|
`${op}: audit must be a sink with an onEvent(event) method, such as a RecordingAuditSink`
|
|
2197
3455
|
);
|
|
2198
3456
|
}
|
|
2199
3457
|
for (const name of booleans) {
|
|
2200
3458
|
const v = bag[name];
|
|
2201
3459
|
if (v !== void 0 && typeof v !== "boolean") {
|
|
2202
|
-
return new
|
|
3460
|
+
return new ValidationError4(`${op}: \`${name}\` must be a boolean; got ${kindOf(v)}`);
|
|
2203
3461
|
}
|
|
2204
3462
|
}
|
|
2205
3463
|
return void 0;
|
|
@@ -2220,6 +3478,407 @@ function checkOptions(options, op, known, booleans, misplaced) {
|
|
|
2220
3478
|
|
|
2221
3479
|
// src/index.ts
|
|
2222
3480
|
import { MemoryStorage, LocalFsStorage, InProcessKeystore } from "@cloudbitmaps/core/node";
|
|
3481
|
+
|
|
3482
|
+
// src/bitmap.ts
|
|
3483
|
+
import {
|
|
3484
|
+
MAX_SERIALIZED_LOAD_BYTES,
|
|
3485
|
+
ValidationError as ValidationError5,
|
|
3486
|
+
decodeSerialized,
|
|
3487
|
+
refusalOfId as refusalOfId2
|
|
3488
|
+
} from "@cloudbitmaps/core";
|
|
3489
|
+
|
|
3490
|
+
// src/count-route.ts
|
|
3491
|
+
var COUNT_BY_KERNELS = true;
|
|
3492
|
+
|
|
3493
|
+
// src/bitmap.ts
|
|
3494
|
+
function tagOf(value) {
|
|
3495
|
+
return Object.prototype.toString.call(value).slice(8, -1);
|
|
3496
|
+
}
|
|
3497
|
+
var VIEW = Object.getPrototypeOf(Uint8Array.prototype);
|
|
3498
|
+
var viewGetter = (name) => Object.getOwnPropertyDescriptor(VIEW, name)?.get;
|
|
3499
|
+
var bufferOf = viewGetter("buffer");
|
|
3500
|
+
var plainByteLength = Object.getOwnPropertyDescriptor(ArrayBuffer.prototype, "byteLength")?.get;
|
|
3501
|
+
var hasSharedMemory = typeof SharedArrayBuffer === "function";
|
|
3502
|
+
function inSharedMemory(ids) {
|
|
3503
|
+
if (!hasSharedMemory) return false;
|
|
3504
|
+
try {
|
|
3505
|
+
plainByteLength.call(bufferOf.call(ids));
|
|
3506
|
+
return false;
|
|
3507
|
+
} catch {
|
|
3508
|
+
return true;
|
|
3509
|
+
}
|
|
3510
|
+
}
|
|
3511
|
+
function checkedId2(id) {
|
|
3512
|
+
if (typeof id !== "number" || id >>> 0 !== id) throw refusalOfId2(id);
|
|
3513
|
+
return id;
|
|
3514
|
+
}
|
|
3515
|
+
function oneIdOnly(method, bulk) {
|
|
3516
|
+
return new ValidationError5(`${method} takes one id; use ${bulk} for several`);
|
|
3517
|
+
}
|
|
3518
|
+
function idsOf(values) {
|
|
3519
|
+
if (typeof values !== "object" || values === null || !(Symbol.iterator in values)) {
|
|
3520
|
+
throw new ValidationError5("values must be an iterable of ids");
|
|
3521
|
+
}
|
|
3522
|
+
const tag = tagOf(values);
|
|
3523
|
+
if (tag === "Uint8Array" || tag === "Uint8ClampedArray") {
|
|
3524
|
+
throw new ValidationError5(
|
|
3525
|
+
`values are ids, and this is a ${tag === "Uint8Array" ? "Uint8Array or Buffer" : tag}: each byte would be read as an id. To read portable bytes, call RoaringBitmap.deserialize(bytes).`
|
|
3526
|
+
);
|
|
3527
|
+
}
|
|
3528
|
+
if (values instanceof Uint32Array && inSharedMemory(values)) return new Uint32Array(values);
|
|
3529
|
+
return values;
|
|
3530
|
+
}
|
|
3531
|
+
var detachedCodec = {
|
|
3532
|
+
...tsRoaringCodec,
|
|
3533
|
+
safeDeserialize: (bytes, maxBytes, options) => TsBitmap.safeDeserialize(bytes, maxBytes, { ...options, detached: true })
|
|
3534
|
+
};
|
|
3535
|
+
function maxBytesOf(options) {
|
|
3536
|
+
if (options === void 0) return MAX_SERIALIZED_LOAD_BYTES;
|
|
3537
|
+
if (typeof options !== "object" || options === null) {
|
|
3538
|
+
throw new ValidationError5(
|
|
3539
|
+
`deserialize takes no format argument, the format is always portable; its second argument is { maxBytes } or nothing, not ${kindOf(options)}`
|
|
3540
|
+
);
|
|
3541
|
+
}
|
|
3542
|
+
checkOptions(options, "RoaringBitmap.deserialize", ["maxBytes"]);
|
|
3543
|
+
const { maxBytes } = picked(options, ["maxBytes"]);
|
|
3544
|
+
if (maxBytes === void 0) return MAX_SERIALIZED_LOAD_BYTES;
|
|
3545
|
+
if (!Number.isInteger(maxBytes) || maxBytes < 0 || maxBytes > MAX_SERIALIZED_LOAD_BYTES) {
|
|
3546
|
+
throw new ValidationError5(
|
|
3547
|
+
`maxBytes must be an integer from 0 to ${MAX_SERIALIZED_LOAD_BYTES}, the size no canonical bitmap exceeds`
|
|
3548
|
+
);
|
|
3549
|
+
}
|
|
3550
|
+
return maxBytes;
|
|
3551
|
+
}
|
|
3552
|
+
var RoaringBitmap = class _RoaringBitmap {
|
|
3553
|
+
#bitmap;
|
|
3554
|
+
/**
|
|
3555
|
+
* A bitmap of `values`: an array or another iterable of ids, a `Uint32Array` (read in place when it already ascends,
|
|
3556
|
+
* else sorted on a copy; it is never changed or kept), or another `RoaringBitmap` (a copy-on-write `clone()`).
|
|
3557
|
+
* With no argument it is empty.
|
|
3558
|
+
*
|
|
3559
|
+
* @throws {ValidationError} for an id that is not an integer from 0 to 4294967295; for a value that is not an
|
|
3560
|
+
* iterable (`null`, a number, a string, an object, an `ArrayBuffer`); and for a `Uint8Array`, `Uint8ClampedArray` or
|
|
3561
|
+
* `Buffer`, which would read each byte as an id: call {@link RoaringBitmap.deserialize} for bytes.
|
|
3562
|
+
*/
|
|
3563
|
+
constructor(values) {
|
|
3564
|
+
if (values === void 0) {
|
|
3565
|
+
this.#bitmap = TsBitmap.empty();
|
|
3566
|
+
} else if (_RoaringBitmap.#is(values)) {
|
|
3567
|
+
this.#bitmap = values.#bitmap.clone();
|
|
3568
|
+
} else {
|
|
3569
|
+
this.#bitmap = TsBitmap.fromValues(idsOf(values));
|
|
3570
|
+
}
|
|
3571
|
+
}
|
|
3572
|
+
/**
|
|
3573
|
+
* Decode portable Roaring bytes you hold, through the check a `{ serialized }` load makes first: a size cap, a
|
|
3574
|
+
* structural check and one whole bitmap, and only then the decoder. The result owns its storage: it keeps nothing
|
|
3575
|
+
* of `bytes`, so a large input that is decoded and then reduced can be freed.
|
|
3576
|
+
*
|
|
3577
|
+
* @param bytes a `Uint8Array`, which a Node `Buffer` is.
|
|
3578
|
+
* @param options `{ maxBytes }` lowers the size cap below the default of 537,403,396 bytes.
|
|
3579
|
+
* @throws {ValidationError} for something that is not a `Uint8Array`; an empty or detached one (an empty buffer is
|
|
3580
|
+
* not a bitmap: `new RoaringBitmap()` is the empty set); one over the cap or `maxBytes`; bytes that are not exactly
|
|
3581
|
+
* one well-formed portable bitmap, including bytes after its last container; a second argument that is not
|
|
3582
|
+
* `undefined` or an object whose only key is `maxBytes` (a format argument such as `'portable'` is one); and a
|
|
3583
|
+
* `maxBytes` that is not an integer from 0 to the cap.
|
|
3584
|
+
*/
|
|
3585
|
+
static deserialize(bytes, options) {
|
|
3586
|
+
const maxBytes = maxBytesOf(options);
|
|
3587
|
+
return _RoaringBitmap.#wrap(
|
|
3588
|
+
decodeSerialized(bytes, detachedCodec, "the buffer", {
|
|
3589
|
+
maxBytes,
|
|
3590
|
+
refuseEmpty: true
|
|
3591
|
+
})
|
|
3592
|
+
);
|
|
3593
|
+
}
|
|
3594
|
+
/** Whether `value` is a `RoaringBitmap` of this copy of the package. */
|
|
3595
|
+
static #is(value) {
|
|
3596
|
+
return typeof value === "object" && value !== null && #bitmap in value;
|
|
3597
|
+
}
|
|
3598
|
+
static #wrap(bitmap) {
|
|
3599
|
+
const out = new _RoaringBitmap();
|
|
3600
|
+
out.#bitmap = bitmap;
|
|
3601
|
+
return out;
|
|
3602
|
+
}
|
|
3603
|
+
/** The codec bitmap of an operand, or a refusal that says what combines with what. */
|
|
3604
|
+
static #operand(other) {
|
|
3605
|
+
if (!_RoaringBitmap.#is(other)) {
|
|
3606
|
+
throw new ValidationError5(
|
|
3607
|
+
"a RoaringBitmap combines only with another RoaringBitmap of this copy of the package"
|
|
3608
|
+
);
|
|
3609
|
+
}
|
|
3610
|
+
return other.#bitmap;
|
|
3611
|
+
}
|
|
3612
|
+
/** How many ids it holds. */
|
|
3613
|
+
get size() {
|
|
3614
|
+
return this.#bitmap.size;
|
|
3615
|
+
}
|
|
3616
|
+
/** Whether it holds no id. */
|
|
3617
|
+
get isEmpty() {
|
|
3618
|
+
return this.#bitmap.isEmpty;
|
|
3619
|
+
}
|
|
3620
|
+
/**
|
|
3621
|
+
* Whether it holds `id`.
|
|
3622
|
+
*
|
|
3623
|
+
* @throws {ValidationError} for a value that is not an integer from 0 to 4294967295.
|
|
3624
|
+
*/
|
|
3625
|
+
has(id) {
|
|
3626
|
+
return this.#bitmap.has(checkedId2(id));
|
|
3627
|
+
}
|
|
3628
|
+
/** The smallest id, or `undefined` when it is empty. */
|
|
3629
|
+
minimum() {
|
|
3630
|
+
return this.#bitmap.minimum();
|
|
3631
|
+
}
|
|
3632
|
+
/** The largest id, or `undefined` when it is empty. */
|
|
3633
|
+
maximum() {
|
|
3634
|
+
return this.#bitmap.maximum();
|
|
3635
|
+
}
|
|
3636
|
+
/**
|
|
3637
|
+
* Add one id; returns this bitmap, for chaining.
|
|
3638
|
+
*
|
|
3639
|
+
* @throws {ValidationError} for a value that is not an integer from 0 to 4294967295, and for a second argument:
|
|
3640
|
+
* use {@link RoaringBitmap.addMany} to add several.
|
|
3641
|
+
*/
|
|
3642
|
+
add(id) {
|
|
3643
|
+
if (arguments.length !== 1) throw oneIdOnly("add", "addMany");
|
|
3644
|
+
this.#bitmap.add(checkedId2(id));
|
|
3645
|
+
return this;
|
|
3646
|
+
}
|
|
3647
|
+
/**
|
|
3648
|
+
* Add every id of `values` (an iterable of ids, or a `Uint32Array`); returns this bitmap. Nothing is added if any
|
|
3649
|
+
* of them is refused.
|
|
3650
|
+
*
|
|
3651
|
+
* @throws {ValidationError} as the constructor does.
|
|
3652
|
+
*/
|
|
3653
|
+
addMany(values) {
|
|
3654
|
+
if (_RoaringBitmap.#is(values)) this.#bitmap.orInPlace(values.#bitmap);
|
|
3655
|
+
else this.#bitmap.addMany(idsOf(values));
|
|
3656
|
+
return this;
|
|
3657
|
+
}
|
|
3658
|
+
/**
|
|
3659
|
+
* Remove one id; whether it was there.
|
|
3660
|
+
*
|
|
3661
|
+
* @throws {ValidationError} for a value that is not an integer from 0 to 4294967295, and for a second argument:
|
|
3662
|
+
* use {@link RoaringBitmap.removeMany} to remove several.
|
|
3663
|
+
*/
|
|
3664
|
+
remove(id) {
|
|
3665
|
+
if (arguments.length !== 1) throw oneIdOnly("remove", "removeMany");
|
|
3666
|
+
return this.#bitmap.remove(checkedId2(id));
|
|
3667
|
+
}
|
|
3668
|
+
/**
|
|
3669
|
+
* Remove every id of `values` (an iterable of ids, or a `Uint32Array`); returns this bitmap. Nothing is removed if
|
|
3670
|
+
* any of them is refused.
|
|
3671
|
+
*
|
|
3672
|
+
* @throws {ValidationError} as the constructor does.
|
|
3673
|
+
*/
|
|
3674
|
+
removeMany(values) {
|
|
3675
|
+
if (_RoaringBitmap.#is(values)) this.#bitmap.andNotInPlace(values.#bitmap);
|
|
3676
|
+
else this.#bitmap.removeMany(collect(idsOf(values)));
|
|
3677
|
+
return this;
|
|
3678
|
+
}
|
|
3679
|
+
/** Remove every id. */
|
|
3680
|
+
clear() {
|
|
3681
|
+
this.#bitmap.clear();
|
|
3682
|
+
}
|
|
3683
|
+
/**
|
|
3684
|
+
* A copy. It is copy-on-write: the copy costs the key list and one flag per container, not the ids, and the first
|
|
3685
|
+
* write to a container on either side copies that container once.
|
|
3686
|
+
*/
|
|
3687
|
+
clone() {
|
|
3688
|
+
return _RoaringBitmap.#wrap(this.#bitmap.clone());
|
|
3689
|
+
}
|
|
3690
|
+
/**
|
|
3691
|
+
* Keep only the ids `other` also holds; returns this bitmap. `other` is not changed, and may be this bitmap.
|
|
3692
|
+
*
|
|
3693
|
+
* @throws {ValidationError} if `other` is not a `RoaringBitmap` of this copy of the package.
|
|
3694
|
+
*/
|
|
3695
|
+
andInPlace(other) {
|
|
3696
|
+
this.#bitmap.andInPlace(_RoaringBitmap.#operand(other));
|
|
3697
|
+
return this;
|
|
3698
|
+
}
|
|
3699
|
+
/**
|
|
3700
|
+
* Add the ids `other` holds; returns this bitmap. `other` is not changed, and may be this bitmap.
|
|
3701
|
+
*
|
|
3702
|
+
* @throws {ValidationError} if `other` is not a `RoaringBitmap` of this copy of the package.
|
|
3703
|
+
*/
|
|
3704
|
+
orInPlace(other) {
|
|
3705
|
+
this.#bitmap.orInPlace(_RoaringBitmap.#operand(other));
|
|
3706
|
+
return this;
|
|
3707
|
+
}
|
|
3708
|
+
/**
|
|
3709
|
+
* Remove the ids `other` holds; returns this bitmap. `other` is not changed, and may be this bitmap.
|
|
3710
|
+
*
|
|
3711
|
+
* @throws {ValidationError} if `other` is not a `RoaringBitmap` of this copy of the package.
|
|
3712
|
+
*/
|
|
3713
|
+
andNotInPlace(other) {
|
|
3714
|
+
this.#bitmap.andNotInPlace(_RoaringBitmap.#operand(other));
|
|
3715
|
+
return this;
|
|
3716
|
+
}
|
|
3717
|
+
/**
|
|
3718
|
+
* Flip the ids `other` holds: keep those only this bitmap holds, add those only `other` holds; returns this bitmap.
|
|
3719
|
+
* `other` is not changed, and may be this bitmap (the result is then empty).
|
|
3720
|
+
*
|
|
3721
|
+
* @throws {ValidationError} if `other` is not a `RoaringBitmap` of this copy of the package.
|
|
3722
|
+
*/
|
|
3723
|
+
xorInPlace(other) {
|
|
3724
|
+
this.#bitmap.xorInPlace(_RoaringBitmap.#operand(other));
|
|
3725
|
+
return this;
|
|
3726
|
+
}
|
|
3727
|
+
/**
|
|
3728
|
+
* How many ids both bitmaps hold, without building the intersection. Neither bitmap changes; `other` may be this one.
|
|
3729
|
+
*
|
|
3730
|
+
* @throws {ValidationError} if `other` is not a `RoaringBitmap` of this copy of the package.
|
|
3731
|
+
*/
|
|
3732
|
+
andCardinality(other) {
|
|
3733
|
+
const that = _RoaringBitmap.#operand(other);
|
|
3734
|
+
return COUNT_BY_KERNELS ? this.#bitmap.andCardinality(that) : TsBitmap.and(this.#bitmap, that).size;
|
|
3735
|
+
}
|
|
3736
|
+
/**
|
|
3737
|
+
* How many ids either bitmap holds. Neither bitmap changes; `other` may be this one.
|
|
3738
|
+
*
|
|
3739
|
+
* @throws {ValidationError} if `other` is not a `RoaringBitmap` of this copy of the package.
|
|
3740
|
+
*/
|
|
3741
|
+
orCardinality(other) {
|
|
3742
|
+
const that = _RoaringBitmap.#operand(other);
|
|
3743
|
+
return COUNT_BY_KERNELS ? this.#bitmap.orCardinality(that) : TsBitmap.or(this.#bitmap, that).size;
|
|
3744
|
+
}
|
|
3745
|
+
/**
|
|
3746
|
+
* How many ids exactly one of the bitmaps holds. Neither bitmap changes; `other` may be this one.
|
|
3747
|
+
*
|
|
3748
|
+
* @throws {ValidationError} if `other` is not a `RoaringBitmap` of this copy of the package.
|
|
3749
|
+
*/
|
|
3750
|
+
xorCardinality(other) {
|
|
3751
|
+
const that = _RoaringBitmap.#operand(other);
|
|
3752
|
+
return COUNT_BY_KERNELS ? this.#bitmap.xorCardinality(that) : TsBitmap.xor(this.#bitmap, that).size;
|
|
3753
|
+
}
|
|
3754
|
+
/**
|
|
3755
|
+
* How many ids this bitmap holds that `other` lacks. Neither bitmap changes; `other` may be this one.
|
|
3756
|
+
*
|
|
3757
|
+
* @throws {ValidationError} if `other` is not a `RoaringBitmap` of this copy of the package.
|
|
3758
|
+
*/
|
|
3759
|
+
andNotCardinality(other) {
|
|
3760
|
+
const that = _RoaringBitmap.#operand(other);
|
|
3761
|
+
return COUNT_BY_KERNELS ? this.#bitmap.andNotCardinality(that) : TsBitmap.andNot(this.#bitmap, that).size;
|
|
3762
|
+
}
|
|
3763
|
+
/**
|
|
3764
|
+
* Whether the bitmaps share an id. Neither bitmap changes; `other` may be this one.
|
|
3765
|
+
*
|
|
3766
|
+
* @throws {ValidationError} if `other` is not a `RoaringBitmap` of this copy of the package.
|
|
3767
|
+
*/
|
|
3768
|
+
intersects(other) {
|
|
3769
|
+
const that = _RoaringBitmap.#operand(other);
|
|
3770
|
+
return COUNT_BY_KERNELS ? this.#bitmap.intersects(that) : !TsBitmap.and(this.#bitmap, that).isEmpty;
|
|
3771
|
+
}
|
|
3772
|
+
/**
|
|
3773
|
+
* Whether every id of this bitmap is in `other` (an empty bitmap is a subset of every bitmap, itself included). Neither
|
|
3774
|
+
* bitmap changes. Unlike the `roaring` package, which answers `false`, a value that is not a bitmap is refused.
|
|
3775
|
+
*
|
|
3776
|
+
* @throws {ValidationError} if `other` is not a `RoaringBitmap` of this copy of the package.
|
|
3777
|
+
*/
|
|
3778
|
+
isSubset(other) {
|
|
3779
|
+
return this.#bitmap.isSubset(_RoaringBitmap.#operand(other));
|
|
3780
|
+
}
|
|
3781
|
+
/**
|
|
3782
|
+
* Whether both bitmaps hold exactly the same ids, whatever the kinds of their containers or the bytes they would
|
|
3783
|
+
* serialize to. Neither bitmap changes.
|
|
3784
|
+
*
|
|
3785
|
+
* @throws {ValidationError} if `other` is not a `RoaringBitmap` of this copy of the package.
|
|
3786
|
+
*/
|
|
3787
|
+
isEqual(other) {
|
|
3788
|
+
return this.#bitmap.isEqual(_RoaringBitmap.#operand(other));
|
|
3789
|
+
}
|
|
3790
|
+
/**
|
|
3791
|
+
* The ids both bitmaps hold, as a new bitmap. Neither operand changes, and the result holds storage of its own.
|
|
3792
|
+
*
|
|
3793
|
+
* @throws {ValidationError} if an operand is not a `RoaringBitmap` of this copy of the package.
|
|
3794
|
+
*/
|
|
3795
|
+
static and(a, b) {
|
|
3796
|
+
return _RoaringBitmap.#wrap(TsBitmap.and(_RoaringBitmap.#operand(a), _RoaringBitmap.#operand(b)));
|
|
3797
|
+
}
|
|
3798
|
+
/**
|
|
3799
|
+
* The ids either bitmap holds, as a new bitmap. Neither operand changes. A container only `a` holds is shared with
|
|
3800
|
+
* the result copy-on-write, so the next write to it, on either side, copies it once.
|
|
3801
|
+
*
|
|
3802
|
+
* @throws {ValidationError} if an operand is not a `RoaringBitmap` of this copy of the package.
|
|
3803
|
+
*/
|
|
3804
|
+
static or(a, b) {
|
|
3805
|
+
return _RoaringBitmap.#wrap(TsBitmap.or(_RoaringBitmap.#operand(a), _RoaringBitmap.#operand(b)));
|
|
3806
|
+
}
|
|
3807
|
+
/**
|
|
3808
|
+
* The ids exactly one of the bitmaps holds, as a new bitmap. Neither operand changes (see {@link RoaringBitmap.or}
|
|
3809
|
+
* for what is shared).
|
|
3810
|
+
*
|
|
3811
|
+
* @throws {ValidationError} if an operand is not a `RoaringBitmap` of this copy of the package.
|
|
3812
|
+
*/
|
|
3813
|
+
static xor(a, b) {
|
|
3814
|
+
return _RoaringBitmap.#wrap(TsBitmap.xor(_RoaringBitmap.#operand(a), _RoaringBitmap.#operand(b)));
|
|
3815
|
+
}
|
|
3816
|
+
/**
|
|
3817
|
+
* The ids of `a` that `b` lacks, as a new bitmap. Neither operand changes (see {@link RoaringBitmap.or} for what is
|
|
3818
|
+
* shared).
|
|
3819
|
+
*
|
|
3820
|
+
* @throws {ValidationError} if an operand is not a `RoaringBitmap` of this copy of the package.
|
|
3821
|
+
*/
|
|
3822
|
+
static andNot(a, b) {
|
|
3823
|
+
return _RoaringBitmap.#wrap(
|
|
3824
|
+
TsBitmap.andNot(_RoaringBitmap.#operand(a), _RoaringBitmap.#operand(b))
|
|
3825
|
+
);
|
|
3826
|
+
}
|
|
3827
|
+
/**
|
|
3828
|
+
* The union of every bitmap of `bitmaps`, as a new bitmap that owns its storage (an empty list gives the empty set).
|
|
3829
|
+
* No operand changes, and none is flagged: the result accumulates in containers of its own.
|
|
3830
|
+
*
|
|
3831
|
+
* @throws {ValidationError} if `bitmaps` is not an iterable, or holds anything that is not a `RoaringBitmap` of this
|
|
3832
|
+
* copy of the package; nothing is combined then.
|
|
3833
|
+
*/
|
|
3834
|
+
static orMany(bitmaps) {
|
|
3835
|
+
if (typeof bitmaps !== "object" || bitmaps === null || !(Symbol.iterator in bitmaps)) {
|
|
3836
|
+
throw new ValidationError5("orMany takes an iterable of RoaringBitmap");
|
|
3837
|
+
}
|
|
3838
|
+
const parts = Array.from(bitmaps, (b) => _RoaringBitmap.#operand(b));
|
|
3839
|
+
return _RoaringBitmap.#wrap(TsBitmap.orMany(parts));
|
|
3840
|
+
}
|
|
3841
|
+
/** The ids in ascending order, each once. A bitmap that changes during the walk gives unspecified ids, and no error. */
|
|
3842
|
+
[Symbol.iterator]() {
|
|
3843
|
+
return this.#bitmap[Symbol.iterator]();
|
|
3844
|
+
}
|
|
3845
|
+
/** The ids as a new ascending array. A bitmap too large to allocate as one throws the runtime's `RangeError`. */
|
|
3846
|
+
toArray() {
|
|
3847
|
+
return this.#bitmap.toArray();
|
|
3848
|
+
}
|
|
3849
|
+
/** The ids as a new ascending `Uint32Array` the caller owns, never a view of the bitmap's storage. */
|
|
3850
|
+
toUint32Array() {
|
|
3851
|
+
return this.#bitmap.toUint32Array();
|
|
3852
|
+
}
|
|
3853
|
+
/**
|
|
3854
|
+
* The portable Roaring bytes, in a new `Uint8Array`. Call {@link RoaringBitmap.runOptimize} first when the bitmap was
|
|
3855
|
+
* decoded from bytes another writer made: its run containers stay as they were, and a bitmap that serializes over
|
|
3856
|
+
* the size cap is refused by a load.
|
|
3857
|
+
*
|
|
3858
|
+
* @param format `'portable'`, the only format there is, or nothing.
|
|
3859
|
+
* @throws {ValidationError} for any other argument.
|
|
3860
|
+
*/
|
|
3861
|
+
serialize(format) {
|
|
3862
|
+
if (format !== void 0 && format !== "portable") {
|
|
3863
|
+
throw new ValidationError5(
|
|
3864
|
+
`a bitmap serializes only as serialize() or serialize('portable'); got ${kindOf(format)}`
|
|
3865
|
+
);
|
|
3866
|
+
}
|
|
3867
|
+
return this.#bitmap.serialize();
|
|
3868
|
+
}
|
|
3869
|
+
/**
|
|
3870
|
+
* Re-encode every container in the smallest form (a run container only where it is strictly smaller than the plain
|
|
3871
|
+
* one), so `serialize()` afterwards depends on the set alone. Membership is unchanged.
|
|
3872
|
+
*
|
|
3873
|
+
* @returns whether the bitmap holds at least one run container afterwards, not whether anything changed.
|
|
3874
|
+
*/
|
|
3875
|
+
runOptimize() {
|
|
3876
|
+
this.#bitmap.optimize();
|
|
3877
|
+
return this.#bitmap.hasRunContainer();
|
|
3878
|
+
}
|
|
3879
|
+
};
|
|
3880
|
+
|
|
3881
|
+
// src/index.ts
|
|
2223
3882
|
import {
|
|
2224
3883
|
excludingReservedRows as excludingReservedRows2,
|
|
2225
3884
|
readRetentionPolicy,
|
|
@@ -2314,6 +3973,29 @@ var CALL_KEYS = {
|
|
|
2314
3973
|
"allowAbsentOperands",
|
|
2315
3974
|
"exclude"
|
|
2316
3975
|
]),
|
|
3976
|
+
intersectCount: keysOf()([
|
|
3977
|
+
"after",
|
|
3978
|
+
"through",
|
|
3979
|
+
"concurrency",
|
|
3980
|
+
"budget",
|
|
3981
|
+
"allowAbsentOperands",
|
|
3982
|
+
"exclude"
|
|
3983
|
+
]),
|
|
3984
|
+
unionCount: keysOf()([
|
|
3985
|
+
"after",
|
|
3986
|
+
"through",
|
|
3987
|
+
"concurrency",
|
|
3988
|
+
"budget",
|
|
3989
|
+
"allowAbsentOperands",
|
|
3990
|
+
"exclude"
|
|
3991
|
+
]),
|
|
3992
|
+
andNotCount: keysOf()([
|
|
3993
|
+
"after",
|
|
3994
|
+
"through",
|
|
3995
|
+
"concurrency",
|
|
3996
|
+
"budget",
|
|
3997
|
+
"allowAbsentOperands"
|
|
3998
|
+
]),
|
|
2317
3999
|
into: keysOf()([
|
|
2318
4000
|
"after",
|
|
2319
4001
|
"through",
|
|
@@ -2391,6 +4073,9 @@ var MISPLACED = {
|
|
|
2391
4073
|
range: outside(CALL_KEYS.into, CALL_KEYS.range),
|
|
2392
4074
|
andNot: outside(CALL_KEYS.into, CALL_KEYS.andNot),
|
|
2393
4075
|
combine: outside(CALL_KEYS.into, CALL_KEYS.combine),
|
|
4076
|
+
intersectCount: outside(CALL_KEYS.into, CALL_KEYS.intersectCount),
|
|
4077
|
+
unionCount: outside(CALL_KEYS.into, CALL_KEYS.unionCount),
|
|
4078
|
+
andNotCount: outside(CALL_KEYS.into, CALL_KEYS.andNotCount),
|
|
2394
4079
|
andNotInto: outside(CALL_KEYS.into, CALL_KEYS.andNotInto),
|
|
2395
4080
|
exportSegments: ["codec"]
|
|
2396
4081
|
};
|
|
@@ -3494,8 +5179,8 @@ var CloudRoaring = class _CloudRoaring {
|
|
|
3494
5179
|
* with `serialize('portable')` such as `roaring`'s `RoaringBitmap32`, or `{ serialized }`, portable Roaring bytes.
|
|
3495
5180
|
* A bitmap is checked (size cap, structure, safe deserializer) before the first request, written from its own
|
|
3496
5181
|
* containers with no per-id work, and gives the generation chunk for chunk what its ids would. An
|
|
3497
|
-
* iterable with a `serialize` method (a `RoaringBitmap32`, another copy's bitmap, or a
|
|
3498
|
-
*
|
|
5182
|
+
* iterable with a `serialize` method (a `RoaringBitmap32`, another copy's bitmap, or a `RoaringBitmap`
|
|
5183
|
+
* of this package) passed as ids loads as `{ bitmap }` and is not iterated. A `Uint8Array` or `Buffer` passed as ids is
|
|
3499
5184
|
* refused with `ValidationError`, since each byte would load as an id, even when it has a `serialize` of its own:
|
|
3500
5185
|
* pass bytes as `{ serialized }`.
|
|
3501
5186
|
*
|
|
@@ -4101,7 +5786,7 @@ var CloudRoaring = class _CloudRoaring {
|
|
|
4101
5786
|
/**
|
|
4102
5787
|
* **Export ("eject") every registered segment's current generation** through the injected `sink`, using only
|
|
4103
5788
|
* public read APIs — so your data is readable **without CloudRoaring** (the exit path; see the README's "Your
|
|
4104
|
-
* data stays yours"). `format: 'roaring'` (default) writes one **portable
|
|
5789
|
+
* data stays yours"). `format: 'roaring'` (default) writes one **portable Roaring bitmap** per segment
|
|
4105
5790
|
* (loadable by any roaring library); `'ndjson'` writes newline-delimited ids (zero-dependency, streaming).
|
|
4106
5791
|
* Enumerates via the store's **own** registry (needs one — throws {@link UnsupportedError} otherwise) so the
|
|
4107
5792
|
* enumeration and the read path provably share one registry. Encrypted segments are decrypted transparently
|
|
@@ -4157,7 +5842,7 @@ function operandsLabel(verb) {
|
|
|
4157
5842
|
}
|
|
4158
5843
|
function refuseNoOperands(verb) {
|
|
4159
5844
|
throw new ValidationError6(
|
|
4160
|
-
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 })"
|
|
5845
|
+
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 })"
|
|
4161
5846
|
);
|
|
4162
5847
|
}
|
|
4163
5848
|
var AS_IDS = {
|
|
@@ -4867,6 +6552,111 @@ var Segment = class _Segment {
|
|
|
4867
6552
|
);
|
|
4868
6553
|
return this.combineInto("andNotInto", dest, excludes, options);
|
|
4869
6554
|
}
|
|
6555
|
+
/**
|
|
6556
|
+
* How many ids `this ∩ others…` holds (minus `exclude`): the length of what {@link intersect} streams, without
|
|
6557
|
+
* streaming it. Every key all the operands hold is decoded and counted as the stream reads it, and a key only some
|
|
6558
|
+
* operands hold is not read, so the call makes the requests {@link intersect} makes and returns a number instead of
|
|
6559
|
+
* the ids. It is exact: it never answers a key from an index, so it trusts nothing {@link count} trusts.
|
|
6560
|
+
*
|
|
6561
|
+
* The range, `concurrency`, `budget`, `allowAbsentOperands` and `exclude` are {@link intersect}'s; a write option fails
|
|
6562
|
+
* the call with {@link ValidationError} before any request, and so does an empty `others` (to count one segment, use
|
|
6563
|
+
* {@link count}).
|
|
6564
|
+
*
|
|
6565
|
+
* Like a stream, a count that runs while a segment is erased or reloaded can describe two instants, within the bound
|
|
6566
|
+
* the streams state. A union or a difference, and an intersection with an `exclude`, looks at its operands'
|
|
6567
|
+
* generations every `concurrency` keys; an intersection with no `exclude` makes no such look, since it decodes every
|
|
6568
|
+
* key and so shows a move in the chunks it decodes, as its stream does. Either way it plans again above the last key
|
|
6569
|
+
* it took when one moved. A pinned handle counts the generation it pinned, and each pinned operand's object is
|
|
6570
|
+
* looked up once before the first key (one footer read each, which `budget` does not charge, and which the stream
|
|
6571
|
+
* does not make), and again at each look where there is one, so an erasure of what it pinned fails the count with
|
|
6572
|
+
* {@link NotFoundError}; a
|
|
6573
|
+
* fault the look meets other than a transient one, which is retried, is raised as it is. A call that involves a
|
|
6574
|
+
* handle whose lease has ended, or has ended by the next look, throws {@link LeaseExpiredError}.
|
|
6575
|
+
*/
|
|
6576
|
+
async intersectCount(others, options) {
|
|
6577
|
+
checkOptions(
|
|
6578
|
+
options,
|
|
6579
|
+
"intersectCount",
|
|
6580
|
+
CALL_KEYS.intersectCount,
|
|
6581
|
+
["allowAbsentOperands"],
|
|
6582
|
+
MISPLACED.intersectCount
|
|
6583
|
+
);
|
|
6584
|
+
return this.countCombine("intersect", others, options ?? void 0);
|
|
6585
|
+
}
|
|
6586
|
+
/**
|
|
6587
|
+
* How many ids `this ∪ others…` holds (minus `exclude`): the length of what {@link union} streams, without streaming
|
|
6588
|
+
* it. A chunk key only one operand holds, that no `exclude` holds and the range does not cut, is answered from that
|
|
6589
|
+
* operand's index, so a union of segments that mostly do not overlap reads little of them; every other key is
|
|
6590
|
+
* decoded and counted. On handles that are not pinned it makes no more requests than {@link union} does, and reads
|
|
6591
|
+
* fewer bytes when the shared keys are few. An empty `others`, with no `exclude` and no range, is {@link count} of
|
|
6592
|
+
* `this`, answered from the registry row when it can be; when that figure is 0 it adds one registry read, to refuse
|
|
6593
|
+
* a segment that does not exist as the stream does.
|
|
6594
|
+
*
|
|
6595
|
+
* What it trusts: the index, for each key it answers without decoding, as {@link count} does, so a party who can write
|
|
6596
|
+
* an object's index can make that key's figure wrong; a decoded key is exact. A source with no per-chunk counts
|
|
6597
|
+
* decodes every key. It takes the options {@link intersectCount} takes; the erasure bound, the lease checks and the
|
|
6598
|
+
* pinned handles are as for {@link intersectCount}, a pinned operand adding a footer read before the first key and at
|
|
6599
|
+
* each look. An empty `others` on a pinned handle is {@link count} of the pin, with no look.
|
|
6600
|
+
*/
|
|
6601
|
+
async unionCount(others, options) {
|
|
6602
|
+
checkOptions(
|
|
6603
|
+
options,
|
|
6604
|
+
"unionCount",
|
|
6605
|
+
CALL_KEYS.unionCount,
|
|
6606
|
+
["allowAbsentOperands"],
|
|
6607
|
+
MISPLACED.unionCount
|
|
6608
|
+
);
|
|
6609
|
+
return this.countCombine("union", others, options ?? void 0);
|
|
6610
|
+
}
|
|
6611
|
+
/**
|
|
6612
|
+
* How many ids `this \ (excludes…)` holds: the length of what {@link andNot} streams, without streaming it. A chunk
|
|
6613
|
+
* key of `this` that no exclude holds and the range does not cut is answered from its index and not read; a key an
|
|
6614
|
+
* exclude shares is decoded and counted. On handles that are not pinned it makes no more requests than {@link andNot}
|
|
6615
|
+
* does, and reads fewer bytes when the excludes overlap little of `this`. An empty `excludes`, with no range, is
|
|
6616
|
+
* {@link count} of `this` (the stream of it is the whole of `this`), answered from the registry row when it can be,
|
|
6617
|
+
* with one registry read added when that figure is 0.
|
|
6618
|
+
*
|
|
6619
|
+
* It takes the options {@link andNot} takes (every one of {@link intersectCount}'s but `exclude`, which a count of a
|
|
6620
|
+
* difference has no use for, since `excludes` is its subtraction) and trusts what {@link unionCount} trusts. The
|
|
6621
|
+
* erasure bound, the lease checks and the pinned handles are as for {@link intersectCount}.
|
|
6622
|
+
*/
|
|
6623
|
+
async andNotCount(excludes, options) {
|
|
6624
|
+
checkOptions(
|
|
6625
|
+
options,
|
|
6626
|
+
"andNotCount",
|
|
6627
|
+
CALL_KEYS.andNotCount,
|
|
6628
|
+
["allowAbsentOperands"],
|
|
6629
|
+
MISPLACED.andNotCount
|
|
6630
|
+
);
|
|
6631
|
+
return this.countCombine("andNot", excludes, options ?? void 0);
|
|
6632
|
+
}
|
|
6633
|
+
/** The one body of the three count methods, after each has checked its own options. */
|
|
6634
|
+
async countCombine(verb, operands, options) {
|
|
6635
|
+
const name = `${verb}Count`;
|
|
6636
|
+
const exclude = verb === "andNot" ? NO_SEGMENTS : this.excludesOf(options);
|
|
6637
|
+
const others = segmentList(
|
|
6638
|
+
operands,
|
|
6639
|
+
verb === "andNot" ? `${name}: \`excludes\`` : `${name}: \`others\``
|
|
6640
|
+
);
|
|
6641
|
+
if (verb === "intersect" && others.length === 0) refuseNoOperands("intersectCount");
|
|
6642
|
+
const handles = [this, ...others, ...exclude];
|
|
6643
|
+
this.assertSegments(name, verb === "andNot" ? "an exclude" : "an operand", others);
|
|
6644
|
+
this.assertSegments(name, "an exclude", exclude);
|
|
6645
|
+
this.assertLeases(handles);
|
|
6646
|
+
const engine = this.combineEngine(handles) ?? this.engine;
|
|
6647
|
+
const read = options == null ? void 0 : readOptions(options);
|
|
6648
|
+
const guard2 = handles.some((h) => h.leaseHold !== void 0) ? () => this.assertLeases(handles) : void 0;
|
|
6649
|
+
const opts = guard2 === void 0 ? read : { ...read, guard: guard2 };
|
|
6650
|
+
const refs = others.map((o) => o.ref);
|
|
6651
|
+
if (verb === "andNot") return engine.combineCount([this.ref], refs, "all", verb, opts);
|
|
6652
|
+
return engine.combineCount(
|
|
6653
|
+
[this.ref, ...refs],
|
|
6654
|
+
exclude.map((o) => o.ref),
|
|
6655
|
+
verb === "union" ? "any" : "all",
|
|
6656
|
+
verb,
|
|
6657
|
+
opts
|
|
6658
|
+
);
|
|
6659
|
+
}
|
|
4870
6660
|
/**
|
|
4871
6661
|
* The one body of the three combines, read as ids or as chunks. `operands` is `others` for `intersect` and
|
|
4872
6662
|
* `union`, and `excludes` for `andNot`, which takes no `exclude` option.
|
|
@@ -4945,13 +6735,13 @@ export {
|
|
|
4945
6735
|
MemoryStorage,
|
|
4946
6736
|
NotFoundError2 as NotFoundError,
|
|
4947
6737
|
RecordingAuditSink,
|
|
6738
|
+
RoaringBitmap,
|
|
4948
6739
|
Segment,
|
|
4949
6740
|
StaleOperandError,
|
|
4950
6741
|
TransientError,
|
|
4951
6742
|
UnsupportedError3 as UnsupportedError,
|
|
4952
6743
|
ValidationError7 as ValidationError,
|
|
4953
6744
|
WriteConflictError2 as WriteConflictError,
|
|
4954
|
-
deserializePortable,
|
|
4955
6745
|
destroySegment,
|
|
4956
6746
|
eraseNamespace,
|
|
4957
6747
|
errorKind2 as errorKind,
|