distillate 0.10.0 → 0.12.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.
@@ -0,0 +1,164 @@
1
+ import { t as BytesLike } from "../bytes-DCuYtUVS.cjs";
2
+ import { a as ReservedBitsError, c as UnknownHashVariantError, l as UnknownVersionError, n as ChecksumError, o as SerializationError, r as FilterJSON, s as TruncatedError, t as BadMagicError } from "../serialize--xR6vGSW.cjs";
3
+ import { t as ParamError } from "../params-DnqJBqLS.cjs";
4
+ //#region src/cuckoo/cuckoo.d.ts
5
+ /** Thrown when an add cannot find room; the filter is left exactly as it was. */
6
+ export declare class CuckooFullError extends Error {
7
+ /** Discriminates this error from other `Error`s. */
8
+ override readonly name = "CuckooFullError";
9
+ }
10
+ /** Settings for a {@link CuckooFilter}. */
11
+ interface CuckooParams {
12
+ /** Expected number of keys. */
13
+ n: number;
14
+ /** Target false-positive rate at `n` keys, e.g. `0.01` for 1%. */
15
+ epsilon: number;
16
+ /** Hash seed; defaults to `0`. */
17
+ seed?: number;
18
+ }
19
+ /** The optional settings {@link CuckooFilter.create} takes after `n` and `epsilon`. */
20
+ type CuckooOptions = Omit<CuckooParams, "n" | "epsilon">;
21
+ /**
22
+ * A cuckoo filter: a set with a tunable false-positive rate, zero false
23
+ * negatives, and delete. Keys are stored as short fingerprints in one of two
24
+ * candidate buckets (Fan et al., "Cuckoo Filter: Practically Better Than
25
+ * Bloom", 2014).
26
+ */
27
+ export declare class CuckooFilter {
28
+ #private;
29
+ /**
30
+ * Creates a filter sized for `n` expected keys at a target false-positive rate.
31
+ *
32
+ * @param n - Expected number of keys.
33
+ * @param epsilon - Target false-positive rate, e.g. `0.01` for 1%.
34
+ * @param options - Optional seed.
35
+ * @returns A new, empty filter.
36
+ */
37
+ static create(n: number, epsilon: number, options?: CuckooOptions): CuckooFilter;
38
+ /**
39
+ * Builds a filter from the given keys; duplicates are ignored. It is sized
40
+ * for the distinct keys at the target false-positive rate, and holds each
41
+ * once, so a key listed twice needs one delete.
42
+ *
43
+ * @param keys - The keys to insert.
44
+ * @param epsilon - Target false-positive rate, e.g. `0.01` for 1%.
45
+ * @param options - Optional seed.
46
+ * @returns A new filter containing every key.
47
+ */
48
+ static from(keys: Iterable<BytesLike>, epsilon: number, options?: CuckooOptions): CuckooFilter;
49
+ /**
50
+ * Restores a filter from its {@link CuckooFilter.toBytes} serialization.
51
+ *
52
+ * @param bytes - The serialized filter.
53
+ * @returns The reconstructed filter.
54
+ */
55
+ static fromBytes(bytes: Uint8Array): CuckooFilter;
56
+ /**
57
+ * Restores a filter from its {@link CuckooFilter.toJSON} envelope.
58
+ *
59
+ * @param value - The parsed JSON envelope.
60
+ * @returns The reconstructed filter.
61
+ */
62
+ static fromJSON(value: unknown): CuckooFilter;
63
+ /**
64
+ * Constructs a filter from {@link CuckooParams}.
65
+ *
66
+ * @throws {@link ParamError} if a setting is invalid.
67
+ */
68
+ constructor({ n, epsilon, seed }: CuckooParams);
69
+ /**
70
+ * Adds `key`. Every call stores a fingerprint, including for a key already
71
+ * present, so each add needs its own delete.
72
+ *
73
+ * @throws {@link CuckooFullError} if the filter has no room for it.
74
+ */
75
+ add(key: BytesLike): void;
76
+ /**
77
+ * Removes one copy of `key`: the first slot holding its fingerprint in
78
+ * either candidate bucket.
79
+ *
80
+ * Only delete keys you added. A key never added can share a fingerprint and
81
+ * bucket with one that was, and deleting it removes that key's fingerprint
82
+ * instead, a false negative the filter cannot detect: it stores fingerprints,
83
+ * not keys, so it cannot tell the two apart.
84
+ *
85
+ * @returns `true` if a matching fingerprint was removed; `false`, with the
86
+ * filter unchanged, if there was none.
87
+ */
88
+ delete(key: BytesLike): boolean;
89
+ /**
90
+ * Tests whether `key` may be in the filter.
91
+ *
92
+ * @returns `false` if `key` is definitely absent; `true` if it was added
93
+ * (and not deleted) or on a false positive.
94
+ */
95
+ has(key: BytesLike): boolean;
96
+ /**
97
+ * Estimates the current false-positive rate from the load: a query compares
98
+ * its fingerprint against about `8 * count / capacity` occupied slots across
99
+ * its two buckets, each matching with probability `1 / (2^f - 1)`.
100
+ *
101
+ * @returns The estimated false-positive rate, `0` for an empty filter.
102
+ */
103
+ rate(): number;
104
+ /**
105
+ * Serializes the filter to a DSTL type 7 frame, readable by
106
+ * {@link CuckooFilter.fromBytes} and by any reader of the documented format.
107
+ *
108
+ * @returns The frame bytes.
109
+ */
110
+ toBytes(): Uint8Array;
111
+ /**
112
+ * Whether `other` holds the same settings and slots, so the two serialize to
113
+ * identical bytes. Which slot a key lands in depends on insertion order, so
114
+ * filters holding the same keys can still differ.
115
+ *
116
+ * @param other - The filter to compare against.
117
+ * @returns `true` if the two are indistinguishable.
118
+ */
119
+ equals(other: CuckooFilter): boolean;
120
+ /**
121
+ * Serializes the filter as a JSON envelope around its {@link CuckooFilter.toBytes} frame.
122
+ *
123
+ * @returns The JSON-safe envelope.
124
+ */
125
+ toJSON(): FilterJSON;
126
+ /** Fingerprints stored, one per add not undone by a delete. */
127
+ get count(): number;
128
+ /** Slots in the table, `4 * buckets`. */
129
+ get capacity(): number;
130
+ /** Number of 4-slot buckets. */
131
+ get buckets(): number;
132
+ /** Width of each stored fingerprint, in bits. */
133
+ get fingerprintBits(): number;
134
+ /** Total slot bits, `fingerprintBits * capacity`. */
135
+ get m(): number;
136
+ /** Slot bits per expected key, `m / n`. */
137
+ get bitsPerKey(): number;
138
+ /** Hash seed. */
139
+ get seed(): number;
140
+ /** Target false-positive rate at `n` keys. */
141
+ get epsilon(): number;
142
+ }
143
+ //#endregion
144
+ //#region src/cuckoo/sizing.d.ts
145
+ /** Cuckoo filter geometry: what a sizing solve determines. */
146
+ interface CuckooSizing {
147
+ /** Fingerprint width in bits. */
148
+ f: number;
149
+ /** Number of 4-slot buckets. */
150
+ buckets: number;
151
+ /** Slot bits per expected key, `4 * f * buckets / n`. */
152
+ bitsPerKey: number;
153
+ }
154
+ /**
155
+ * Cuckoo geometry for `n` keys at target FPR `epsilon`: `f` bits from the
156
+ * `2b / epsilon` bound with 4-slot buckets, and enough buckets for 95% load
157
+ * plus `sqrt(n)` slack. At exactly 95%, small tables fail to take `n` keys at
158
+ * about 0.6% of sizes (a few buckets collect more keys than they hold, which
159
+ * more kicks do not fix); the slack removed every failure in about 170k
160
+ * prototype runs and still leaves a million-key filter at 94.6% load.
161
+ */
162
+ export declare function cuckooSizing(n: number, epsilon: number): CuckooSizing;
163
+ //#endregion
164
+ export { BadMagicError, ChecksumError, type CuckooOptions, type CuckooParams, type CuckooSizing, type FilterJSON, ParamError, ReservedBitsError, SerializationError, TruncatedError, UnknownHashVariantError, UnknownVersionError };
@@ -0,0 +1,164 @@
1
+ import { t as BytesLike } from "../bytes-DCuYtUVS.js";
2
+ import { a as ReservedBitsError, c as UnknownHashVariantError, l as UnknownVersionError, n as ChecksumError, o as SerializationError, r as FilterJSON, s as TruncatedError, t as BadMagicError } from "../serialize--xR6vGSW.js";
3
+ import { t as ParamError } from "../params-DnqJBqLS.js";
4
+ //#region src/cuckoo/cuckoo.d.ts
5
+ /** Thrown when an add cannot find room; the filter is left exactly as it was. */
6
+ export declare class CuckooFullError extends Error {
7
+ /** Discriminates this error from other `Error`s. */
8
+ override readonly name = "CuckooFullError";
9
+ }
10
+ /** Settings for a {@link CuckooFilter}. */
11
+ interface CuckooParams {
12
+ /** Expected number of keys. */
13
+ n: number;
14
+ /** Target false-positive rate at `n` keys, e.g. `0.01` for 1%. */
15
+ epsilon: number;
16
+ /** Hash seed; defaults to `0`. */
17
+ seed?: number;
18
+ }
19
+ /** The optional settings {@link CuckooFilter.create} takes after `n` and `epsilon`. */
20
+ type CuckooOptions = Omit<CuckooParams, "n" | "epsilon">;
21
+ /**
22
+ * A cuckoo filter: a set with a tunable false-positive rate, zero false
23
+ * negatives, and delete. Keys are stored as short fingerprints in one of two
24
+ * candidate buckets (Fan et al., "Cuckoo Filter: Practically Better Than
25
+ * Bloom", 2014).
26
+ */
27
+ export declare class CuckooFilter {
28
+ #private;
29
+ /**
30
+ * Creates a filter sized for `n` expected keys at a target false-positive rate.
31
+ *
32
+ * @param n - Expected number of keys.
33
+ * @param epsilon - Target false-positive rate, e.g. `0.01` for 1%.
34
+ * @param options - Optional seed.
35
+ * @returns A new, empty filter.
36
+ */
37
+ static create(n: number, epsilon: number, options?: CuckooOptions): CuckooFilter;
38
+ /**
39
+ * Builds a filter from the given keys; duplicates are ignored. It is sized
40
+ * for the distinct keys at the target false-positive rate, and holds each
41
+ * once, so a key listed twice needs one delete.
42
+ *
43
+ * @param keys - The keys to insert.
44
+ * @param epsilon - Target false-positive rate, e.g. `0.01` for 1%.
45
+ * @param options - Optional seed.
46
+ * @returns A new filter containing every key.
47
+ */
48
+ static from(keys: Iterable<BytesLike>, epsilon: number, options?: CuckooOptions): CuckooFilter;
49
+ /**
50
+ * Restores a filter from its {@link CuckooFilter.toBytes} serialization.
51
+ *
52
+ * @param bytes - The serialized filter.
53
+ * @returns The reconstructed filter.
54
+ */
55
+ static fromBytes(bytes: Uint8Array): CuckooFilter;
56
+ /**
57
+ * Restores a filter from its {@link CuckooFilter.toJSON} envelope.
58
+ *
59
+ * @param value - The parsed JSON envelope.
60
+ * @returns The reconstructed filter.
61
+ */
62
+ static fromJSON(value: unknown): CuckooFilter;
63
+ /**
64
+ * Constructs a filter from {@link CuckooParams}.
65
+ *
66
+ * @throws {@link ParamError} if a setting is invalid.
67
+ */
68
+ constructor({ n, epsilon, seed }: CuckooParams);
69
+ /**
70
+ * Adds `key`. Every call stores a fingerprint, including for a key already
71
+ * present, so each add needs its own delete.
72
+ *
73
+ * @throws {@link CuckooFullError} if the filter has no room for it.
74
+ */
75
+ add(key: BytesLike): void;
76
+ /**
77
+ * Removes one copy of `key`: the first slot holding its fingerprint in
78
+ * either candidate bucket.
79
+ *
80
+ * Only delete keys you added. A key never added can share a fingerprint and
81
+ * bucket with one that was, and deleting it removes that key's fingerprint
82
+ * instead, a false negative the filter cannot detect: it stores fingerprints,
83
+ * not keys, so it cannot tell the two apart.
84
+ *
85
+ * @returns `true` if a matching fingerprint was removed; `false`, with the
86
+ * filter unchanged, if there was none.
87
+ */
88
+ delete(key: BytesLike): boolean;
89
+ /**
90
+ * Tests whether `key` may be in the filter.
91
+ *
92
+ * @returns `false` if `key` is definitely absent; `true` if it was added
93
+ * (and not deleted) or on a false positive.
94
+ */
95
+ has(key: BytesLike): boolean;
96
+ /**
97
+ * Estimates the current false-positive rate from the load: a query compares
98
+ * its fingerprint against about `8 * count / capacity` occupied slots across
99
+ * its two buckets, each matching with probability `1 / (2^f - 1)`.
100
+ *
101
+ * @returns The estimated false-positive rate, `0` for an empty filter.
102
+ */
103
+ rate(): number;
104
+ /**
105
+ * Serializes the filter to a DSTL type 7 frame, readable by
106
+ * {@link CuckooFilter.fromBytes} and by any reader of the documented format.
107
+ *
108
+ * @returns The frame bytes.
109
+ */
110
+ toBytes(): Uint8Array;
111
+ /**
112
+ * Whether `other` holds the same settings and slots, so the two serialize to
113
+ * identical bytes. Which slot a key lands in depends on insertion order, so
114
+ * filters holding the same keys can still differ.
115
+ *
116
+ * @param other - The filter to compare against.
117
+ * @returns `true` if the two are indistinguishable.
118
+ */
119
+ equals(other: CuckooFilter): boolean;
120
+ /**
121
+ * Serializes the filter as a JSON envelope around its {@link CuckooFilter.toBytes} frame.
122
+ *
123
+ * @returns The JSON-safe envelope.
124
+ */
125
+ toJSON(): FilterJSON;
126
+ /** Fingerprints stored, one per add not undone by a delete. */
127
+ get count(): number;
128
+ /** Slots in the table, `4 * buckets`. */
129
+ get capacity(): number;
130
+ /** Number of 4-slot buckets. */
131
+ get buckets(): number;
132
+ /** Width of each stored fingerprint, in bits. */
133
+ get fingerprintBits(): number;
134
+ /** Total slot bits, `fingerprintBits * capacity`. */
135
+ get m(): number;
136
+ /** Slot bits per expected key, `m / n`. */
137
+ get bitsPerKey(): number;
138
+ /** Hash seed. */
139
+ get seed(): number;
140
+ /** Target false-positive rate at `n` keys. */
141
+ get epsilon(): number;
142
+ }
143
+ //#endregion
144
+ //#region src/cuckoo/sizing.d.ts
145
+ /** Cuckoo filter geometry: what a sizing solve determines. */
146
+ interface CuckooSizing {
147
+ /** Fingerprint width in bits. */
148
+ f: number;
149
+ /** Number of 4-slot buckets. */
150
+ buckets: number;
151
+ /** Slot bits per expected key, `4 * f * buckets / n`. */
152
+ bitsPerKey: number;
153
+ }
154
+ /**
155
+ * Cuckoo geometry for `n` keys at target FPR `epsilon`: `f` bits from the
156
+ * `2b / epsilon` bound with 4-slot buckets, and enough buckets for 95% load
157
+ * plus `sqrt(n)` slack. At exactly 95%, small tables fail to take `n` keys at
158
+ * about 0.6% of sizes (a few buckets collect more keys than they hold, which
159
+ * more kicks do not fix); the slack removed every failure in about 170k
160
+ * prototype runs and still leaves a million-key filter at 94.6% load.
161
+ */
162
+ export declare function cuckooSizing(n: number, epsilon: number): CuckooSizing;
163
+ //#endregion
164
+ export { BadMagicError, ChecksumError, type CuckooOptions, type CuckooParams, type CuckooSizing, type FilterJSON, ParamError, ReservedBitsError, SerializationError, TruncatedError, UnknownHashVariantError, UnknownVersionError };
@@ -0,0 +1,267 @@
1
+ import { i as hash128KeyInto, u as reduce } from "../hasher-3Cyn7Yg-.js";
2
+ import { a as TruncatedError, c as assertBodyLength, d as bytesEqual, f as fromJSONEnvelope, g as writeFrame, h as toJSONEnvelope, i as SerializationError, l as assertMinBodyLength, m as readHeader, n as ChecksumError, o as UnknownHashVariantError, r as ReservedBitsError, s as UnknownVersionError, t as BadMagicError, u as assertParamsPadding } from "../serialize-CMSYFym-.js";
3
+ import { i as assertProbability, o as assertUint32, r as assertPositiveInt, t as ParamError } from "../params-CeajSrwv.js";
4
+ function cuckooSizing(n, epsilon) {
5
+ assertProbability(epsilon, "epsilon");
6
+ const f = Math.max(4, Math.ceil(Math.log2(8 / epsilon)));
7
+ if (f > 32) throw new ParamError(`epsilon ${String(epsilon)} needs a ${String(f)}-bit fingerprint, above the maximum ${String(32)} bits`);
8
+ const buckets = Math.ceil(n / 3.8) + Math.ceil(Math.sqrt(n));
9
+ return {
10
+ f,
11
+ buckets,
12
+ bitsPerKey: 4 * f * buckets / n
13
+ };
14
+ }
15
+ //#endregion
16
+ //#region src/cuckoo/cuckoo.ts
17
+ const TYPE = 7;
18
+ const PARAMS_SIZE = 32;
19
+ const PARAMS_FIELDS_END = 28;
20
+ const padded8 = (length) => Math.ceil(length / 8) * 8;
21
+ const wordBytes = (words) => new Uint8Array(words.buffer, words.byteOffset, words.byteLength);
22
+ const SLOTS = 4;
23
+ const MAX_KICKS = 500;
24
+ const UNDO_SLOT = new Float64Array(MAX_KICKS);
25
+ const UNDO_FP = new Uint32Array(MAX_KICKS);
26
+ const HASH = {
27
+ w0: 0,
28
+ w1: 0,
29
+ w2: 0,
30
+ w3: 0
31
+ };
32
+ let restoring;
33
+ var CuckooFullError = class extends Error {
34
+ name = "CuckooFullError";
35
+ };
36
+ var CuckooFilter = class CuckooFilter {
37
+ #n;
38
+ #epsilon;
39
+ #seed;
40
+ #f;
41
+ #buckets;
42
+ #mask;
43
+ #words;
44
+ #count = 0;
45
+ #fp = 0;
46
+ #i1 = 0;
47
+ #i2 = 0;
48
+ static create(n, epsilon, options = {}) {
49
+ return new CuckooFilter({
50
+ ...options,
51
+ n,
52
+ epsilon
53
+ });
54
+ }
55
+ static from(keys, epsilon, options = {}) {
56
+ const seen = new Set();
57
+ const distinct = [];
58
+ for (const key of keys) {
59
+ hash128KeyInto(key, options.seed ?? 0, HASH);
60
+ const id = `${String(HASH.w0)},${String(HASH.w1)},${String(HASH.w2)},${String(HASH.w3)}`;
61
+ if (seen.has(id)) continue;
62
+ seen.add(id);
63
+ distinct.push(key);
64
+ }
65
+ const f = CuckooFilter.create(Math.max(1, distinct.length), epsilon, options);
66
+ for (const k of distinct) f.add(k);
67
+ return f;
68
+ }
69
+ static fromBytes(bytes) {
70
+ const { type, flags, body } = readHeader(bytes);
71
+ if (type !== TYPE) throw new SerializationError(`expected DSTL type ${String(TYPE)}, got ${String(type)}`);
72
+ if ((flags & 15) !== 0) throw new UnknownHashVariantError(`unsupported hash variant ${String(flags & 15)}`);
73
+ assertMinBodyLength(body.length, PARAMS_SIZE, "cuckoo");
74
+ assertParamsPadding(body, PARAMS_FIELDS_END, PARAMS_SIZE, "cuckoo");
75
+ const view = new DataView(body.buffer, body.byteOffset, body.byteLength);
76
+ const params = {
77
+ n: view.getUint32(0, true),
78
+ seed: view.getUint32(4, true),
79
+ epsilon: view.getFloat64(8, true)
80
+ };
81
+ let filter;
82
+ try {
83
+ const f = view.getUint32(16, true);
84
+ const buckets = view.getUint32(20, true);
85
+ if (f < 4 || f > 32) throw new SerializationError(`cuckoo: stored f ${String(f)} is outside 4..${String(32)}`);
86
+ if (buckets < 1) throw new SerializationError("cuckoo: stored buckets is 0");
87
+ const m = f * SLOTS * buckets;
88
+ if (m > 4294967295) throw new SerializationError(`cuckoo: stored geometry gives m ${String(m)} bits, more than 2^32 - 1`);
89
+ const words = Math.ceil(m / 32);
90
+ assertBodyLength(body.length, PARAMS_SIZE + padded8(4 * words), "cuckoo");
91
+ restoring = {
92
+ f,
93
+ buckets
94
+ };
95
+ try {
96
+ filter = new CuckooFilter(params);
97
+ } finally {
98
+ restoring = void 0;
99
+ }
100
+ } catch (err) {
101
+ if (err instanceof ParamError) throw new SerializationError(`cuckoo: ${err.message}`);
102
+ throw err;
103
+ }
104
+ const words = filter.#words;
105
+ for (let w = 0; w < words.length; w++) words[w] = view.getUint32(PARAMS_SIZE + 4 * w, true);
106
+ const tail = filter.m % 32;
107
+ if (tail !== 0 && (words[words.length - 1] ?? 0) >>> tail !== 0) throw new SerializationError("cuckoo: bits set past the last slot");
108
+ if (body.subarray(PARAMS_SIZE + 4 * words.length).some((b) => b !== 0)) throw new SerializationError("cuckoo: slot padding is not zero");
109
+ const count = view.getUint32(24, true);
110
+ let occupied = 0;
111
+ for (let j = 0; j < filter.capacity; j++) if (filter.#slot(j) !== 0) occupied++;
112
+ if (count !== occupied) throw new SerializationError(`cuckoo: count ${String(count)} does not match ${String(occupied)} occupied slots`);
113
+ filter.#count = count;
114
+ return filter;
115
+ }
116
+ static fromJSON(value) {
117
+ return CuckooFilter.fromBytes(fromJSONEnvelope(value));
118
+ }
119
+ constructor({ n, epsilon, seed = 0 }) {
120
+ assertPositiveInt(n, "n");
121
+ assertUint32(n, "n");
122
+ assertProbability(epsilon, "epsilon");
123
+ assertUint32(seed, "seed");
124
+ const { f, buckets } = restoring ?? cuckooSizing(n, epsilon);
125
+ assertUint32(f * SLOTS * buckets, "m");
126
+ this.#n = n;
127
+ this.#epsilon = epsilon;
128
+ this.#seed = seed;
129
+ this.#f = f;
130
+ this.#buckets = buckets;
131
+ this.#mask = 2 ** f - 1;
132
+ this.#words = new Uint32Array(Math.ceil(f * SLOTS * buckets / 32));
133
+ }
134
+ add(key) {
135
+ this.#hash(key);
136
+ if (this.#replace(this.#i1, 0, this.#fp) || this.#replace(this.#i2, 0, this.#fp)) {
137
+ this.#count++;
138
+ return;
139
+ }
140
+ let i = (HASH.w2 & 1) === 0 ? this.#i1 : this.#i2;
141
+ let x = (HASH.w3 | 1) >>> 0;
142
+ let fp = this.#fp;
143
+ for (let kick = 0; kick < MAX_KICKS; kick++) {
144
+ x ^= x << 13;
145
+ x >>>= 0;
146
+ x ^= x >>> 17;
147
+ x ^= x << 5;
148
+ x >>>= 0;
149
+ const j = i * SLOTS + (x & 3);
150
+ const victim = this.#slot(j);
151
+ UNDO_SLOT[kick] = j;
152
+ UNDO_FP[kick] = victim;
153
+ this.#setSlot(j, fp);
154
+ fp = victim;
155
+ i = this.#alt(i, fp);
156
+ if (this.#replace(i, 0, fp)) {
157
+ this.#count++;
158
+ return;
159
+ }
160
+ }
161
+ for (let kick = 499; kick >= 0; kick--) this.#setSlot(UNDO_SLOT[kick] ?? 0, UNDO_FP[kick] ?? 0);
162
+ throw new CuckooFullError(`cuckoo filter is full at ${String(this.#count)} of ${String(this.capacity)} slots`);
163
+ }
164
+ delete(key) {
165
+ this.#hash(key);
166
+ const removed = this.#replace(this.#i1, this.#fp, 0) || this.#i2 !== this.#i1 && this.#replace(this.#i2, this.#fp, 0);
167
+ if (removed) this.#count--;
168
+ return removed;
169
+ }
170
+ has(key) {
171
+ this.#hash(key);
172
+ return this.#find(this.#i1, this.#fp) >= 0 || this.#find(this.#i2, this.#fp) >= 0;
173
+ }
174
+ rate() {
175
+ const occupied = 8 * this.#count / this.capacity;
176
+ return 1 - (1 - 1 / this.#mask) ** occupied;
177
+ }
178
+ toBytes() {
179
+ const words = this.#words;
180
+ return writeFrame({
181
+ version: 5,
182
+ type: TYPE,
183
+ flags: 0
184
+ }, PARAMS_SIZE, padded8(4 * words.length), (_, view) => {
185
+ view.setUint32(0, this.#n, true);
186
+ view.setUint32(4, this.#seed, true);
187
+ view.setFloat64(8, this.#epsilon, true);
188
+ view.setUint32(16, this.#f, true);
189
+ view.setUint32(20, this.#buckets, true);
190
+ view.setUint32(24, this.#count, true);
191
+ words.forEach((word, w) => {
192
+ view.setUint32(PARAMS_SIZE + 4 * w, word, true);
193
+ });
194
+ });
195
+ }
196
+ equals(other) {
197
+ return this.#n === other.#n && this.#epsilon === other.#epsilon && this.#seed === other.#seed && this.#count === other.#count && bytesEqual(wordBytes(this.#words), wordBytes(other.#words));
198
+ }
199
+ toJSON() {
200
+ return toJSONEnvelope(this.toBytes());
201
+ }
202
+ #hash(key) {
203
+ hash128KeyInto(key, this.#seed, HASH);
204
+ this.#fp = HASH.w1 >>> 32 - this.#f || 1;
205
+ this.#i1 = reduce(HASH.w0, this.#buckets);
206
+ this.#i2 = this.#alt(this.#i1, this.#fp);
207
+ }
208
+ #alt(i, fp) {
209
+ const b = this.#buckets;
210
+ return ((Math.imul(fp, 1540483477) >>> 0) % b + b - i) % b;
211
+ }
212
+ #find(bucket, value) {
213
+ for (let j = bucket * SLOTS; j < bucket * SLOTS + SLOTS; j++) if (this.#slot(j) === value) return j;
214
+ return -1;
215
+ }
216
+ #replace(bucket, from, to) {
217
+ const j = this.#find(bucket, from);
218
+ if (j < 0) return false;
219
+ this.#setSlot(j, to);
220
+ return true;
221
+ }
222
+ #slot(j) {
223
+ const bit = j * this.#f;
224
+ const w = bit >>> 5;
225
+ const off = bit & 31;
226
+ let v = (this.#words[w] ?? 0) >>> off;
227
+ if (off + this.#f > 32) v |= (this.#words[w + 1] ?? 0) << 32 - off;
228
+ return (v & this.#mask) >>> 0;
229
+ }
230
+ #setSlot(j, fp) {
231
+ const bit = j * this.#f;
232
+ const w = bit >>> 5;
233
+ const off = bit & 31;
234
+ const words = this.#words;
235
+ words[w] = (words[w] ?? 0) & ~(this.#mask << off) | fp << off;
236
+ if (off + this.#f > 32) {
237
+ const shift = 32 - off;
238
+ words[w + 1] = (words[w + 1] ?? 0) & ~(this.#mask >>> shift) | fp >>> shift;
239
+ }
240
+ }
241
+ get count() {
242
+ return this.#count;
243
+ }
244
+ get capacity() {
245
+ return SLOTS * this.#buckets;
246
+ }
247
+ get buckets() {
248
+ return this.#buckets;
249
+ }
250
+ get fingerprintBits() {
251
+ return this.#f;
252
+ }
253
+ get m() {
254
+ return this.#f * this.capacity;
255
+ }
256
+ get bitsPerKey() {
257
+ return this.m / this.#n;
258
+ }
259
+ get seed() {
260
+ return this.#seed;
261
+ }
262
+ get epsilon() {
263
+ return this.#epsilon;
264
+ }
265
+ };
266
+ //#endregion
267
+ export { BadMagicError, ChecksumError, CuckooFilter, CuckooFullError, ParamError, ReservedBitsError, SerializationError, TruncatedError, UnknownHashVariantError, UnknownVersionError, cuckooSizing };
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_hasher = require("../hasher-D8LCBTOM.cjs");
2
+ const require_hasher = require("../hasher-MhY7aQ8F.cjs");
3
3
  const require_serialize = require("../serialize-CHikZ4GH.cjs");
4
4
  //#region src/fuse/fuse.ts
5
5
  const ARITY = 3;
@@ -1,4 +1,4 @@
1
- import { i as hash128KeyInto, n as RLO, o as mul64, r as fmix64, t as RHI } from "../hasher-DVWXS_vJ.js";
1
+ import { i as hash128KeyInto, n as RLO, o as mul64, r as fmix64, t as RHI } from "../hasher-3Cyn7Yg-.js";
2
2
  import { a as TruncatedError, c as assertBodyLength, d as bytesEqual, f as fromJSONEnvelope, g as writeFrame, h as toJSONEnvelope, i as SerializationError, l as assertMinBodyLength, m as readHeader, n as ChecksumError, o as UnknownHashVariantError, r as ReservedBitsError, s as UnknownVersionError, t as BadMagicError } from "../serialize-CMSYFym-.js";
3
3
  //#region src/fuse/fuse.ts
4
4
  const ARITY = 3;
@@ -216,14 +216,15 @@ function hash32x2Into(key, seed, out) {
216
216
  out[0] = LANES.w0;
217
217
  out[1] = LANES.w1;
218
218
  }
219
+ function probeAt(a, b, i, range) {
220
+ return reduce(a + Math.imul(i, b) + i * i >>> 0, range);
221
+ }
222
+ function probeLanesInto(a, b, count, range, out) {
223
+ for (let i = 0; i < count; i++) out[i] = probeAt(a, b, i, range);
224
+ }
219
225
  function probeInto(key, count, range, seed, out) {
220
226
  keyToLanes(key, seed);
221
- const a = LANES.w0;
222
- const b = LANES.w1;
223
- for (let i = 0; i < count; i++) {
224
- const x = a + Math.imul(i, b) + i * i >>> 0;
225
- out[i] = reduce(x, range);
226
- }
227
+ probeLanesInto(LANES.w0, LANES.w1, count, range, out);
227
228
  }
228
229
  //#endregion
229
- export { hash32x2Into as a, reduce as c, hash128KeyInto as i, RLO as n, mul64 as o, fmix64 as r, probeInto as s, RHI as t };
230
+ export { hash32x2Into as a, probeInto as c, hash128KeyInto as i, probeLanesInto as l, RLO as n, mul64 as o, fmix64 as r, probeAt as s, RHI as t, reduce as u };
@@ -216,14 +216,15 @@ function hash32x2Into(key, seed, out) {
216
216
  out[0] = LANES.w0;
217
217
  out[1] = LANES.w1;
218
218
  }
219
+ function probeAt(a, b, i, range) {
220
+ return reduce(a + Math.imul(i, b) + i * i >>> 0, range);
221
+ }
222
+ function probeLanesInto(a, b, count, range, out) {
223
+ for (let i = 0; i < count; i++) out[i] = probeAt(a, b, i, range);
224
+ }
219
225
  function probeInto(key, count, range, seed, out) {
220
226
  keyToLanes(key, seed);
221
- const a = LANES.w0;
222
- const b = LANES.w1;
223
- for (let i = 0; i < count; i++) {
224
- const x = a + Math.imul(i, b) + i * i >>> 0;
225
- out[i] = reduce(x, range);
226
- }
227
+ probeLanesInto(LANES.w0, LANES.w1, count, range, out);
227
228
  }
228
229
  //#endregion
229
230
  Object.defineProperty(exports, "RHI", {
@@ -262,12 +263,24 @@ Object.defineProperty(exports, "mul64", {
262
263
  return mul64;
263
264
  }
264
265
  });
266
+ Object.defineProperty(exports, "probeAt", {
267
+ enumerable: true,
268
+ get: function() {
269
+ return probeAt;
270
+ }
271
+ });
265
272
  Object.defineProperty(exports, "probeInto", {
266
273
  enumerable: true,
267
274
  get: function() {
268
275
  return probeInto;
269
276
  }
270
277
  });
278
+ Object.defineProperty(exports, "probeLanesInto", {
279
+ enumerable: true,
280
+ get: function() {
281
+ return probeLanesInto;
282
+ }
283
+ });
271
284
  Object.defineProperty(exports, "reduce", {
272
285
  enumerable: true,
273
286
  get: function() {
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_hasher = require("../hasher-D8LCBTOM.cjs");
2
+ const require_hasher = require("../hasher-MhY7aQ8F.cjs");
3
3
  const require_serialize = require("../serialize-CHikZ4GH.cjs");
4
4
  const require_params = require("../params-UTZbJ22c.cjs");
5
5
  const require_sizing = require("../sizing-BLzZk2zr.cjs");