@cloudbitmaps/roaring 0.12.0 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/PRIVACY.md +2 -2
- package/README.md +4 -4
- package/dist/bin/export-segments.js +30 -11
- package/dist/bin/export-segments.js.map +2 -2
- package/dist/index.d.ts +42 -6
- package/dist/index.js +30 -11
- package/dist/index.js.map +2 -2
- package/dist/roaring-codec.d.ts +2 -0
- package/dist/testing/fuzz-codec.d.ts +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -958,7 +958,13 @@ export declare class CloudRoaring {
|
|
|
958
958
|
* in `(after, through]` and fetches only the chunks the range overlaps, as {@link Segment.iterate} does.
|
|
959
959
|
*/
|
|
960
960
|
export interface BaseCombineOptions extends IdRange {
|
|
961
|
-
/**
|
|
961
|
+
/**
|
|
962
|
+
* Max chunk keys resolved concurrently — bounds the Storage footprint (about `concurrency × operands` chunks in
|
|
963
|
+
* flight). A positive integer; default 32. The window opens 8 keys wide (or `concurrency`, if lower) and widens
|
|
964
|
+
* as keys are taken, so a read that stops early fetches no more than a few keys ahead; one that runs to the end
|
|
965
|
+
* spends nearly all of its round trips at the full width. A read that stops early has requested up to
|
|
966
|
+
* `concurrency` keys per operand past the last one it used.
|
|
967
|
+
*/
|
|
962
968
|
readonly concurrency?: number;
|
|
963
969
|
/** Override the store's per-op denial-of-wallet budget for this call (`false` lifts it). */
|
|
964
970
|
readonly budget?: BudgetOption;
|
|
@@ -1045,6 +1051,36 @@ export interface MaterializeOptions extends CombineOptions {
|
|
|
1045
1051
|
*/
|
|
1046
1052
|
readonly keep?: number;
|
|
1047
1053
|
}
|
|
1054
|
+
/**
|
|
1055
|
+
* What a streaming read returns: the ids, ascending, one at a time under `for await`, or one chunk at a time from
|
|
1056
|
+
* {@link IdStream.batches}.
|
|
1057
|
+
*
|
|
1058
|
+
* It is an `AsyncIterable<number>`, so every consumer of an id stream takes it as it always did. A live read is the
|
|
1059
|
+
* engine's async generator itself, with `batches` attached: `for await` it, or drive it with `next()`, `return()` and
|
|
1060
|
+
* `throw()`, exactly as before, and it is single-use (a second `for await` over it yields nothing). `batches()` is a
|
|
1061
|
+
* separate, new read: it starts when called, fetches its chunks afresh and charges the per-op budget again, whether or
|
|
1062
|
+
* not the per-id stream was read, and reading both is two reads (invariant 3 applies to each separately). Nothing is
|
|
1063
|
+
* fetched until a read is first pulled.
|
|
1064
|
+
*/
|
|
1065
|
+
export interface IdStream extends AsyncIterable<number> {
|
|
1066
|
+
/**
|
|
1067
|
+
* The same ids as the per-id stream, in the same order, one `Uint32Array` per chunk: each array ascending, holding
|
|
1068
|
+
* every id of one chunk the read yields (a range trimmed at its edges exactly as the per-id stream trims it), and
|
|
1069
|
+
* no array is empty. Chunks arrive in ascending order, so the concatenation is the per-id stream.
|
|
1070
|
+
*
|
|
1071
|
+
* One `await` per chunk instead of one per id: measured locally, an in-memory read goes several times faster, and
|
|
1072
|
+
* a large scan stops being bound by the event loop. The reads, the budget and the read-ahead window are the per-id
|
|
1073
|
+
* stream's, and so is stopping early: leaving a `for await` over it (`break`, `return`, a throw) ends the read.
|
|
1074
|
+
*
|
|
1075
|
+
* **Memory:** one array per chunk, at most 65,536 ids (256 KiB), allocated for that chunk alone and yours to
|
|
1076
|
+
* keep, change or hand on; the read holds no reference to it after yielding it.
|
|
1077
|
+
*
|
|
1078
|
+
* ```ts
|
|
1079
|
+
* for await (const ids of seg.andNot([optOut]).batches()) await send(ids);
|
|
1080
|
+
* ```
|
|
1081
|
+
*/
|
|
1082
|
+
batches(): AsyncIterable<Uint32Array>;
|
|
1083
|
+
}
|
|
1048
1084
|
/**
|
|
1049
1085
|
* What `andNotInto` takes: the write options without `exclude`, because its `excludes` argument IS the
|
|
1050
1086
|
* subtraction — a second one in the options would be two spellings of one thing.
|
|
@@ -1257,7 +1293,7 @@ export declare class Segment {
|
|
|
1257
1293
|
* stream is first read. `after >= through` is an empty range, which reads nothing. An expired handle reads empty
|
|
1258
1294
|
* without checking its options, as every read of one does.
|
|
1259
1295
|
*/
|
|
1260
|
-
iterate(options?: IdRange):
|
|
1296
|
+
iterate(options?: IdRange): IdStream;
|
|
1261
1297
|
/**
|
|
1262
1298
|
* The options a combine hands the engine, read once, when it is called ({@link readOptions}), with the `exclude`
|
|
1263
1299
|
* it was given, already reduced to its live handles ({@link liveExcludes}) and mapped down to the plain refs
|
|
@@ -1283,11 +1319,11 @@ export declare class Segment {
|
|
|
1283
1319
|
* Chunk-skipping intersection: stream the ids in **this** segment AND every segment in `others`, ascending.
|
|
1284
1320
|
* Fetches only the Storage chunks present in *all* operands (a key absent from any operand contributes nothing
|
|
1285
1321
|
* and is never downloaded), streaming under a bounded in-flight window — so the Storage footprint stays small
|
|
1286
|
-
* (Lambda-friendly) regardless of segment size. Pass `concurrency` to tune that window (a positive integer).
|
|
1322
|
+
* (Lambda-friendly) regardless of segment size. Pass `concurrency` to tune that window (a positive integer, 32 by default).
|
|
1287
1323
|
* AND is commutative, so `a.intersect([b])` and `b.intersect([a])` yield the same ids. Pass `budget` to
|
|
1288
1324
|
* override the store's per-op denial-of-wallet budget for this call (or `false` to lift it).
|
|
1289
1325
|
*/
|
|
1290
|
-
intersect(others: Segment[], options?: CombineOptions):
|
|
1326
|
+
intersect(others: Segment[], options?: CombineOptions): IdStream;
|
|
1291
1327
|
/**
|
|
1292
1328
|
* Materialize `this ∩ others…` (minus `exclude`) as a **new generation of `dest`** — `dest`'s previous contents
|
|
1293
1329
|
* are superseded, not added to. Streaming + bounded-memory; the result is one immutable object published
|
|
@@ -1319,7 +1355,7 @@ export declare class Segment {
|
|
|
1319
1355
|
* deliberately. If you find yourself unioning the same segments on every read, materializing the combined
|
|
1320
1356
|
* segment once (`unionInto`, or a load) is the cheaper shape.
|
|
1321
1357
|
*/
|
|
1322
|
-
union(others: Segment[], options?: CombineOptions):
|
|
1358
|
+
union(others: Segment[], options?: CombineOptions): IdStream;
|
|
1323
1359
|
/** Materialize `this ∪ others…` (minus `exclude`) as a **new generation of `dest`** — see {@link intersectInto}. */
|
|
1324
1360
|
unionInto(dest: Segment, others: Segment[], options?: MaterializeOptions): Promise<MaterializeResult>;
|
|
1325
1361
|
/**
|
|
@@ -1337,7 +1373,7 @@ export declare class Segment {
|
|
|
1337
1373
|
* To filter the *result of an intersection*, do not chain — pass `exclude` to {@link intersect} instead, so
|
|
1338
1374
|
* the suppression folds into the same pass rather than materializing an intermediate segment first.
|
|
1339
1375
|
*/
|
|
1340
|
-
andNot(excludes: Segment[], options?: BaseCombineOptions):
|
|
1376
|
+
andNot(excludes: Segment[], options?: BaseCombineOptions): IdStream;
|
|
1341
1377
|
/** Materialize `this \ (excludes…)` as a **new generation of `dest`** — see {@link intersectInto}. */
|
|
1342
1378
|
andNotInto(dest: Segment, excludes: Segment[], options?: AndNotIntoOptions): Promise<MaterializeResult>;
|
|
1343
1379
|
/**
|
package/dist/index.js
CHANGED
|
@@ -439,6 +439,10 @@ var SafeBitmap = class _SafeBitmap {
|
|
|
439
439
|
toArray() {
|
|
440
440
|
return this.bitmap.toArray();
|
|
441
441
|
}
|
|
442
|
+
/** The values as one fresh ascending `Uint32Array`, exported natively. */
|
|
443
|
+
toUint32Array() {
|
|
444
|
+
return this.bitmap.toUint32Array();
|
|
445
|
+
}
|
|
442
446
|
};
|
|
443
447
|
function bitmapAsLoadInput(input) {
|
|
444
448
|
return input instanceof RoaringBitmap32 ? { bitmap: input } : input;
|
|
@@ -1658,9 +1662,14 @@ var CloudRoaring = class _CloudRoaring {
|
|
|
1658
1662
|
return estimateCost(input);
|
|
1659
1663
|
}
|
|
1660
1664
|
};
|
|
1661
|
-
var
|
|
1662
|
-
|
|
1663
|
-
});
|
|
1665
|
+
var withBatches = (gen, batches) => Object.assign(gen, { batches });
|
|
1666
|
+
var failing = (err) => {
|
|
1667
|
+
const rejecting = () => ({ next: () => Promise.reject(err) });
|
|
1668
|
+
return {
|
|
1669
|
+
[Symbol.asyncIterator]: rejecting,
|
|
1670
|
+
batches: () => ({ [Symbol.asyncIterator]: rejecting })
|
|
1671
|
+
};
|
|
1672
|
+
};
|
|
1664
1673
|
var samePin = (a, b) => a === void 0 || b === void 0 ? a === b : a.generation === b.generation && a.fingerprint === b.fingerprint;
|
|
1665
1674
|
var twoPins = (a, b) => {
|
|
1666
1675
|
const one = (p) => p === void 0 ? "live" : `pinned at generation ${p.generation ?? "none"}`;
|
|
@@ -1679,6 +1688,8 @@ var readOptions = (options) => ({
|
|
|
1679
1688
|
var NO_SEGMENTS = [];
|
|
1680
1689
|
var EMPTY_IDS = {
|
|
1681
1690
|
async *[Symbol.asyncIterator]() {
|
|
1691
|
+
},
|
|
1692
|
+
async *batches() {
|
|
1682
1693
|
}
|
|
1683
1694
|
};
|
|
1684
1695
|
var KEEP_EVERY_GENERATION = Number.MAX_SAFE_INTEGER;
|
|
@@ -1934,7 +1945,9 @@ var Segment = class _Segment {
|
|
|
1934
1945
|
if (this.expired()) return EMPTY_IDS;
|
|
1935
1946
|
const range = options == null ? void 0 : rangeOf(options);
|
|
1936
1947
|
const none = range === void 0 || range.after === void 0 && range.through === void 0;
|
|
1937
|
-
|
|
1948
|
+
const { engine, ref } = this;
|
|
1949
|
+
const bounds = none ? void 0 : range;
|
|
1950
|
+
return withBatches(engine.iterate(ref, bounds), () => engine.iterateBatches(ref, bounds));
|
|
1938
1951
|
}
|
|
1939
1952
|
/**
|
|
1940
1953
|
* The options a combine hands the engine, read once, when it is called ({@link readOptions}), with the `exclude`
|
|
@@ -1971,7 +1984,7 @@ var Segment = class _Segment {
|
|
|
1971
1984
|
* Chunk-skipping intersection: stream the ids in **this** segment AND every segment in `others`, ascending.
|
|
1972
1985
|
* Fetches only the Storage chunks present in *all* operands (a key absent from any operand contributes nothing
|
|
1973
1986
|
* and is never downloaded), streaming under a bounded in-flight window — so the Storage footprint stays small
|
|
1974
|
-
* (Lambda-friendly) regardless of segment size. Pass `concurrency` to tune that window (a positive integer).
|
|
1987
|
+
* (Lambda-friendly) regardless of segment size. Pass `concurrency` to tune that window (a positive integer, 32 by default).
|
|
1975
1988
|
* AND is commutative, so `a.intersect([b])` and `b.intersect([a])` yield the same ids. Pass `budget` to
|
|
1976
1989
|
* override the store's per-op denial-of-wallet budget for this call (or `false` to lift it).
|
|
1977
1990
|
*/
|
|
@@ -1984,7 +1997,9 @@ var Segment = class _Segment {
|
|
|
1984
1997
|
} catch (err) {
|
|
1985
1998
|
return failing(err);
|
|
1986
1999
|
}
|
|
1987
|
-
|
|
2000
|
+
const refs = [this.ref, ...others.map((o) => o.ref)];
|
|
2001
|
+
const opts = this.refsIn(options, exclude);
|
|
2002
|
+
return withBatches(engine.intersect(refs, opts), () => engine.intersectBatches(refs, opts));
|
|
1988
2003
|
}
|
|
1989
2004
|
/**
|
|
1990
2005
|
* Materialize `this ∩ others…` (minus `exclude`) as a **new generation of `dest`** — `dest`'s previous contents
|
|
@@ -2042,7 +2057,9 @@ var Segment = class _Segment {
|
|
|
2042
2057
|
} catch (err) {
|
|
2043
2058
|
return failing(err);
|
|
2044
2059
|
}
|
|
2045
|
-
|
|
2060
|
+
const refs = [this.ref, ...others.map((o) => o.ref)];
|
|
2061
|
+
const opts = this.refsIn(options, exclude);
|
|
2062
|
+
return withBatches(engine.union(refs, opts), () => engine.unionBatches(refs, opts));
|
|
2046
2063
|
}
|
|
2047
2064
|
/** Materialize `this ∪ others…` (minus `exclude`) as a **new generation of `dest`** — see {@link intersectInto}. */
|
|
2048
2065
|
async unionInto(dest, others, options) {
|
|
@@ -2081,10 +2098,12 @@ var Segment = class _Segment {
|
|
|
2081
2098
|
} catch (err) {
|
|
2082
2099
|
return failing(err);
|
|
2083
2100
|
}
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2101
|
+
const base = this.ref;
|
|
2102
|
+
const refs = excludes.map((o) => o.ref);
|
|
2103
|
+
const opts = options == null ? void 0 : readOptions(options);
|
|
2104
|
+
return withBatches(
|
|
2105
|
+
engine.andNot(base, refs, opts),
|
|
2106
|
+
() => engine.andNotBatches(base, refs, opts)
|
|
2088
2107
|
);
|
|
2089
2108
|
}
|
|
2090
2109
|
/** Materialize `this \ (excludes…)` as a **new generation of `dest`** — see {@link intersectInto}. */
|