distillate 0.14.0 → 0.14.1
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/dist/cuckoo/index.cjs +19 -8
- package/dist/cuckoo/index.js +19 -8
- package/dist/distinct-BhxDB8mW.js +61 -0
- package/dist/distinct-Ck5PKuCS.cjs +66 -0
- package/dist/fuse/index.cjs +5 -10
- package/dist/fuse/index.js +5 -10
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/package.json +7 -7
package/dist/cuckoo/index.cjs
CHANGED
|
@@ -2,6 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
2
2
|
const require_hasher = require("../hasher-DPXmP7SH.cjs");
|
|
3
3
|
const require_serialize = require("../serialize-CHikZ4GH.cjs");
|
|
4
4
|
const require_params = require("../params-UTZbJ22c.cjs");
|
|
5
|
+
const require_distinct = require("../distinct-Ck5PKuCS.cjs");
|
|
5
6
|
function cuckooSizing(n, epsilon) {
|
|
6
7
|
require_params.assertProbability(epsilon, "epsilon");
|
|
7
8
|
const f = Math.max(4, Math.ceil(Math.log2(8 / epsilon)));
|
|
@@ -54,17 +55,21 @@ var CuckooFilter = class CuckooFilter {
|
|
|
54
55
|
});
|
|
55
56
|
}
|
|
56
57
|
static from(keys, epsilon, options = {}) {
|
|
57
|
-
const
|
|
58
|
-
const distinct = [];
|
|
58
|
+
const distinct = new require_distinct.DistinctHashes(4);
|
|
59
59
|
for (const key of keys) {
|
|
60
60
|
require_hasher.hash128KeyInto(key, options.seed ?? 0, HASH);
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
61
|
+
distinct.add(HASH);
|
|
62
|
+
}
|
|
63
|
+
const f = CuckooFilter.create(Math.max(1, distinct.size), epsilon, options);
|
|
64
|
+
const words = distinct.words;
|
|
65
|
+
for (let at = 0; at < words.length; at += 4) {
|
|
66
|
+
HASH.w0 = words[at] ?? 0;
|
|
67
|
+
HASH.w1 = words[at + 1] ?? 0;
|
|
68
|
+
HASH.w2 = words[at + 2] ?? 0;
|
|
69
|
+
HASH.w3 = words[at + 3] ?? 0;
|
|
70
|
+
f.#derive();
|
|
71
|
+
f.#insert();
|
|
65
72
|
}
|
|
66
|
-
const f = CuckooFilter.create(Math.max(1, distinct.length), epsilon, options);
|
|
67
|
-
for (const k of distinct) f.add(k);
|
|
68
73
|
return f;
|
|
69
74
|
}
|
|
70
75
|
static fromBytes(bytes) {
|
|
@@ -134,6 +139,9 @@ var CuckooFilter = class CuckooFilter {
|
|
|
134
139
|
}
|
|
135
140
|
add(key) {
|
|
136
141
|
this.#hash(key);
|
|
142
|
+
this.#insert();
|
|
143
|
+
}
|
|
144
|
+
#insert() {
|
|
137
145
|
if (this.#replace(this.#i1, 0, this.#fp) || this.#replace(this.#i2, 0, this.#fp)) {
|
|
138
146
|
this.#count++;
|
|
139
147
|
return;
|
|
@@ -202,6 +210,9 @@ var CuckooFilter = class CuckooFilter {
|
|
|
202
210
|
}
|
|
203
211
|
#hash(key) {
|
|
204
212
|
require_hasher.hash128KeyInto(key, this.#seed, HASH);
|
|
213
|
+
this.#derive();
|
|
214
|
+
}
|
|
215
|
+
#derive() {
|
|
205
216
|
this.#fp = HASH.w1 >>> 32 - this.#f || 1;
|
|
206
217
|
this.#i1 = require_hasher.reduce(HASH.w0, this.#buckets);
|
|
207
218
|
this.#i2 = this.#alt(this.#i1, this.#fp);
|
package/dist/cuckoo/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { i as hash128KeyInto, u as reduce } from "../hasher-DOdmZ-LI.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, u as assertParamsPadding } from "../serialize-CMSYFym-.js";
|
|
3
3
|
import { i as assertProbability, o as assertUint32, r as assertPositiveInt, t as ParamError } from "../params-CeajSrwv.js";
|
|
4
|
+
import { t as DistinctHashes } from "../distinct-BhxDB8mW.js";
|
|
4
5
|
function cuckooSizing(n, epsilon) {
|
|
5
6
|
assertProbability(epsilon, "epsilon");
|
|
6
7
|
const f = Math.max(4, Math.ceil(Math.log2(8 / epsilon)));
|
|
@@ -53,17 +54,21 @@ var CuckooFilter = class CuckooFilter {
|
|
|
53
54
|
});
|
|
54
55
|
}
|
|
55
56
|
static from(keys, epsilon, options = {}) {
|
|
56
|
-
const
|
|
57
|
-
const distinct = [];
|
|
57
|
+
const distinct = new DistinctHashes(4);
|
|
58
58
|
for (const key of keys) {
|
|
59
59
|
hash128KeyInto(key, options.seed ?? 0, HASH);
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
60
|
+
distinct.add(HASH);
|
|
61
|
+
}
|
|
62
|
+
const f = CuckooFilter.create(Math.max(1, distinct.size), epsilon, options);
|
|
63
|
+
const words = distinct.words;
|
|
64
|
+
for (let at = 0; at < words.length; at += 4) {
|
|
65
|
+
HASH.w0 = words[at] ?? 0;
|
|
66
|
+
HASH.w1 = words[at + 1] ?? 0;
|
|
67
|
+
HASH.w2 = words[at + 2] ?? 0;
|
|
68
|
+
HASH.w3 = words[at + 3] ?? 0;
|
|
69
|
+
f.#derive();
|
|
70
|
+
f.#insert();
|
|
64
71
|
}
|
|
65
|
-
const f = CuckooFilter.create(Math.max(1, distinct.length), epsilon, options);
|
|
66
|
-
for (const k of distinct) f.add(k);
|
|
67
72
|
return f;
|
|
68
73
|
}
|
|
69
74
|
static fromBytes(bytes) {
|
|
@@ -133,6 +138,9 @@ var CuckooFilter = class CuckooFilter {
|
|
|
133
138
|
}
|
|
134
139
|
add(key) {
|
|
135
140
|
this.#hash(key);
|
|
141
|
+
this.#insert();
|
|
142
|
+
}
|
|
143
|
+
#insert() {
|
|
136
144
|
if (this.#replace(this.#i1, 0, this.#fp) || this.#replace(this.#i2, 0, this.#fp)) {
|
|
137
145
|
this.#count++;
|
|
138
146
|
return;
|
|
@@ -201,6 +209,9 @@ var CuckooFilter = class CuckooFilter {
|
|
|
201
209
|
}
|
|
202
210
|
#hash(key) {
|
|
203
211
|
hash128KeyInto(key, this.#seed, HASH);
|
|
212
|
+
this.#derive();
|
|
213
|
+
}
|
|
214
|
+
#derive() {
|
|
204
215
|
this.#fp = HASH.w1 >>> 32 - this.#f || 1;
|
|
205
216
|
this.#i1 = reduce(HASH.w0, this.#buckets);
|
|
206
217
|
this.#i2 = this.#alt(this.#i1, this.#fp);
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
//#region src/core/distinct.ts
|
|
2
|
+
const START = 1024;
|
|
3
|
+
var DistinctHashes = class {
|
|
4
|
+
#width;
|
|
5
|
+
#words;
|
|
6
|
+
#table = new Int32Array(2 * START);
|
|
7
|
+
#size = 0;
|
|
8
|
+
constructor(width) {
|
|
9
|
+
this.#width = width;
|
|
10
|
+
this.#words = new Uint32Array(START * width);
|
|
11
|
+
}
|
|
12
|
+
get size() {
|
|
13
|
+
return this.#size;
|
|
14
|
+
}
|
|
15
|
+
get words() {
|
|
16
|
+
return this.#words.subarray(0, this.#size * this.#width);
|
|
17
|
+
}
|
|
18
|
+
add(hash) {
|
|
19
|
+
const width = this.#width;
|
|
20
|
+
const w0 = hash.w0 >>> 0;
|
|
21
|
+
const w1 = hash.w1 >>> 0;
|
|
22
|
+
const w2 = hash.w2 >>> 0;
|
|
23
|
+
const w3 = hash.w3 >>> 0;
|
|
24
|
+
if ((this.#size + 1) * width > this.#words.length) this.#grow();
|
|
25
|
+
const words = this.#words;
|
|
26
|
+
const mask = this.#table.length - 1;
|
|
27
|
+
let slot = w0 & mask;
|
|
28
|
+
for (;;) {
|
|
29
|
+
const held = this.#table[slot] ?? 0;
|
|
30
|
+
if (held === 0) break;
|
|
31
|
+
const at = (held - 1) * width;
|
|
32
|
+
if (words[at] === w0 && words[at + 1] === w1 && (width === 2 || words[at + 2] === w2 && words[at + 3] === w3)) return false;
|
|
33
|
+
slot = slot + 1 & mask;
|
|
34
|
+
}
|
|
35
|
+
const at = this.#size * width;
|
|
36
|
+
words[at] = w0;
|
|
37
|
+
words[at + 1] = w1;
|
|
38
|
+
if (width === 4) {
|
|
39
|
+
words[at + 2] = w2;
|
|
40
|
+
words[at + 3] = w3;
|
|
41
|
+
}
|
|
42
|
+
this.#size++;
|
|
43
|
+
this.#table[slot] = this.#size;
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
#grow() {
|
|
47
|
+
const words = new Uint32Array(this.#words.length * 2);
|
|
48
|
+
words.set(this.#words);
|
|
49
|
+
this.#words = words;
|
|
50
|
+
this.#table = new Int32Array(this.#table.length * 2);
|
|
51
|
+
for (let i = 0; i < this.#size; i++) this.#place(i);
|
|
52
|
+
}
|
|
53
|
+
#place(i) {
|
|
54
|
+
const mask = this.#table.length - 1;
|
|
55
|
+
let slot = (this.#words[i * this.#width] ?? 0) & mask;
|
|
56
|
+
while ((this.#table[slot] ?? 0) !== 0) slot = slot + 1 & mask;
|
|
57
|
+
this.#table[slot] = i + 1;
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
//#endregion
|
|
61
|
+
export { DistinctHashes as t };
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
//#region src/core/distinct.ts
|
|
2
|
+
const START = 1024;
|
|
3
|
+
var DistinctHashes = class {
|
|
4
|
+
#width;
|
|
5
|
+
#words;
|
|
6
|
+
#table = new Int32Array(2 * START);
|
|
7
|
+
#size = 0;
|
|
8
|
+
constructor(width) {
|
|
9
|
+
this.#width = width;
|
|
10
|
+
this.#words = new Uint32Array(START * width);
|
|
11
|
+
}
|
|
12
|
+
get size() {
|
|
13
|
+
return this.#size;
|
|
14
|
+
}
|
|
15
|
+
get words() {
|
|
16
|
+
return this.#words.subarray(0, this.#size * this.#width);
|
|
17
|
+
}
|
|
18
|
+
add(hash) {
|
|
19
|
+
const width = this.#width;
|
|
20
|
+
const w0 = hash.w0 >>> 0;
|
|
21
|
+
const w1 = hash.w1 >>> 0;
|
|
22
|
+
const w2 = hash.w2 >>> 0;
|
|
23
|
+
const w3 = hash.w3 >>> 0;
|
|
24
|
+
if ((this.#size + 1) * width > this.#words.length) this.#grow();
|
|
25
|
+
const words = this.#words;
|
|
26
|
+
const mask = this.#table.length - 1;
|
|
27
|
+
let slot = w0 & mask;
|
|
28
|
+
for (;;) {
|
|
29
|
+
const held = this.#table[slot] ?? 0;
|
|
30
|
+
if (held === 0) break;
|
|
31
|
+
const at = (held - 1) * width;
|
|
32
|
+
if (words[at] === w0 && words[at + 1] === w1 && (width === 2 || words[at + 2] === w2 && words[at + 3] === w3)) return false;
|
|
33
|
+
slot = slot + 1 & mask;
|
|
34
|
+
}
|
|
35
|
+
const at = this.#size * width;
|
|
36
|
+
words[at] = w0;
|
|
37
|
+
words[at + 1] = w1;
|
|
38
|
+
if (width === 4) {
|
|
39
|
+
words[at + 2] = w2;
|
|
40
|
+
words[at + 3] = w3;
|
|
41
|
+
}
|
|
42
|
+
this.#size++;
|
|
43
|
+
this.#table[slot] = this.#size;
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
#grow() {
|
|
47
|
+
const words = new Uint32Array(this.#words.length * 2);
|
|
48
|
+
words.set(this.#words);
|
|
49
|
+
this.#words = words;
|
|
50
|
+
this.#table = new Int32Array(this.#table.length * 2);
|
|
51
|
+
for (let i = 0; i < this.#size; i++) this.#place(i);
|
|
52
|
+
}
|
|
53
|
+
#place(i) {
|
|
54
|
+
const mask = this.#table.length - 1;
|
|
55
|
+
let slot = (this.#words[i * this.#width] ?? 0) & mask;
|
|
56
|
+
while ((this.#table[slot] ?? 0) !== 0) slot = slot + 1 & mask;
|
|
57
|
+
this.#table[slot] = i + 1;
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
//#endregion
|
|
61
|
+
Object.defineProperty(exports, "DistinctHashes", {
|
|
62
|
+
enumerable: true,
|
|
63
|
+
get: function() {
|
|
64
|
+
return DistinctHashes;
|
|
65
|
+
}
|
|
66
|
+
});
|
package/dist/fuse/index.cjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_hasher = require("../hasher-DPXmP7SH.cjs");
|
|
3
3
|
const require_serialize = require("../serialize-CHikZ4GH.cjs");
|
|
4
|
+
const require_distinct = require("../distinct-Ck5PKuCS.cjs");
|
|
4
5
|
//#region src/fuse/fuse.ts
|
|
5
6
|
const ARITY = 3;
|
|
6
7
|
const TYPE_FUSE8 = 3;
|
|
@@ -131,18 +132,12 @@ function buildFingerprints(fp, hashes, params, maxAttempts = 100) {
|
|
|
131
132
|
throw new BinaryFuseBuildError("binary fuse construction failed");
|
|
132
133
|
}
|
|
133
134
|
function buildState(keys, alloc) {
|
|
134
|
-
const
|
|
135
|
-
const seen = new Set();
|
|
135
|
+
const distinct = new require_distinct.DistinctHashes(2);
|
|
136
136
|
for (const key of keys) {
|
|
137
137
|
require_hasher.hash128KeyInto(key, 0, scratchHash);
|
|
138
|
-
|
|
139
|
-
const hi = scratchHash.w1 >>> 0;
|
|
140
|
-
const id = `${String(lo)},${String(hi)}`;
|
|
141
|
-
if (seen.has(id)) continue;
|
|
142
|
-
seen.add(id);
|
|
143
|
-
hashList.push(lo, hi);
|
|
138
|
+
distinct.add(scratchHash);
|
|
144
139
|
}
|
|
145
|
-
const size =
|
|
140
|
+
const size = distinct.size;
|
|
146
141
|
const params = computeParams(size);
|
|
147
142
|
if (size === 0) return {
|
|
148
143
|
fp: alloc(0),
|
|
@@ -150,7 +145,7 @@ function buildState(keys, alloc) {
|
|
|
150
145
|
params,
|
|
151
146
|
size: 0
|
|
152
147
|
};
|
|
153
|
-
const hashes =
|
|
148
|
+
const hashes = distinct.words;
|
|
154
149
|
const fp = alloc(params.arrayLength);
|
|
155
150
|
return {
|
|
156
151
|
fp,
|
package/dist/fuse/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { i as hash128KeyInto, n as RLO, o as mul64, r as fmix64, t as RHI } from "../hasher-DOdmZ-LI.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
|
+
import { t as DistinctHashes } from "../distinct-BhxDB8mW.js";
|
|
3
4
|
//#region src/fuse/fuse.ts
|
|
4
5
|
const ARITY = 3;
|
|
5
6
|
const TYPE_FUSE8 = 3;
|
|
@@ -130,18 +131,12 @@ function buildFingerprints(fp, hashes, params, maxAttempts = 100) {
|
|
|
130
131
|
throw new BinaryFuseBuildError("binary fuse construction failed");
|
|
131
132
|
}
|
|
132
133
|
function buildState(keys, alloc) {
|
|
133
|
-
const
|
|
134
|
-
const seen = new Set();
|
|
134
|
+
const distinct = new DistinctHashes(2);
|
|
135
135
|
for (const key of keys) {
|
|
136
136
|
hash128KeyInto(key, 0, scratchHash);
|
|
137
|
-
|
|
138
|
-
const hi = scratchHash.w1 >>> 0;
|
|
139
|
-
const id = `${String(lo)},${String(hi)}`;
|
|
140
|
-
if (seen.has(id)) continue;
|
|
141
|
-
seen.add(id);
|
|
142
|
-
hashList.push(lo, hi);
|
|
137
|
+
distinct.add(scratchHash);
|
|
143
138
|
}
|
|
144
|
-
const size =
|
|
139
|
+
const size = distinct.size;
|
|
145
140
|
const params = computeParams(size);
|
|
146
141
|
if (size === 0) return {
|
|
147
142
|
fp: alloc(0),
|
|
@@ -149,7 +144,7 @@ function buildState(keys, alloc) {
|
|
|
149
144
|
params,
|
|
150
145
|
size: 0
|
|
151
146
|
};
|
|
152
|
-
const hashes =
|
|
147
|
+
const hashes = distinct.words;
|
|
153
148
|
const fp = alloc(params.arrayLength);
|
|
154
149
|
return {
|
|
155
150
|
fp,
|
package/dist/index.cjs
CHANGED
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "distillate",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.1",
|
|
4
4
|
"description": "Probabilistic data structures for JavaScript. Space-efficient, approximate-membership filters (Bloom, Blocked Bloom, Binary Fuse) with tunable error and a portable binary format; zero dependencies, universal.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"bloom-filter",
|
|
@@ -113,17 +113,17 @@
|
|
|
113
113
|
],
|
|
114
114
|
"devDependencies": {
|
|
115
115
|
"@arethetypeswrong/cli": "^0.18.5",
|
|
116
|
-
"@microsoft/api-extractor": "^7.59.
|
|
117
|
-
"@types/node": "^22.20.
|
|
118
|
-
"@vitest/coverage-v8": "^5.0.
|
|
119
|
-
"fast-check": "^4.10.
|
|
116
|
+
"@microsoft/api-extractor": "^7.59.2",
|
|
117
|
+
"@types/node": "^22.20.4",
|
|
118
|
+
"@vitest/coverage-v8": "^5.0.2",
|
|
119
|
+
"fast-check": "^4.10.2",
|
|
120
120
|
"mitata": "^1.0.34",
|
|
121
121
|
"publint": "^0.3.24",
|
|
122
122
|
"tsdown": "^0.23.0",
|
|
123
|
-
"tsx": "^4.23.
|
|
123
|
+
"tsx": "^4.23.15",
|
|
124
124
|
"typedoc": "^0.28.20",
|
|
125
125
|
"typescript": "^5.9.3",
|
|
126
|
-
"vitest": "^5.0.
|
|
126
|
+
"vitest": "^5.0.2"
|
|
127
127
|
},
|
|
128
128
|
"engines": {
|
|
129
129
|
"node": ">=22"
|