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