distillate 0.4.0 → 0.6.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/README.md +9 -9
- package/dist/blocked/index.cjs +115 -46
- package/dist/blocked/index.d.cts +40 -3
- package/dist/blocked/index.d.ts +40 -3
- package/dist/blocked/index.js +115 -46
- package/dist/bloom/index.cjs +69 -26
- package/dist/bloom/index.d.cts +34 -2
- package/dist/bloom/index.d.ts +34 -2
- package/dist/bloom/index.js +69 -26
- package/dist/fuse/index.cjs +73 -77
- package/dist/fuse/index.d.cts +34 -2
- package/dist/fuse/index.d.ts +34 -2
- package/dist/fuse/index.js +63 -67
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/{params-J8p3bKq5.cjs → params--8CNXYWu.cjs} +10 -0
- package/dist/{params-ChTRNxM9.js → params-BrWuBC2A.js} +5 -1
- package/dist/serialize-BIIKUHH6.cjs +515 -0
- package/dist/serialize-BnwtzcMw.js +414 -0
- package/dist/serialize-DRKh6QOr.d.cts +15 -0
- package/dist/serialize-DRKh6QOr.d.ts +15 -0
- package/package.json +5 -28
- package/dist/bytes-DCuYtUVS.d.cts +0 -4
- package/dist/bytes-DCuYtUVS.d.ts +0 -4
- package/dist/serialize-DPdiySxq.cjs +0 -355
- package/dist/serialize-DkkBKDT0.js +0 -308
package/dist/fuse/index.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_serialize = require("../serialize-
|
|
2
|
+
const require_serialize = require("../serialize-BIIKUHH6.cjs");
|
|
3
3
|
//#region src/fuse/fuse.ts
|
|
4
4
|
const ARITY = 3;
|
|
5
5
|
const TYPE_FUSE8 = 3;
|
|
@@ -9,71 +9,23 @@ var BinaryFuseBuildError = class extends Error {
|
|
|
9
9
|
/** Discriminates this error from other `Error`s. */
|
|
10
10
|
name = "BinaryFuseBuildError";
|
|
11
11
|
};
|
|
12
|
-
let RLO = 0;
|
|
13
|
-
let RHI = 0;
|
|
14
12
|
const scratchHash = {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
w0: 0,
|
|
14
|
+
w1: 0,
|
|
15
|
+
w2: 0,
|
|
16
|
+
w3: 0
|
|
19
17
|
};
|
|
20
|
-
function mul64(alo, ahi, blo, bhi) {
|
|
21
|
-
const a0 = alo & 65535;
|
|
22
|
-
const a1 = alo >>> 16;
|
|
23
|
-
const a2 = ahi & 65535;
|
|
24
|
-
const a3 = ahi >>> 16;
|
|
25
|
-
const b0 = blo & 65535;
|
|
26
|
-
const b1 = blo >>> 16;
|
|
27
|
-
const b2 = bhi & 65535;
|
|
28
|
-
const b3 = bhi >>> 16;
|
|
29
|
-
let c0 = a0 * b0;
|
|
30
|
-
let c1 = c0 >>> 16;
|
|
31
|
-
c0 &= 65535;
|
|
32
|
-
c1 += a1 * b0;
|
|
33
|
-
let c2 = c1 >>> 16;
|
|
34
|
-
c1 &= 65535;
|
|
35
|
-
c1 += a0 * b1;
|
|
36
|
-
c2 += c1 >>> 16;
|
|
37
|
-
c1 &= 65535;
|
|
38
|
-
c2 += a2 * b0;
|
|
39
|
-
let c3 = c2 >>> 16;
|
|
40
|
-
c2 &= 65535;
|
|
41
|
-
c2 += a1 * b1;
|
|
42
|
-
c3 += c2 >>> 16;
|
|
43
|
-
c2 &= 65535;
|
|
44
|
-
c2 += a0 * b2;
|
|
45
|
-
c3 += c2 >>> 16;
|
|
46
|
-
c2 &= 65535;
|
|
47
|
-
c3 += a3 * b0 + a2 * b1 + a1 * b2 + a0 * b3;
|
|
48
|
-
c3 &= 65535;
|
|
49
|
-
RLO = (c1 << 16 | c0) >>> 0;
|
|
50
|
-
RHI = (c3 << 16 | c2) >>> 0;
|
|
51
|
-
}
|
|
52
|
-
function fmix64(lo, hi) {
|
|
53
|
-
let l = (lo ^ hi >>> 1) >>> 0;
|
|
54
|
-
let h = hi;
|
|
55
|
-
mul64(l, h, 3981806797, 4283543511);
|
|
56
|
-
l = RLO;
|
|
57
|
-
h = RHI;
|
|
58
|
-
l = (l ^ h >>> 1) >>> 0;
|
|
59
|
-
mul64(l, h, 444984403, 3301882366);
|
|
60
|
-
l = RLO;
|
|
61
|
-
h = RHI;
|
|
62
|
-
l = (l ^ h >>> 1) >>> 0;
|
|
63
|
-
RLO = l;
|
|
64
|
-
RHI = h;
|
|
65
|
-
}
|
|
66
18
|
function mixSeed(lo, hi, seed) {
|
|
67
19
|
const l = (lo >>> 0) + (seed >>> 0);
|
|
68
20
|
const carry = l > 4294967295 ? 1 : 0;
|
|
69
|
-
fmix64(l >>> 0, hi + carry >>> 0);
|
|
21
|
+
require_serialize.fmix64(l >>> 0, hi + carry >>> 0);
|
|
70
22
|
}
|
|
71
23
|
function mulhi64(lo, hi, n) {
|
|
72
|
-
mul64(hi, 0, n, 0);
|
|
73
|
-
const aLo = RLO;
|
|
74
|
-
const aHi = RHI;
|
|
75
|
-
mul64(lo, 0, n, 0);
|
|
76
|
-
const bHi = RHI;
|
|
24
|
+
require_serialize.mul64(hi, 0, n, 0);
|
|
25
|
+
const aLo = require_serialize.RLO;
|
|
26
|
+
const aHi = require_serialize.RHI;
|
|
27
|
+
require_serialize.mul64(lo, 0, n, 0);
|
|
28
|
+
const bHi = require_serialize.RHI;
|
|
77
29
|
return aHi + ((aLo >>> 0) + (bHi >>> 0) > 4294967295 ? 1 : 0) >>> 0;
|
|
78
30
|
}
|
|
79
31
|
function positionsInto(mlo, mhi, seg, segMask, segCountLen, out) {
|
|
@@ -130,8 +82,8 @@ function buildFingerprints(fp, hashes, params, maxAttempts = 100) {
|
|
|
130
82
|
xorHi.fill(0);
|
|
131
83
|
for (let i = 0; i < size; i++) {
|
|
132
84
|
mixSeed(hashes[2 * i] ?? 0, hashes[2 * i + 1] ?? 0, seed);
|
|
133
|
-
const mlo = RLO;
|
|
134
|
-
const mhi = RHI;
|
|
85
|
+
const mlo = require_serialize.RLO;
|
|
86
|
+
const mhi = require_serialize.RHI;
|
|
135
87
|
positionsInto(mlo, mhi, seg, segMask, segCountLen, pos);
|
|
136
88
|
for (let j = 0; j < 3; j++) {
|
|
137
89
|
const p = pos[j] ?? 0;
|
|
@@ -184,8 +136,8 @@ function buildState(keys, alloc) {
|
|
|
184
136
|
const seen = /* @__PURE__ */ new Set();
|
|
185
137
|
for (const key of keys) {
|
|
186
138
|
require_serialize.hash128KeyInto(key, 0, scratchHash);
|
|
187
|
-
const lo = scratchHash.
|
|
188
|
-
const hi = scratchHash.
|
|
139
|
+
const lo = scratchHash.w0 >>> 0;
|
|
140
|
+
const hi = scratchHash.w1 >>> 0;
|
|
189
141
|
const id = `${String(lo)},${String(hi)}`;
|
|
190
142
|
if (seen.has(id)) continue;
|
|
191
143
|
seen.add(id);
|
|
@@ -209,14 +161,17 @@ function buildState(keys, alloc) {
|
|
|
209
161
|
};
|
|
210
162
|
}
|
|
211
163
|
function fuseStateFromBytes(bytes, expectedType) {
|
|
212
|
-
const { type, body } = require_serialize.readHeader(bytes);
|
|
164
|
+
const { type, flags, body } = require_serialize.readHeader(bytes);
|
|
213
165
|
if (type !== expectedType) throw new require_serialize.SerializationError(`expected AMQF type ${String(expectedType)}, got ${String(type)}`);
|
|
166
|
+
if ((flags & 15) !== 0) throw new require_serialize.UnknownHashVariantError(`unsupported hash variant ${String(flags & 15)}`);
|
|
214
167
|
require_serialize.assertMinBodyLength(body.length, 16, "fuse");
|
|
215
168
|
const dv = new DataView(body.buffer, body.byteOffset, body.byteLength);
|
|
216
169
|
const seed = dv.getUint32(0, true);
|
|
217
170
|
const seg = dv.getUint32(4, true);
|
|
218
171
|
const segCountLen = dv.getUint32(8, true);
|
|
219
172
|
const size = dv.getUint32(12, true);
|
|
173
|
+
if (seg === 0 || (seg & seg - 1) !== 0 || seg > 1 << 18) throw new require_serialize.SerializationError(`invalid fuse segment length ${String(seg)}`);
|
|
174
|
+
if (segCountLen % seg !== 0) throw new require_serialize.SerializationError(`fuse segment count length ${String(segCountLen)} is not a multiple of segment length ${String(seg)}`);
|
|
220
175
|
const bpe = expectedType === TYPE_FUSE8 ? 1 : 2;
|
|
221
176
|
const expectedArrayLength = size === 0 ? 0 : segCountLen + 2 * seg;
|
|
222
177
|
require_serialize.assertBodyLength(body.length, 16 + expectedArrayLength * bpe, "fuse");
|
|
@@ -260,6 +215,10 @@ var BinaryFuse = class {
|
|
|
260
215
|
get size() {
|
|
261
216
|
return this.#size;
|
|
262
217
|
}
|
|
218
|
+
/** Hash seed selected during construction (may differ from 0 after a peel retry). */
|
|
219
|
+
get seed() {
|
|
220
|
+
return this.#seed;
|
|
221
|
+
}
|
|
263
222
|
/** Actual bits stored per key (`0` for an empty filter). */
|
|
264
223
|
get bitsPerKey() {
|
|
265
224
|
return this.#size === 0 ? 0 : this.#fp.byteLength * 8 / this.#size;
|
|
@@ -271,18 +230,17 @@ var BinaryFuse = class {
|
|
|
271
230
|
*/
|
|
272
231
|
toBytes() {
|
|
273
232
|
const laneBytes = new Uint8Array(this.#fp.buffer, this.#fp.byteOffset, this.#fp.byteLength);
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
dv.setUint32(0, this.#seed, true);
|
|
277
|
-
dv.setUint32(4, this.#seg, true);
|
|
278
|
-
dv.setUint32(8, this.#segCountLen, true);
|
|
279
|
-
dv.setUint32(12, this.#size, true);
|
|
280
|
-
body.set(laneBytes, 16);
|
|
281
|
-
return require_serialize.writeHeader({
|
|
282
|
-
version: 2,
|
|
233
|
+
return require_serialize.writeFrame({
|
|
234
|
+
version: 3,
|
|
283
235
|
type: this.#fp.BYTES_PER_ELEMENT === 1 ? TYPE_FUSE8 : TYPE_FUSE16,
|
|
284
236
|
flags: 0
|
|
285
|
-
}, body)
|
|
237
|
+
}, 16 + laneBytes.length, (body, dv) => {
|
|
238
|
+
dv.setUint32(0, this.#seed, true);
|
|
239
|
+
dv.setUint32(4, this.#seg, true);
|
|
240
|
+
dv.setUint32(8, this.#segCountLen, true);
|
|
241
|
+
dv.setUint32(12, this.#size, true);
|
|
242
|
+
body.set(laneBytes, 16);
|
|
243
|
+
});
|
|
286
244
|
}
|
|
287
245
|
/**
|
|
288
246
|
* Tests whether a key is in the set.
|
|
@@ -293,9 +251,9 @@ var BinaryFuse = class {
|
|
|
293
251
|
has(key) {
|
|
294
252
|
if (this.#fp.length === 0) return false;
|
|
295
253
|
require_serialize.hash128KeyInto(key, 0, scratchHash);
|
|
296
|
-
mixSeed(scratchHash.
|
|
297
|
-
const mlo = RLO;
|
|
298
|
-
const mhi = RHI;
|
|
254
|
+
mixSeed(scratchHash.w0 >>> 0, scratchHash.w1 >>> 0, this.#seed);
|
|
255
|
+
const mlo = require_serialize.RLO;
|
|
256
|
+
const mhi = require_serialize.RHI;
|
|
299
257
|
positionsInto(mlo, mhi, this.#seg, this.#segMask, this.#segCountLen, this.#pos);
|
|
300
258
|
const mask = fpMask(this.#fp);
|
|
301
259
|
const p0 = this.#pos[0] ?? 0;
|
|
@@ -303,6 +261,26 @@ var BinaryFuse = class {
|
|
|
303
261
|
const p2 = this.#pos[2] ?? 0;
|
|
304
262
|
return ((mlo ^ mhi) & mask) === (((this.#fp[p0] ?? 0) ^ (this.#fp[p1] ?? 0) ^ (this.#fp[p2] ?? 0)) & mask);
|
|
305
263
|
}
|
|
264
|
+
/**
|
|
265
|
+
* Tests structural equality: `true` when `other` serializes to identical
|
|
266
|
+
* bytes. A {@link BinaryFuse8} and a {@link BinaryFuse16} are never equal,
|
|
267
|
+
* since their frames carry different type bytes.
|
|
268
|
+
*
|
|
269
|
+
* @param other - The filter to compare against.
|
|
270
|
+
* @returns `true` if the two filters are byte-for-byte identical.
|
|
271
|
+
*/
|
|
272
|
+
equals(other) {
|
|
273
|
+
return require_serialize.bytesEqual(this.toBytes(), other.toBytes());
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Serializes the filter to a JSON-friendly envelope wrapping the base64 of
|
|
277
|
+
* the `toBytes` frame.
|
|
278
|
+
*
|
|
279
|
+
* @returns The envelope, readable by the matching `fromJSON`.
|
|
280
|
+
*/
|
|
281
|
+
toJSON() {
|
|
282
|
+
return require_serialize.toJSONEnvelope(this.toBytes());
|
|
283
|
+
}
|
|
306
284
|
};
|
|
307
285
|
/**
|
|
308
286
|
* A static 8-bit binary fuse filter: built once from a key set, then immutable.
|
|
@@ -335,6 +313,15 @@ var BinaryFuse8 = class BinaryFuse8 extends BinaryFuse {
|
|
|
335
313
|
static fromBytes(bytes) {
|
|
336
314
|
return new BinaryFuse8(fuseStateFromBytes(bytes, TYPE_FUSE8));
|
|
337
315
|
}
|
|
316
|
+
/**
|
|
317
|
+
* Restores a filter from its {@link BinaryFuse8.toJSON} envelope.
|
|
318
|
+
*
|
|
319
|
+
* @param value - The JSON envelope.
|
|
320
|
+
* @returns The reconstructed filter.
|
|
321
|
+
*/
|
|
322
|
+
static fromJSON(value) {
|
|
323
|
+
return BinaryFuse8.fromBytes(require_serialize.fromJSONEnvelope(value));
|
|
324
|
+
}
|
|
338
325
|
};
|
|
339
326
|
/**
|
|
340
327
|
* A static 16-bit binary fuse filter: like {@link BinaryFuse8} but twice the
|
|
@@ -366,6 +353,15 @@ var BinaryFuse16 = class BinaryFuse16 extends BinaryFuse {
|
|
|
366
353
|
static fromBytes(bytes) {
|
|
367
354
|
return new BinaryFuse16(fuseStateFromBytes(bytes, TYPE_FUSE16));
|
|
368
355
|
}
|
|
356
|
+
/**
|
|
357
|
+
* Restores a filter from its {@link BinaryFuse16.toJSON} envelope.
|
|
358
|
+
*
|
|
359
|
+
* @param value - The JSON envelope.
|
|
360
|
+
* @returns The reconstructed filter.
|
|
361
|
+
*/
|
|
362
|
+
static fromJSON(value) {
|
|
363
|
+
return BinaryFuse16.fromBytes(require_serialize.fromJSONEnvelope(value));
|
|
364
|
+
}
|
|
369
365
|
};
|
|
370
366
|
//#endregion
|
|
371
367
|
exports.BinaryFuse16 = BinaryFuse16;
|
package/dist/fuse/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { n as BytesLike, t as FilterJSON } from "../serialize-DRKh6QOr.cjs";
|
|
2
2
|
//#region src/fuse/fuse.d.ts
|
|
3
3
|
/** Thrown when binary fuse construction fails to converge on the key set. */
|
|
4
4
|
declare class BinaryFuseBuildError extends Error {
|
|
@@ -26,6 +26,8 @@ declare abstract class BinaryFuse {
|
|
|
26
26
|
protected constructor(state: FuseState);
|
|
27
27
|
/** Number of distinct keys the filter was built from. */
|
|
28
28
|
get size(): number;
|
|
29
|
+
/** Hash seed selected during construction (may differ from 0 after a peel retry). */
|
|
30
|
+
get seed(): number;
|
|
29
31
|
/** Actual bits stored per key (`0` for an empty filter). */
|
|
30
32
|
get bitsPerKey(): number;
|
|
31
33
|
/**
|
|
@@ -41,6 +43,22 @@ declare abstract class BinaryFuse {
|
|
|
41
43
|
* @returns `true` if present (possibly a false positive); `false` guarantees absence.
|
|
42
44
|
*/
|
|
43
45
|
has(key: BytesLike): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Tests structural equality: `true` when `other` serializes to identical
|
|
48
|
+
* bytes. A {@link BinaryFuse8} and a {@link BinaryFuse16} are never equal,
|
|
49
|
+
* since their frames carry different type bytes.
|
|
50
|
+
*
|
|
51
|
+
* @param other - The filter to compare against.
|
|
52
|
+
* @returns `true` if the two filters are byte-for-byte identical.
|
|
53
|
+
*/
|
|
54
|
+
equals(other: BinaryFuse8 | BinaryFuse16): boolean;
|
|
55
|
+
/**
|
|
56
|
+
* Serializes the filter to a JSON-friendly envelope wrapping the base64 of
|
|
57
|
+
* the `toBytes` frame.
|
|
58
|
+
*
|
|
59
|
+
* @returns The envelope, readable by the matching `fromJSON`.
|
|
60
|
+
*/
|
|
61
|
+
toJSON(): FilterJSON;
|
|
44
62
|
}
|
|
45
63
|
/**
|
|
46
64
|
* A static 8-bit binary fuse filter: built once from a key set, then immutable.
|
|
@@ -69,6 +87,13 @@ declare class BinaryFuse8 extends BinaryFuse {
|
|
|
69
87
|
* @returns The reconstructed filter.
|
|
70
88
|
*/
|
|
71
89
|
static fromBytes(bytes: Uint8Array): BinaryFuse8;
|
|
90
|
+
/**
|
|
91
|
+
* Restores a filter from its {@link BinaryFuse8.toJSON} envelope.
|
|
92
|
+
*
|
|
93
|
+
* @param value - The JSON envelope.
|
|
94
|
+
* @returns The reconstructed filter.
|
|
95
|
+
*/
|
|
96
|
+
static fromJSON(value: unknown): BinaryFuse8;
|
|
72
97
|
}
|
|
73
98
|
/**
|
|
74
99
|
* A static 16-bit binary fuse filter: like {@link BinaryFuse8} but twice the
|
|
@@ -96,6 +121,13 @@ declare class BinaryFuse16 extends BinaryFuse {
|
|
|
96
121
|
* @returns The reconstructed filter.
|
|
97
122
|
*/
|
|
98
123
|
static fromBytes(bytes: Uint8Array): BinaryFuse16;
|
|
124
|
+
/**
|
|
125
|
+
* Restores a filter from its {@link BinaryFuse16.toJSON} envelope.
|
|
126
|
+
*
|
|
127
|
+
* @param value - The JSON envelope.
|
|
128
|
+
* @returns The reconstructed filter.
|
|
129
|
+
*/
|
|
130
|
+
static fromJSON(value: unknown): BinaryFuse16;
|
|
99
131
|
}
|
|
100
132
|
//#endregion
|
|
101
|
-
export { BinaryFuse16, BinaryFuse8, BinaryFuseBuildError };
|
|
133
|
+
export { BinaryFuse16, BinaryFuse8, BinaryFuseBuildError, type FilterJSON };
|
package/dist/fuse/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { n as BytesLike, t as FilterJSON } from "../serialize-DRKh6QOr.js";
|
|
2
2
|
//#region src/fuse/fuse.d.ts
|
|
3
3
|
/** Thrown when binary fuse construction fails to converge on the key set. */
|
|
4
4
|
declare class BinaryFuseBuildError extends Error {
|
|
@@ -26,6 +26,8 @@ declare abstract class BinaryFuse {
|
|
|
26
26
|
protected constructor(state: FuseState);
|
|
27
27
|
/** Number of distinct keys the filter was built from. */
|
|
28
28
|
get size(): number;
|
|
29
|
+
/** Hash seed selected during construction (may differ from 0 after a peel retry). */
|
|
30
|
+
get seed(): number;
|
|
29
31
|
/** Actual bits stored per key (`0` for an empty filter). */
|
|
30
32
|
get bitsPerKey(): number;
|
|
31
33
|
/**
|
|
@@ -41,6 +43,22 @@ declare abstract class BinaryFuse {
|
|
|
41
43
|
* @returns `true` if present (possibly a false positive); `false` guarantees absence.
|
|
42
44
|
*/
|
|
43
45
|
has(key: BytesLike): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Tests structural equality: `true` when `other` serializes to identical
|
|
48
|
+
* bytes. A {@link BinaryFuse8} and a {@link BinaryFuse16} are never equal,
|
|
49
|
+
* since their frames carry different type bytes.
|
|
50
|
+
*
|
|
51
|
+
* @param other - The filter to compare against.
|
|
52
|
+
* @returns `true` if the two filters are byte-for-byte identical.
|
|
53
|
+
*/
|
|
54
|
+
equals(other: BinaryFuse8 | BinaryFuse16): boolean;
|
|
55
|
+
/**
|
|
56
|
+
* Serializes the filter to a JSON-friendly envelope wrapping the base64 of
|
|
57
|
+
* the `toBytes` frame.
|
|
58
|
+
*
|
|
59
|
+
* @returns The envelope, readable by the matching `fromJSON`.
|
|
60
|
+
*/
|
|
61
|
+
toJSON(): FilterJSON;
|
|
44
62
|
}
|
|
45
63
|
/**
|
|
46
64
|
* A static 8-bit binary fuse filter: built once from a key set, then immutable.
|
|
@@ -69,6 +87,13 @@ declare class BinaryFuse8 extends BinaryFuse {
|
|
|
69
87
|
* @returns The reconstructed filter.
|
|
70
88
|
*/
|
|
71
89
|
static fromBytes(bytes: Uint8Array): BinaryFuse8;
|
|
90
|
+
/**
|
|
91
|
+
* Restores a filter from its {@link BinaryFuse8.toJSON} envelope.
|
|
92
|
+
*
|
|
93
|
+
* @param value - The JSON envelope.
|
|
94
|
+
* @returns The reconstructed filter.
|
|
95
|
+
*/
|
|
96
|
+
static fromJSON(value: unknown): BinaryFuse8;
|
|
72
97
|
}
|
|
73
98
|
/**
|
|
74
99
|
* A static 16-bit binary fuse filter: like {@link BinaryFuse8} but twice the
|
|
@@ -96,6 +121,13 @@ declare class BinaryFuse16 extends BinaryFuse {
|
|
|
96
121
|
* @returns The reconstructed filter.
|
|
97
122
|
*/
|
|
98
123
|
static fromBytes(bytes: Uint8Array): BinaryFuse16;
|
|
124
|
+
/**
|
|
125
|
+
* Restores a filter from its {@link BinaryFuse16.toJSON} envelope.
|
|
126
|
+
*
|
|
127
|
+
* @param value - The JSON envelope.
|
|
128
|
+
* @returns The reconstructed filter.
|
|
129
|
+
*/
|
|
130
|
+
static fromJSON(value: unknown): BinaryFuse16;
|
|
99
131
|
}
|
|
100
132
|
//#endregion
|
|
101
|
-
export { BinaryFuse16, BinaryFuse8, BinaryFuseBuildError };
|
|
133
|
+
export { BinaryFuse16, BinaryFuse8, BinaryFuseBuildError, type FilterJSON };
|
package/dist/fuse/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as bytesEqual, c as toJSONEnvelope, d as RLO, f as fmix64, h as mul64, i as assertMinBodyLength, l as writeFrame, n as UnknownHashVariantError, o as fromJSONEnvelope, p as hash128KeyInto, r as assertBodyLength, s as readHeader, t as SerializationError, u as RHI } from "../serialize-BnwtzcMw.js";
|
|
2
2
|
//#region src/fuse/fuse.ts
|
|
3
3
|
const ARITY = 3;
|
|
4
4
|
const TYPE_FUSE8 = 3;
|
|
@@ -8,60 +8,12 @@ var BinaryFuseBuildError = class extends Error {
|
|
|
8
8
|
/** Discriminates this error from other `Error`s. */
|
|
9
9
|
name = "BinaryFuseBuildError";
|
|
10
10
|
};
|
|
11
|
-
let RLO = 0;
|
|
12
|
-
let RHI = 0;
|
|
13
11
|
const scratchHash = {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
w0: 0,
|
|
13
|
+
w1: 0,
|
|
14
|
+
w2: 0,
|
|
15
|
+
w3: 0
|
|
18
16
|
};
|
|
19
|
-
function mul64(alo, ahi, blo, bhi) {
|
|
20
|
-
const a0 = alo & 65535;
|
|
21
|
-
const a1 = alo >>> 16;
|
|
22
|
-
const a2 = ahi & 65535;
|
|
23
|
-
const a3 = ahi >>> 16;
|
|
24
|
-
const b0 = blo & 65535;
|
|
25
|
-
const b1 = blo >>> 16;
|
|
26
|
-
const b2 = bhi & 65535;
|
|
27
|
-
const b3 = bhi >>> 16;
|
|
28
|
-
let c0 = a0 * b0;
|
|
29
|
-
let c1 = c0 >>> 16;
|
|
30
|
-
c0 &= 65535;
|
|
31
|
-
c1 += a1 * b0;
|
|
32
|
-
let c2 = c1 >>> 16;
|
|
33
|
-
c1 &= 65535;
|
|
34
|
-
c1 += a0 * b1;
|
|
35
|
-
c2 += c1 >>> 16;
|
|
36
|
-
c1 &= 65535;
|
|
37
|
-
c2 += a2 * b0;
|
|
38
|
-
let c3 = c2 >>> 16;
|
|
39
|
-
c2 &= 65535;
|
|
40
|
-
c2 += a1 * b1;
|
|
41
|
-
c3 += c2 >>> 16;
|
|
42
|
-
c2 &= 65535;
|
|
43
|
-
c2 += a0 * b2;
|
|
44
|
-
c3 += c2 >>> 16;
|
|
45
|
-
c2 &= 65535;
|
|
46
|
-
c3 += a3 * b0 + a2 * b1 + a1 * b2 + a0 * b3;
|
|
47
|
-
c3 &= 65535;
|
|
48
|
-
RLO = (c1 << 16 | c0) >>> 0;
|
|
49
|
-
RHI = (c3 << 16 | c2) >>> 0;
|
|
50
|
-
}
|
|
51
|
-
function fmix64(lo, hi) {
|
|
52
|
-
let l = (lo ^ hi >>> 1) >>> 0;
|
|
53
|
-
let h = hi;
|
|
54
|
-
mul64(l, h, 3981806797, 4283543511);
|
|
55
|
-
l = RLO;
|
|
56
|
-
h = RHI;
|
|
57
|
-
l = (l ^ h >>> 1) >>> 0;
|
|
58
|
-
mul64(l, h, 444984403, 3301882366);
|
|
59
|
-
l = RLO;
|
|
60
|
-
h = RHI;
|
|
61
|
-
l = (l ^ h >>> 1) >>> 0;
|
|
62
|
-
RLO = l;
|
|
63
|
-
RHI = h;
|
|
64
|
-
}
|
|
65
17
|
function mixSeed(lo, hi, seed) {
|
|
66
18
|
const l = (lo >>> 0) + (seed >>> 0);
|
|
67
19
|
const carry = l > 4294967295 ? 1 : 0;
|
|
@@ -183,8 +135,8 @@ function buildState(keys, alloc) {
|
|
|
183
135
|
const seen = /* @__PURE__ */ new Set();
|
|
184
136
|
for (const key of keys) {
|
|
185
137
|
hash128KeyInto(key, 0, scratchHash);
|
|
186
|
-
const lo = scratchHash.
|
|
187
|
-
const hi = scratchHash.
|
|
138
|
+
const lo = scratchHash.w0 >>> 0;
|
|
139
|
+
const hi = scratchHash.w1 >>> 0;
|
|
188
140
|
const id = `${String(lo)},${String(hi)}`;
|
|
189
141
|
if (seen.has(id)) continue;
|
|
190
142
|
seen.add(id);
|
|
@@ -208,14 +160,17 @@ function buildState(keys, alloc) {
|
|
|
208
160
|
};
|
|
209
161
|
}
|
|
210
162
|
function fuseStateFromBytes(bytes, expectedType) {
|
|
211
|
-
const { type, body } = readHeader(bytes);
|
|
163
|
+
const { type, flags, body } = readHeader(bytes);
|
|
212
164
|
if (type !== expectedType) throw new SerializationError(`expected AMQF type ${String(expectedType)}, got ${String(type)}`);
|
|
165
|
+
if ((flags & 15) !== 0) throw new UnknownHashVariantError(`unsupported hash variant ${String(flags & 15)}`);
|
|
213
166
|
assertMinBodyLength(body.length, 16, "fuse");
|
|
214
167
|
const dv = new DataView(body.buffer, body.byteOffset, body.byteLength);
|
|
215
168
|
const seed = dv.getUint32(0, true);
|
|
216
169
|
const seg = dv.getUint32(4, true);
|
|
217
170
|
const segCountLen = dv.getUint32(8, true);
|
|
218
171
|
const size = dv.getUint32(12, true);
|
|
172
|
+
if (seg === 0 || (seg & seg - 1) !== 0 || seg > 1 << 18) throw new SerializationError(`invalid fuse segment length ${String(seg)}`);
|
|
173
|
+
if (segCountLen % seg !== 0) throw new SerializationError(`fuse segment count length ${String(segCountLen)} is not a multiple of segment length ${String(seg)}`);
|
|
219
174
|
const bpe = expectedType === TYPE_FUSE8 ? 1 : 2;
|
|
220
175
|
const expectedArrayLength = size === 0 ? 0 : segCountLen + 2 * seg;
|
|
221
176
|
assertBodyLength(body.length, 16 + expectedArrayLength * bpe, "fuse");
|
|
@@ -259,6 +214,10 @@ var BinaryFuse = class {
|
|
|
259
214
|
get size() {
|
|
260
215
|
return this.#size;
|
|
261
216
|
}
|
|
217
|
+
/** Hash seed selected during construction (may differ from 0 after a peel retry). */
|
|
218
|
+
get seed() {
|
|
219
|
+
return this.#seed;
|
|
220
|
+
}
|
|
262
221
|
/** Actual bits stored per key (`0` for an empty filter). */
|
|
263
222
|
get bitsPerKey() {
|
|
264
223
|
return this.#size === 0 ? 0 : this.#fp.byteLength * 8 / this.#size;
|
|
@@ -270,18 +229,17 @@ var BinaryFuse = class {
|
|
|
270
229
|
*/
|
|
271
230
|
toBytes() {
|
|
272
231
|
const laneBytes = new Uint8Array(this.#fp.buffer, this.#fp.byteOffset, this.#fp.byteLength);
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
dv.setUint32(0, this.#seed, true);
|
|
276
|
-
dv.setUint32(4, this.#seg, true);
|
|
277
|
-
dv.setUint32(8, this.#segCountLen, true);
|
|
278
|
-
dv.setUint32(12, this.#size, true);
|
|
279
|
-
body.set(laneBytes, 16);
|
|
280
|
-
return writeHeader({
|
|
281
|
-
version: 2,
|
|
232
|
+
return writeFrame({
|
|
233
|
+
version: 3,
|
|
282
234
|
type: this.#fp.BYTES_PER_ELEMENT === 1 ? TYPE_FUSE8 : TYPE_FUSE16,
|
|
283
235
|
flags: 0
|
|
284
|
-
}, body)
|
|
236
|
+
}, 16 + laneBytes.length, (body, dv) => {
|
|
237
|
+
dv.setUint32(0, this.#seed, true);
|
|
238
|
+
dv.setUint32(4, this.#seg, true);
|
|
239
|
+
dv.setUint32(8, this.#segCountLen, true);
|
|
240
|
+
dv.setUint32(12, this.#size, true);
|
|
241
|
+
body.set(laneBytes, 16);
|
|
242
|
+
});
|
|
285
243
|
}
|
|
286
244
|
/**
|
|
287
245
|
* Tests whether a key is in the set.
|
|
@@ -292,7 +250,7 @@ var BinaryFuse = class {
|
|
|
292
250
|
has(key) {
|
|
293
251
|
if (this.#fp.length === 0) return false;
|
|
294
252
|
hash128KeyInto(key, 0, scratchHash);
|
|
295
|
-
mixSeed(scratchHash.
|
|
253
|
+
mixSeed(scratchHash.w0 >>> 0, scratchHash.w1 >>> 0, this.#seed);
|
|
296
254
|
const mlo = RLO;
|
|
297
255
|
const mhi = RHI;
|
|
298
256
|
positionsInto(mlo, mhi, this.#seg, this.#segMask, this.#segCountLen, this.#pos);
|
|
@@ -302,6 +260,26 @@ var BinaryFuse = class {
|
|
|
302
260
|
const p2 = this.#pos[2] ?? 0;
|
|
303
261
|
return ((mlo ^ mhi) & mask) === (((this.#fp[p0] ?? 0) ^ (this.#fp[p1] ?? 0) ^ (this.#fp[p2] ?? 0)) & mask);
|
|
304
262
|
}
|
|
263
|
+
/**
|
|
264
|
+
* Tests structural equality: `true` when `other` serializes to identical
|
|
265
|
+
* bytes. A {@link BinaryFuse8} and a {@link BinaryFuse16} are never equal,
|
|
266
|
+
* since their frames carry different type bytes.
|
|
267
|
+
*
|
|
268
|
+
* @param other - The filter to compare against.
|
|
269
|
+
* @returns `true` if the two filters are byte-for-byte identical.
|
|
270
|
+
*/
|
|
271
|
+
equals(other) {
|
|
272
|
+
return bytesEqual(this.toBytes(), other.toBytes());
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Serializes the filter to a JSON-friendly envelope wrapping the base64 of
|
|
276
|
+
* the `toBytes` frame.
|
|
277
|
+
*
|
|
278
|
+
* @returns The envelope, readable by the matching `fromJSON`.
|
|
279
|
+
*/
|
|
280
|
+
toJSON() {
|
|
281
|
+
return toJSONEnvelope(this.toBytes());
|
|
282
|
+
}
|
|
305
283
|
};
|
|
306
284
|
/**
|
|
307
285
|
* A static 8-bit binary fuse filter: built once from a key set, then immutable.
|
|
@@ -334,6 +312,15 @@ var BinaryFuse8 = class BinaryFuse8 extends BinaryFuse {
|
|
|
334
312
|
static fromBytes(bytes) {
|
|
335
313
|
return new BinaryFuse8(fuseStateFromBytes(bytes, TYPE_FUSE8));
|
|
336
314
|
}
|
|
315
|
+
/**
|
|
316
|
+
* Restores a filter from its {@link BinaryFuse8.toJSON} envelope.
|
|
317
|
+
*
|
|
318
|
+
* @param value - The JSON envelope.
|
|
319
|
+
* @returns The reconstructed filter.
|
|
320
|
+
*/
|
|
321
|
+
static fromJSON(value) {
|
|
322
|
+
return BinaryFuse8.fromBytes(fromJSONEnvelope(value));
|
|
323
|
+
}
|
|
337
324
|
};
|
|
338
325
|
/**
|
|
339
326
|
* A static 16-bit binary fuse filter: like {@link BinaryFuse8} but twice the
|
|
@@ -365,6 +352,15 @@ var BinaryFuse16 = class BinaryFuse16 extends BinaryFuse {
|
|
|
365
352
|
static fromBytes(bytes) {
|
|
366
353
|
return new BinaryFuse16(fuseStateFromBytes(bytes, TYPE_FUSE16));
|
|
367
354
|
}
|
|
355
|
+
/**
|
|
356
|
+
* Restores a filter from its {@link BinaryFuse16.toJSON} envelope.
|
|
357
|
+
*
|
|
358
|
+
* @param value - The JSON envelope.
|
|
359
|
+
* @returns The reconstructed filter.
|
|
360
|
+
*/
|
|
361
|
+
static fromJSON(value) {
|
|
362
|
+
return BinaryFuse16.fromBytes(fromJSONEnvelope(value));
|
|
363
|
+
}
|
|
368
364
|
};
|
|
369
365
|
//#endregion
|
|
370
366
|
export { BinaryFuse16, BinaryFuse8, BinaryFuseBuildError };
|
package/dist/index.cjs
CHANGED
package/dist/index.js
CHANGED
|
@@ -12,6 +12,10 @@ function assertPositiveInt(value, label) {
|
|
|
12
12
|
function assertPositiveFinite(value, label) {
|
|
13
13
|
if (!Number.isFinite(value) || value <= 0) throw new ParamError(`${label} must be a positive number, got ${String(value)}`);
|
|
14
14
|
}
|
|
15
|
+
/** Asserts `value` is an integer in the uint16 range `[0, 65535]`. */
|
|
16
|
+
function assertUint16(value, label) {
|
|
17
|
+
if (!Number.isInteger(value) || value < 0 || value > 65535) throw new ParamError(`${label} must be a uint16, got ${String(value)}`);
|
|
18
|
+
}
|
|
15
19
|
/** Asserts `value` is an integer in the uint32 range `[0, 2^32 - 1]`. */
|
|
16
20
|
function assertUint32(value, label) {
|
|
17
21
|
if (!Number.isInteger(value) || value < 0 || value > 4294967295) throw new ParamError(`${label} must be a uint32, got ${String(value)}`);
|
|
@@ -45,6 +49,12 @@ Object.defineProperty(exports, "assertProbability", {
|
|
|
45
49
|
return assertProbability;
|
|
46
50
|
}
|
|
47
51
|
});
|
|
52
|
+
Object.defineProperty(exports, "assertUint16", {
|
|
53
|
+
enumerable: true,
|
|
54
|
+
get: function() {
|
|
55
|
+
return assertUint16;
|
|
56
|
+
}
|
|
57
|
+
});
|
|
48
58
|
Object.defineProperty(exports, "assertUint32", {
|
|
49
59
|
enumerable: true,
|
|
50
60
|
get: function() {
|
|
@@ -12,6 +12,10 @@ function assertPositiveInt(value, label) {
|
|
|
12
12
|
function assertPositiveFinite(value, label) {
|
|
13
13
|
if (!Number.isFinite(value) || value <= 0) throw new ParamError(`${label} must be a positive number, got ${String(value)}`);
|
|
14
14
|
}
|
|
15
|
+
/** Asserts `value` is an integer in the uint16 range `[0, 65535]`. */
|
|
16
|
+
function assertUint16(value, label) {
|
|
17
|
+
if (!Number.isInteger(value) || value < 0 || value > 65535) throw new ParamError(`${label} must be a uint16, got ${String(value)}`);
|
|
18
|
+
}
|
|
15
19
|
/** Asserts `value` is an integer in the uint32 range `[0, 2^32 - 1]`. */
|
|
16
20
|
function assertUint32(value, label) {
|
|
17
21
|
if (!Number.isInteger(value) || value < 0 || value > 4294967295) throw new ParamError(`${label} must be a uint32, got ${String(value)}`);
|
|
@@ -21,4 +25,4 @@ function assertProbability(value, label) {
|
|
|
21
25
|
if (!Number.isFinite(value) || value <= 0 || value >= 1) throw new ParamError(`${label} must be in the open interval (0, 1), got ${String(value)}`);
|
|
22
26
|
}
|
|
23
27
|
//#endregion
|
|
24
|
-
export {
|
|
28
|
+
export { assertUint16 as a, assertProbability as i, assertPositiveFinite as n, assertUint32 as o, assertPositiveInt as r, ParamError as t };
|