distillate 0.4.0 → 0.5.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 +4 -4
- package/dist/blocked/index.cjs +8 -12
- package/dist/blocked/index.js +8 -12
- package/dist/bloom/index.cjs +4 -3
- package/dist/bloom/index.js +4 -3
- package/dist/fuse/index.cjs +11 -59
- package/dist/fuse/index.js +1 -49
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/{serialize-DPdiySxq.cjs → serialize-BQ2UzZqq.js} +55 -56
- package/dist/{serialize-DkkBKDT0.js → serialize-fa-pEUGq.cjs} +138 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -43,7 +43,7 @@ Each structure ships as its own subpath, so you only bundle what you import.
|
|
|
43
43
|
| Import | Structure | Mutable? | Use for |
|
|
44
44
|
| -------------------- | ------------- | -------- | ---------------------------------------------------- |
|
|
45
45
|
| `distillate/bloom` | Classic Bloom | yes | Familiar default, migration from `bloom-filters` |
|
|
46
|
-
| `distillate/blocked` | Blocked Bloom | yes |
|
|
46
|
+
| `distillate/blocked` | Blocked Bloom | yes | Very large sets that outgrow CPU cache (10M+ keys) |
|
|
47
47
|
| `distillate/fuse` | Binary Fuse | no | Static set built once and queried a lot; least space |
|
|
48
48
|
|
|
49
49
|
### Classic Bloom (`distillate/bloom`)
|
|
@@ -72,7 +72,7 @@ filter.add("alice");
|
|
|
72
72
|
filter.has("alice"); // true
|
|
73
73
|
```
|
|
74
74
|
|
|
75
|
-
Same surface as Classic Bloom (`add` / `has` / `union` / `toBytes` / `fromBytes` / `bitsPerKey`). Confines every lookup to
|
|
75
|
+
Same surface as Classic Bloom (`add` / `has` / `union` / `toBytes` / `fromBytes` / `bitsPerKey`). Confines every lookup to a single cache line, which only pays off once the filter outgrows CPU cache. At typical sizes it matches Classic; for very large sets (tens of millions of keys, past L2/L3) it runs about 1.4x Classic's lookup throughput, at the cost of ~20-30% more space. Prefer Classic unless you are memory-bound at scale.
|
|
76
76
|
|
|
77
77
|
### Binary Fuse (`distillate/fuse`)
|
|
78
78
|
|
|
@@ -98,10 +98,10 @@ Classic Bloom head-to-head at a **matched 1% false-positive rate** over the same
|
|
|
98
98
|
|
|
99
99
|
| Classic Bloom | bits/key | measured FPR | `has` throughput |
|
|
100
100
|
| -------------- | -------- | ------------ | ---------------- |
|
|
101
|
-
| **distillate** | 9.59 | 1.03% | ~
|
|
101
|
+
| **distillate** | 9.59 | 1.03% | ~16 M ops/s |
|
|
102
102
|
| bloom-filters | 9.59 | 0.99% | ~0.29 M ops/s |
|
|
103
103
|
|
|
104
|
-
Same space, same accuracy, **~
|
|
104
|
+
Same space, same accuracy, **~56x the lookup throughput** of [`bloom-filters`](https://www.npmjs.com/package/bloom-filters) (the package distillate replaces), while hashing UTF-8 bytes with MurmurHash3 so filters stay portable and cross-language readable.
|
|
105
105
|
|
|
106
106
|
These are a point-in-time snapshot on one machine. The full report (blocked/fuse, 1M capacity, the `bloomfilter` micro-package) and exactly how it is measured live in the [distillate-bench](https://github.com/akshay-xp/distillate-bench) repo: [RESULTS.md](https://github.com/akshay-xp/distillate-bench/blob/main/RESULTS.md), [METHODOLOGY.md](https://github.com/akshay-xp/distillate-bench/blob/main/METHODOLOGY.md).
|
|
107
107
|
|
package/dist/blocked/index.cjs
CHANGED
|
@@ -1,15 +1,10 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_serialize = require("../serialize-
|
|
2
|
+
const require_serialize = require("../serialize-fa-pEUGq.cjs");
|
|
3
3
|
const require_params = require("../params-J8p3bKq5.cjs");
|
|
4
4
|
//#region src/blocked/blocked.ts
|
|
5
5
|
const TYPE = 2;
|
|
6
6
|
const SALT = Uint32Array.of(1203114875, 1150766481, 2284105051, 2729912477, 1884591559, 770785867, 2667333959, 1550580529);
|
|
7
|
-
const
|
|
8
|
-
h1lo: 0,
|
|
9
|
-
h1hi: 0,
|
|
10
|
-
h2lo: 0,
|
|
11
|
-
h2hi: 0
|
|
12
|
-
};
|
|
7
|
+
const scratch2 = /* @__PURE__ */ new Uint32Array(2);
|
|
13
8
|
/** Thrown when an operation requires two filters built with identical parameters. */
|
|
14
9
|
var BlockedBloomParamMismatchError = class extends Error {
|
|
15
10
|
/** Discriminates this error from other `Error`s. */
|
|
@@ -104,8 +99,9 @@ var BlockedBloomFilter = class BlockedBloomFilter {
|
|
|
104
99
|
* @returns The reconstructed filter.
|
|
105
100
|
*/
|
|
106
101
|
static fromBytes(bytes) {
|
|
107
|
-
const { type, body } = require_serialize.readHeader(bytes);
|
|
102
|
+
const { type, flags, body } = require_serialize.readHeader(bytes);
|
|
108
103
|
if (type !== TYPE) throw new require_serialize.SerializationError(`expected AMQF type ${String(TYPE)}, got ${String(type)}`);
|
|
104
|
+
if ((flags & 15) !== 1) throw new require_serialize.UnknownHashVariantError(`unsupported hash variant ${String(flags & 15)}`);
|
|
109
105
|
require_serialize.assertMinBodyLength(body.length, 12, "blocked");
|
|
110
106
|
const dv = new DataView(body.buffer, body.byteOffset, body.byteLength);
|
|
111
107
|
const numBlocks = dv.getUint32(0, true);
|
|
@@ -137,7 +133,7 @@ var BlockedBloomFilter = class BlockedBloomFilter {
|
|
|
137
133
|
return require_serialize.writeHeader({
|
|
138
134
|
version: 2,
|
|
139
135
|
type: TYPE,
|
|
140
|
-
flags:
|
|
136
|
+
flags: 1
|
|
141
137
|
}, body);
|
|
142
138
|
}
|
|
143
139
|
/**
|
|
@@ -185,9 +181,9 @@ var BlockedBloomFilter = class BlockedBloomFilter {
|
|
|
185
181
|
}
|
|
186
182
|
};
|
|
187
183
|
function fillBlock(key, numBlocks, seed, outWords, outBits) {
|
|
188
|
-
require_serialize.
|
|
189
|
-
const block = require_serialize.reduce(
|
|
190
|
-
const x =
|
|
184
|
+
require_serialize.hash32x2Into(key, seed, scratch2);
|
|
185
|
+
const block = require_serialize.reduce(scratch2[0] ?? 0, numBlocks);
|
|
186
|
+
const x = scratch2[1] ?? 0;
|
|
191
187
|
const base = block * 8;
|
|
192
188
|
for (let i = 0; i < 8; i++) {
|
|
193
189
|
outWords[i] = base + i;
|
package/dist/blocked/index.js
CHANGED
|
@@ -1,14 +1,9 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as readHeader, d as hash32x2Into, i as assertMinBodyLength, m as reduce, n as UnknownHashVariantError, o as writeHeader, r as assertBodyLength, t as SerializationError } from "../serialize-BQ2UzZqq.js";
|
|
2
2
|
import { a as assertUint32, i as assertProbability, n as assertPositiveFinite, r as assertPositiveInt, t as ParamError } from "../params-ChTRNxM9.js";
|
|
3
3
|
//#region src/blocked/blocked.ts
|
|
4
4
|
const TYPE = 2;
|
|
5
5
|
const SALT = Uint32Array.of(1203114875, 1150766481, 2284105051, 2729912477, 1884591559, 770785867, 2667333959, 1550580529);
|
|
6
|
-
const
|
|
7
|
-
h1lo: 0,
|
|
8
|
-
h1hi: 0,
|
|
9
|
-
h2lo: 0,
|
|
10
|
-
h2hi: 0
|
|
11
|
-
};
|
|
6
|
+
const scratch2 = /* @__PURE__ */ new Uint32Array(2);
|
|
12
7
|
/** Thrown when an operation requires two filters built with identical parameters. */
|
|
13
8
|
var BlockedBloomParamMismatchError = class extends Error {
|
|
14
9
|
/** Discriminates this error from other `Error`s. */
|
|
@@ -103,8 +98,9 @@ var BlockedBloomFilter = class BlockedBloomFilter {
|
|
|
103
98
|
* @returns The reconstructed filter.
|
|
104
99
|
*/
|
|
105
100
|
static fromBytes(bytes) {
|
|
106
|
-
const { type, body } = readHeader(bytes);
|
|
101
|
+
const { type, flags, body } = readHeader(bytes);
|
|
107
102
|
if (type !== TYPE) throw new SerializationError(`expected AMQF type ${String(TYPE)}, got ${String(type)}`);
|
|
103
|
+
if ((flags & 15) !== 1) throw new UnknownHashVariantError(`unsupported hash variant ${String(flags & 15)}`);
|
|
108
104
|
assertMinBodyLength(body.length, 12, "blocked");
|
|
109
105
|
const dv = new DataView(body.buffer, body.byteOffset, body.byteLength);
|
|
110
106
|
const numBlocks = dv.getUint32(0, true);
|
|
@@ -136,7 +132,7 @@ var BlockedBloomFilter = class BlockedBloomFilter {
|
|
|
136
132
|
return writeHeader({
|
|
137
133
|
version: 2,
|
|
138
134
|
type: TYPE,
|
|
139
|
-
flags:
|
|
135
|
+
flags: 1
|
|
140
136
|
}, body);
|
|
141
137
|
}
|
|
142
138
|
/**
|
|
@@ -184,9 +180,9 @@ var BlockedBloomFilter = class BlockedBloomFilter {
|
|
|
184
180
|
}
|
|
185
181
|
};
|
|
186
182
|
function fillBlock(key, numBlocks, seed, outWords, outBits) {
|
|
187
|
-
|
|
188
|
-
const block = reduce(
|
|
189
|
-
const x =
|
|
183
|
+
hash32x2Into(key, seed, scratch2);
|
|
184
|
+
const block = reduce(scratch2[0] ?? 0, numBlocks);
|
|
185
|
+
const x = scratch2[1] ?? 0;
|
|
190
186
|
const base = block * 8;
|
|
191
187
|
for (let i = 0; i < 8; i++) {
|
|
192
188
|
outWords[i] = base + i;
|
package/dist/bloom/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-fa-pEUGq.cjs");
|
|
3
3
|
const require_params = require("../params-J8p3bKq5.cjs");
|
|
4
4
|
//#region src/core/bitset.ts
|
|
5
5
|
var BitSetRangeError = class extends RangeError {
|
|
@@ -94,8 +94,9 @@ var BloomFilter = class BloomFilter {
|
|
|
94
94
|
* @returns The reconstructed filter.
|
|
95
95
|
*/
|
|
96
96
|
static fromBytes(bytes) {
|
|
97
|
-
const { type, body } = require_serialize.readHeader(bytes);
|
|
97
|
+
const { type, flags, body } = require_serialize.readHeader(bytes);
|
|
98
98
|
if (type !== TYPE) throw new require_serialize.SerializationError(`expected AMQF type ${String(TYPE)}, got ${String(type)}`);
|
|
99
|
+
if ((flags & 15) !== 1) throw new require_serialize.UnknownHashVariantError(`unsupported hash variant ${String(flags & 15)}`);
|
|
99
100
|
require_serialize.assertMinBodyLength(body.length, 14, "bloom");
|
|
100
101
|
const dv = new DataView(body.buffer, body.byteOffset, body.byteLength);
|
|
101
102
|
const m = dv.getUint32(0, true);
|
|
@@ -174,7 +175,7 @@ var BloomFilter = class BloomFilter {
|
|
|
174
175
|
return require_serialize.writeHeader({
|
|
175
176
|
version: 2,
|
|
176
177
|
type: TYPE,
|
|
177
|
-
flags:
|
|
178
|
+
flags: 1
|
|
178
179
|
}, body);
|
|
179
180
|
}
|
|
180
181
|
/**
|
package/dist/bloom/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as readHeader, i as assertMinBodyLength, n as UnknownHashVariantError, o as writeHeader, p as probeInto, r as assertBodyLength, t as SerializationError } from "../serialize-BQ2UzZqq.js";
|
|
2
2
|
import { a as assertUint32, i as assertProbability, r as assertPositiveInt, t as ParamError } from "../params-ChTRNxM9.js";
|
|
3
3
|
//#region src/core/bitset.ts
|
|
4
4
|
var BitSetRangeError = class extends RangeError {
|
|
@@ -93,8 +93,9 @@ var BloomFilter = class BloomFilter {
|
|
|
93
93
|
* @returns The reconstructed filter.
|
|
94
94
|
*/
|
|
95
95
|
static fromBytes(bytes) {
|
|
96
|
-
const { type, body } = readHeader(bytes);
|
|
96
|
+
const { type, flags, body } = readHeader(bytes);
|
|
97
97
|
if (type !== TYPE) throw new SerializationError(`expected AMQF type ${String(TYPE)}, got ${String(type)}`);
|
|
98
|
+
if ((flags & 15) !== 1) throw new UnknownHashVariantError(`unsupported hash variant ${String(flags & 15)}`);
|
|
98
99
|
assertMinBodyLength(body.length, 14, "bloom");
|
|
99
100
|
const dv = new DataView(body.buffer, body.byteOffset, body.byteLength);
|
|
100
101
|
const m = dv.getUint32(0, true);
|
|
@@ -173,7 +174,7 @@ var BloomFilter = class BloomFilter {
|
|
|
173
174
|
return writeHeader({
|
|
174
175
|
version: 2,
|
|
175
176
|
type: TYPE,
|
|
176
|
-
flags:
|
|
177
|
+
flags: 1
|
|
177
178
|
}, body);
|
|
178
179
|
}
|
|
179
180
|
/**
|
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-fa-pEUGq.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
13
|
h1lo: 0,
|
|
16
14
|
h1hi: 0,
|
|
17
15
|
h2lo: 0,
|
|
18
16
|
h2hi: 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;
|
|
@@ -294,8 +246,8 @@ var BinaryFuse = class {
|
|
|
294
246
|
if (this.#fp.length === 0) return false;
|
|
295
247
|
require_serialize.hash128KeyInto(key, 0, scratchHash);
|
|
296
248
|
mixSeed(scratchHash.h1lo >>> 0, scratchHash.h1hi >>> 0, this.#seed);
|
|
297
|
-
const mlo = RLO;
|
|
298
|
-
const mhi = RHI;
|
|
249
|
+
const mlo = require_serialize.RLO;
|
|
250
|
+
const mhi = require_serialize.RHI;
|
|
299
251
|
positionsInto(mlo, mhi, this.#seg, this.#segMask, this.#segCountLen, this.#pos);
|
|
300
252
|
const mask = fpMask(this.#fp);
|
|
301
253
|
const p0 = this.#pos[0] ?? 0;
|
package/dist/fuse/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as readHeader, c as RLO, f as mul64, i as assertMinBodyLength, l as fmix64, o as writeHeader, r as assertBodyLength, s as RHI, t as SerializationError, u as hash128KeyInto } from "../serialize-BQ2UzZqq.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
12
|
h1lo: 0,
|
|
15
13
|
h1hi: 0,
|
|
16
14
|
h2lo: 0,
|
|
17
15
|
h2hi: 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;
|
package/dist/index.cjs
CHANGED
package/dist/index.js
CHANGED
|
@@ -81,6 +81,37 @@ function fmix64(lo, hi) {
|
|
|
81
81
|
RLO = l;
|
|
82
82
|
RHI = h;
|
|
83
83
|
}
|
|
84
|
+
function murmur32(bytes, seed, len = bytes.length) {
|
|
85
|
+
let h = seed >>> 0;
|
|
86
|
+
const n = len & -4;
|
|
87
|
+
for (let i = 0; i < n; i += 4) {
|
|
88
|
+
let k = ((bytes[i] ?? 0) | (bytes[i + 1] ?? 0) << 8 | (bytes[i + 2] ?? 0) << 16 | (bytes[i + 3] ?? 0) << 24) >>> 0;
|
|
89
|
+
k = Math.imul(k, 3432918353);
|
|
90
|
+
k = (k << 15 | k >>> 17) >>> 0;
|
|
91
|
+
k = Math.imul(k, 461845907);
|
|
92
|
+
h = (h ^ k) >>> 0;
|
|
93
|
+
h = (h << 13 | h >>> 19) >>> 0;
|
|
94
|
+
h = Math.imul(h, 5) + 3864292196 >>> 0;
|
|
95
|
+
}
|
|
96
|
+
let k1 = 0;
|
|
97
|
+
const rem = len & 3;
|
|
98
|
+
if (rem >= 3) k1 ^= (bytes[n + 2] ?? 0) << 16;
|
|
99
|
+
if (rem >= 2) k1 ^= (bytes[n + 1] ?? 0) << 8;
|
|
100
|
+
if (rem >= 1) {
|
|
101
|
+
k1 ^= bytes[n] ?? 0;
|
|
102
|
+
k1 = Math.imul(k1 >>> 0, 3432918353);
|
|
103
|
+
k1 = (k1 << 15 | k1 >>> 17) >>> 0;
|
|
104
|
+
k1 = Math.imul(k1, 461845907);
|
|
105
|
+
h = (h ^ k1) >>> 0;
|
|
106
|
+
}
|
|
107
|
+
h = (h ^ len) >>> 0;
|
|
108
|
+
h ^= h >>> 16;
|
|
109
|
+
h = Math.imul(h, 2246822507);
|
|
110
|
+
h ^= h >>> 13;
|
|
111
|
+
h = Math.imul(h, 3266489909);
|
|
112
|
+
h ^= h >>> 16;
|
|
113
|
+
return h >>> 0;
|
|
114
|
+
}
|
|
84
115
|
function computeLanes(bytes, seed, len) {
|
|
85
116
|
const nblocks = len >>> 4;
|
|
86
117
|
let h1lo = seed >>> 0;
|
|
@@ -186,16 +217,22 @@ function computeLanes(bytes, seed, len) {
|
|
|
186
217
|
}
|
|
187
218
|
const keyEncoder = new TextEncoder();
|
|
188
219
|
let keyBuf = /* @__PURE__ */ new Uint8Array(256);
|
|
189
|
-
|
|
220
|
+
let encBytes = keyBuf;
|
|
221
|
+
let encLen = 0;
|
|
222
|
+
function encodeKey(key) {
|
|
190
223
|
if (typeof key === "string") {
|
|
191
224
|
const cap = key.length * 3;
|
|
192
225
|
if (keyBuf.length < cap) keyBuf = new Uint8Array(cap);
|
|
193
|
-
|
|
194
|
-
|
|
226
|
+
encLen = keyEncoder.encodeInto(key, keyBuf).written;
|
|
227
|
+
encBytes = keyBuf;
|
|
195
228
|
return;
|
|
196
229
|
}
|
|
197
|
-
|
|
198
|
-
|
|
230
|
+
encBytes = normalize(key);
|
|
231
|
+
encLen = encBytes.length;
|
|
232
|
+
}
|
|
233
|
+
function keyToLanes(key, seed) {
|
|
234
|
+
encodeKey(key);
|
|
235
|
+
computeLanes(encBytes, seed, encLen);
|
|
199
236
|
}
|
|
200
237
|
function hash128KeyInto(key, seed, out) {
|
|
201
238
|
keyToLanes(key, seed);
|
|
@@ -221,10 +258,16 @@ function reduce(x, range) {
|
|
|
221
258
|
* Kirsch-Mitzenmacher enhanced double hashing `g_i = h1 + i*h2 + i^2`
|
|
222
259
|
* (the RocksDB `+i^2` fix), reduced into range with Lemire multiply-shift.
|
|
223
260
|
*/
|
|
261
|
+
const SEED2 = 2654435761;
|
|
262
|
+
function hash32x2Into(key, seed, out) {
|
|
263
|
+
encodeKey(key);
|
|
264
|
+
out[0] = murmur32(encBytes, seed, encLen);
|
|
265
|
+
out[1] = murmur32(encBytes, (seed ^ SEED2) >>> 0, encLen);
|
|
266
|
+
}
|
|
224
267
|
function probeInto(key, count, range, seed, out) {
|
|
225
|
-
|
|
226
|
-
const a = (
|
|
227
|
-
const b = (
|
|
268
|
+
encodeKey(key);
|
|
269
|
+
const a = murmur32(encBytes, seed, encLen);
|
|
270
|
+
const b = murmur32(encBytes, (seed ^ SEED2) >>> 0, encLen);
|
|
228
271
|
for (let i = 0; i < count; i++) out[i] = reduce(a + Math.imul(i, b) + i * i >>> 0, range);
|
|
229
272
|
}
|
|
230
273
|
//#endregion
|
|
@@ -274,6 +317,9 @@ var BadMagicError = class extends SerializationError {
|
|
|
274
317
|
var UnknownVersionError = class extends SerializationError {
|
|
275
318
|
name = "UnknownVersionError";
|
|
276
319
|
};
|
|
320
|
+
var UnknownHashVariantError = class extends SerializationError {
|
|
321
|
+
name = "UnknownHashVariantError";
|
|
322
|
+
};
|
|
277
323
|
var ChecksumError = class extends SerializationError {
|
|
278
324
|
name = "ChecksumError";
|
|
279
325
|
};
|
|
@@ -305,51 +351,4 @@ function readHeader(frame) {
|
|
|
305
351
|
};
|
|
306
352
|
}
|
|
307
353
|
//#endregion
|
|
308
|
-
|
|
309
|
-
enumerable: true,
|
|
310
|
-
get: function() {
|
|
311
|
-
return SerializationError;
|
|
312
|
-
}
|
|
313
|
-
});
|
|
314
|
-
Object.defineProperty(exports, "assertBodyLength", {
|
|
315
|
-
enumerable: true,
|
|
316
|
-
get: function() {
|
|
317
|
-
return assertBodyLength;
|
|
318
|
-
}
|
|
319
|
-
});
|
|
320
|
-
Object.defineProperty(exports, "assertMinBodyLength", {
|
|
321
|
-
enumerable: true,
|
|
322
|
-
get: function() {
|
|
323
|
-
return assertMinBodyLength;
|
|
324
|
-
}
|
|
325
|
-
});
|
|
326
|
-
Object.defineProperty(exports, "hash128KeyInto", {
|
|
327
|
-
enumerable: true,
|
|
328
|
-
get: function() {
|
|
329
|
-
return hash128KeyInto;
|
|
330
|
-
}
|
|
331
|
-
});
|
|
332
|
-
Object.defineProperty(exports, "probeInto", {
|
|
333
|
-
enumerable: true,
|
|
334
|
-
get: function() {
|
|
335
|
-
return probeInto;
|
|
336
|
-
}
|
|
337
|
-
});
|
|
338
|
-
Object.defineProperty(exports, "readHeader", {
|
|
339
|
-
enumerable: true,
|
|
340
|
-
get: function() {
|
|
341
|
-
return readHeader;
|
|
342
|
-
}
|
|
343
|
-
});
|
|
344
|
-
Object.defineProperty(exports, "reduce", {
|
|
345
|
-
enumerable: true,
|
|
346
|
-
get: function() {
|
|
347
|
-
return reduce;
|
|
348
|
-
}
|
|
349
|
-
});
|
|
350
|
-
Object.defineProperty(exports, "writeHeader", {
|
|
351
|
-
enumerable: true,
|
|
352
|
-
get: function() {
|
|
353
|
-
return writeHeader;
|
|
354
|
-
}
|
|
355
|
-
});
|
|
354
|
+
export { readHeader as a, RLO as c, hash32x2Into as d, mul64 as f, assertMinBodyLength as i, fmix64 as l, reduce as m, UnknownHashVariantError as n, writeHeader as o, probeInto as p, assertBodyLength as r, RHI as s, SerializationError as t, hash128KeyInto as u };
|
|
@@ -81,6 +81,37 @@ function fmix64(lo, hi) {
|
|
|
81
81
|
RLO = l;
|
|
82
82
|
RHI = h;
|
|
83
83
|
}
|
|
84
|
+
function murmur32(bytes, seed, len = bytes.length) {
|
|
85
|
+
let h = seed >>> 0;
|
|
86
|
+
const n = len & -4;
|
|
87
|
+
for (let i = 0; i < n; i += 4) {
|
|
88
|
+
let k = ((bytes[i] ?? 0) | (bytes[i + 1] ?? 0) << 8 | (bytes[i + 2] ?? 0) << 16 | (bytes[i + 3] ?? 0) << 24) >>> 0;
|
|
89
|
+
k = Math.imul(k, 3432918353);
|
|
90
|
+
k = (k << 15 | k >>> 17) >>> 0;
|
|
91
|
+
k = Math.imul(k, 461845907);
|
|
92
|
+
h = (h ^ k) >>> 0;
|
|
93
|
+
h = (h << 13 | h >>> 19) >>> 0;
|
|
94
|
+
h = Math.imul(h, 5) + 3864292196 >>> 0;
|
|
95
|
+
}
|
|
96
|
+
let k1 = 0;
|
|
97
|
+
const rem = len & 3;
|
|
98
|
+
if (rem >= 3) k1 ^= (bytes[n + 2] ?? 0) << 16;
|
|
99
|
+
if (rem >= 2) k1 ^= (bytes[n + 1] ?? 0) << 8;
|
|
100
|
+
if (rem >= 1) {
|
|
101
|
+
k1 ^= bytes[n] ?? 0;
|
|
102
|
+
k1 = Math.imul(k1 >>> 0, 3432918353);
|
|
103
|
+
k1 = (k1 << 15 | k1 >>> 17) >>> 0;
|
|
104
|
+
k1 = Math.imul(k1, 461845907);
|
|
105
|
+
h = (h ^ k1) >>> 0;
|
|
106
|
+
}
|
|
107
|
+
h = (h ^ len) >>> 0;
|
|
108
|
+
h ^= h >>> 16;
|
|
109
|
+
h = Math.imul(h, 2246822507);
|
|
110
|
+
h ^= h >>> 13;
|
|
111
|
+
h = Math.imul(h, 3266489909);
|
|
112
|
+
h ^= h >>> 16;
|
|
113
|
+
return h >>> 0;
|
|
114
|
+
}
|
|
84
115
|
function computeLanes(bytes, seed, len) {
|
|
85
116
|
const nblocks = len >>> 4;
|
|
86
117
|
let h1lo = seed >>> 0;
|
|
@@ -186,16 +217,22 @@ function computeLanes(bytes, seed, len) {
|
|
|
186
217
|
}
|
|
187
218
|
const keyEncoder = new TextEncoder();
|
|
188
219
|
let keyBuf = /* @__PURE__ */ new Uint8Array(256);
|
|
189
|
-
|
|
220
|
+
let encBytes = keyBuf;
|
|
221
|
+
let encLen = 0;
|
|
222
|
+
function encodeKey(key) {
|
|
190
223
|
if (typeof key === "string") {
|
|
191
224
|
const cap = key.length * 3;
|
|
192
225
|
if (keyBuf.length < cap) keyBuf = new Uint8Array(cap);
|
|
193
|
-
|
|
194
|
-
|
|
226
|
+
encLen = keyEncoder.encodeInto(key, keyBuf).written;
|
|
227
|
+
encBytes = keyBuf;
|
|
195
228
|
return;
|
|
196
229
|
}
|
|
197
|
-
|
|
198
|
-
|
|
230
|
+
encBytes = normalize(key);
|
|
231
|
+
encLen = encBytes.length;
|
|
232
|
+
}
|
|
233
|
+
function keyToLanes(key, seed) {
|
|
234
|
+
encodeKey(key);
|
|
235
|
+
computeLanes(encBytes, seed, encLen);
|
|
199
236
|
}
|
|
200
237
|
function hash128KeyInto(key, seed, out) {
|
|
201
238
|
keyToLanes(key, seed);
|
|
@@ -221,10 +258,16 @@ function reduce(x, range) {
|
|
|
221
258
|
* Kirsch-Mitzenmacher enhanced double hashing `g_i = h1 + i*h2 + i^2`
|
|
222
259
|
* (the RocksDB `+i^2` fix), reduced into range with Lemire multiply-shift.
|
|
223
260
|
*/
|
|
261
|
+
const SEED2 = 2654435761;
|
|
262
|
+
function hash32x2Into(key, seed, out) {
|
|
263
|
+
encodeKey(key);
|
|
264
|
+
out[0] = murmur32(encBytes, seed, encLen);
|
|
265
|
+
out[1] = murmur32(encBytes, (seed ^ SEED2) >>> 0, encLen);
|
|
266
|
+
}
|
|
224
267
|
function probeInto(key, count, range, seed, out) {
|
|
225
|
-
|
|
226
|
-
const a = (
|
|
227
|
-
const b = (
|
|
268
|
+
encodeKey(key);
|
|
269
|
+
const a = murmur32(encBytes, seed, encLen);
|
|
270
|
+
const b = murmur32(encBytes, (seed ^ SEED2) >>> 0, encLen);
|
|
228
271
|
for (let i = 0; i < count; i++) out[i] = reduce(a + Math.imul(i, b) + i * i >>> 0, range);
|
|
229
272
|
}
|
|
230
273
|
//#endregion
|
|
@@ -274,6 +317,9 @@ var BadMagicError = class extends SerializationError {
|
|
|
274
317
|
var UnknownVersionError = class extends SerializationError {
|
|
275
318
|
name = "UnknownVersionError";
|
|
276
319
|
};
|
|
320
|
+
var UnknownHashVariantError = class extends SerializationError {
|
|
321
|
+
name = "UnknownHashVariantError";
|
|
322
|
+
};
|
|
277
323
|
var ChecksumError = class extends SerializationError {
|
|
278
324
|
name = "ChecksumError";
|
|
279
325
|
};
|
|
@@ -305,4 +351,87 @@ function readHeader(frame) {
|
|
|
305
351
|
};
|
|
306
352
|
}
|
|
307
353
|
//#endregion
|
|
308
|
-
|
|
354
|
+
Object.defineProperty(exports, "RHI", {
|
|
355
|
+
enumerable: true,
|
|
356
|
+
get: function() {
|
|
357
|
+
return RHI;
|
|
358
|
+
}
|
|
359
|
+
});
|
|
360
|
+
Object.defineProperty(exports, "RLO", {
|
|
361
|
+
enumerable: true,
|
|
362
|
+
get: function() {
|
|
363
|
+
return RLO;
|
|
364
|
+
}
|
|
365
|
+
});
|
|
366
|
+
Object.defineProperty(exports, "SerializationError", {
|
|
367
|
+
enumerable: true,
|
|
368
|
+
get: function() {
|
|
369
|
+
return SerializationError;
|
|
370
|
+
}
|
|
371
|
+
});
|
|
372
|
+
Object.defineProperty(exports, "UnknownHashVariantError", {
|
|
373
|
+
enumerable: true,
|
|
374
|
+
get: function() {
|
|
375
|
+
return UnknownHashVariantError;
|
|
376
|
+
}
|
|
377
|
+
});
|
|
378
|
+
Object.defineProperty(exports, "assertBodyLength", {
|
|
379
|
+
enumerable: true,
|
|
380
|
+
get: function() {
|
|
381
|
+
return assertBodyLength;
|
|
382
|
+
}
|
|
383
|
+
});
|
|
384
|
+
Object.defineProperty(exports, "assertMinBodyLength", {
|
|
385
|
+
enumerable: true,
|
|
386
|
+
get: function() {
|
|
387
|
+
return assertMinBodyLength;
|
|
388
|
+
}
|
|
389
|
+
});
|
|
390
|
+
Object.defineProperty(exports, "fmix64", {
|
|
391
|
+
enumerable: true,
|
|
392
|
+
get: function() {
|
|
393
|
+
return fmix64;
|
|
394
|
+
}
|
|
395
|
+
});
|
|
396
|
+
Object.defineProperty(exports, "hash128KeyInto", {
|
|
397
|
+
enumerable: true,
|
|
398
|
+
get: function() {
|
|
399
|
+
return hash128KeyInto;
|
|
400
|
+
}
|
|
401
|
+
});
|
|
402
|
+
Object.defineProperty(exports, "hash32x2Into", {
|
|
403
|
+
enumerable: true,
|
|
404
|
+
get: function() {
|
|
405
|
+
return hash32x2Into;
|
|
406
|
+
}
|
|
407
|
+
});
|
|
408
|
+
Object.defineProperty(exports, "mul64", {
|
|
409
|
+
enumerable: true,
|
|
410
|
+
get: function() {
|
|
411
|
+
return mul64;
|
|
412
|
+
}
|
|
413
|
+
});
|
|
414
|
+
Object.defineProperty(exports, "probeInto", {
|
|
415
|
+
enumerable: true,
|
|
416
|
+
get: function() {
|
|
417
|
+
return probeInto;
|
|
418
|
+
}
|
|
419
|
+
});
|
|
420
|
+
Object.defineProperty(exports, "readHeader", {
|
|
421
|
+
enumerable: true,
|
|
422
|
+
get: function() {
|
|
423
|
+
return readHeader;
|
|
424
|
+
}
|
|
425
|
+
});
|
|
426
|
+
Object.defineProperty(exports, "reduce", {
|
|
427
|
+
enumerable: true,
|
|
428
|
+
get: function() {
|
|
429
|
+
return reduce;
|
|
430
|
+
}
|
|
431
|
+
});
|
|
432
|
+
Object.defineProperty(exports, "writeHeader", {
|
|
433
|
+
enumerable: true,
|
|
434
|
+
get: function() {
|
|
435
|
+
return writeHeader;
|
|
436
|
+
}
|
|
437
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "distillate",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
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",
|