distillate 0.14.0 → 0.14.2

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.
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_hasher = require("../hasher-DPXmP7SH.cjs");
2
+ const require_hasher = require("../hasher-CKLP9Oqe.cjs");
3
3
  const require_serialize = require("../serialize-CHikZ4GH.cjs");
4
4
  const require_params = require("../params-UTZbJ22c.cjs");
5
5
  //#region src/blocked/blocked.ts
@@ -1,4 +1,4 @@
1
- import { a as hash32x2Into, u as reduce } from "../hasher-DOdmZ-LI.js";
1
+ import { a as hash32x2Into, u as reduce } from "../hasher-BQxNrCQC.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, n as assertPositiveFinite, o as assertUint32, r as assertPositiveInt, t as ParamError } from "../params-CeajSrwv.js";
4
4
  //#region src/blocked/blocked.ts
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_sizing = require("../sizing-Ch0SDdza.cjs");
3
- const require_hasher = require("../hasher-DPXmP7SH.cjs");
3
+ const require_hasher = require("../hasher-CKLP9Oqe.cjs");
4
4
  const require_serialize = require("../serialize-CHikZ4GH.cjs");
5
5
  const require_params = require("../params-UTZbJ22c.cjs");
6
6
  //#region src/bloom/bloom.ts
@@ -67,7 +67,7 @@ var BloomFilter = class BloomFilter {
67
67
  this.#m = m;
68
68
  this.#k = k;
69
69
  this.#seed = seed;
70
- this.#scratch = new Uint32Array(k);
70
+ this.#scratch = new Uint32Array(Math.max(k, 2));
71
71
  this.#n = n ?? Math.max(1, Math.round(m * Math.LN2 / k));
72
72
  }
73
73
  get m() {
@@ -131,8 +131,10 @@ var BloomFilter = class BloomFilter {
131
131
  for (let i = 0; i < this.#k; i++) this.#bits.set(this.#scratch[i] ?? 0);
132
132
  }
133
133
  has(key) {
134
- require_hasher.probeInto(key, this.#k, this.#m, this.#seed, this.#scratch);
135
- for (let i = 0; i < this.#k; i++) if (!this.#bits.get(this.#scratch[i] ?? 0)) return false;
134
+ require_hasher.hash32x2Into(key, this.#seed, this.#scratch);
135
+ const a = this.#scratch[0] ?? 0;
136
+ const b = this.#scratch[1] ?? 0;
137
+ for (let i = 0; i < this.#k; i++) if (!this.#bits.get(require_hasher.probeAt(a, b, i, this.#m))) return false;
136
138
  return true;
137
139
  }
138
140
  };
@@ -1,5 +1,5 @@
1
1
  import { n as BitSet, t as bloomSizing } from "../sizing-zxCBlyhO.js";
2
- import { c as probeInto } from "../hasher-DOdmZ-LI.js";
2
+ import { a as hash32x2Into, c as probeInto, s as probeAt } from "../hasher-BQxNrCQC.js";
3
3
  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";
4
4
  import { a as assertUint16, i as assertProbability, o as assertUint32, r as assertPositiveInt, t as ParamError } from "../params-CeajSrwv.js";
5
5
  //#region src/bloom/bloom.ts
@@ -66,7 +66,7 @@ var BloomFilter = class BloomFilter {
66
66
  this.#m = m;
67
67
  this.#k = k;
68
68
  this.#seed = seed;
69
- this.#scratch = new Uint32Array(k);
69
+ this.#scratch = new Uint32Array(Math.max(k, 2));
70
70
  this.#n = n ?? Math.max(1, Math.round(m * Math.LN2 / k));
71
71
  }
72
72
  get m() {
@@ -130,8 +130,10 @@ var BloomFilter = class BloomFilter {
130
130
  for (let i = 0; i < this.#k; i++) this.#bits.set(this.#scratch[i] ?? 0);
131
131
  }
132
132
  has(key) {
133
- probeInto(key, this.#k, this.#m, this.#seed, this.#scratch);
134
- for (let i = 0; i < this.#k; i++) if (!this.#bits.get(this.#scratch[i] ?? 0)) return false;
133
+ hash32x2Into(key, this.#seed, this.#scratch);
134
+ const a = this.#scratch[0] ?? 0;
135
+ const b = this.#scratch[1] ?? 0;
136
+ for (let i = 0; i < this.#k; i++) if (!this.#bits.get(probeAt(a, b, i, this.#m))) return false;
135
137
  return true;
136
138
  }
137
139
  };
@@ -0,0 +1,45 @@
1
+ //#region src/core/bytes.ts
2
+ const encoder = new TextEncoder();
3
+ function normalize(input) {
4
+ if (typeof input === "string") return encoder.encode(input);
5
+ if (input instanceof Uint8Array) return input;
6
+ return new Uint8Array(input);
7
+ }
8
+ const ASCII_FAST_MAX = 12;
9
+ let keyBuf = new Uint8Array(256);
10
+ let keyBytes = keyBuf;
11
+ function encodedBytes() {
12
+ return keyBytes;
13
+ }
14
+ function encodeKey(key) {
15
+ if (typeof key === "string") {
16
+ const n = key.length;
17
+ if (keyBuf.length < n * 3) keyBuf = new Uint8Array(n * 3);
18
+ keyBytes = keyBuf;
19
+ if (n <= ASCII_FAST_MAX) {
20
+ let i = 0;
21
+ for (; i < n; i++) {
22
+ const c = key.charCodeAt(i);
23
+ if (c > 127) break;
24
+ keyBuf[i] = c;
25
+ }
26
+ if (i === n) return n;
27
+ }
28
+ return encoder.encodeInto(key, keyBuf).written;
29
+ }
30
+ keyBytes = normalize(key);
31
+ return keyBytes.length;
32
+ }
33
+ //#endregion
34
+ Object.defineProperty(exports, "encodeKey", {
35
+ enumerable: true,
36
+ get: function() {
37
+ return encodeKey;
38
+ }
39
+ });
40
+ Object.defineProperty(exports, "encodedBytes", {
41
+ enumerable: true,
42
+ get: function() {
43
+ return encodedBytes;
44
+ }
45
+ });
@@ -0,0 +1,34 @@
1
+ //#region src/core/bytes.ts
2
+ const encoder = new TextEncoder();
3
+ function normalize(input) {
4
+ if (typeof input === "string") return encoder.encode(input);
5
+ if (input instanceof Uint8Array) return input;
6
+ return new Uint8Array(input);
7
+ }
8
+ const ASCII_FAST_MAX = 12;
9
+ let keyBuf = new Uint8Array(256);
10
+ let keyBytes = keyBuf;
11
+ function encodedBytes() {
12
+ return keyBytes;
13
+ }
14
+ function encodeKey(key) {
15
+ if (typeof key === "string") {
16
+ const n = key.length;
17
+ if (keyBuf.length < n * 3) keyBuf = new Uint8Array(n * 3);
18
+ keyBytes = keyBuf;
19
+ if (n <= ASCII_FAST_MAX) {
20
+ let i = 0;
21
+ for (; i < n; i++) {
22
+ const c = key.charCodeAt(i);
23
+ if (c > 127) break;
24
+ keyBuf[i] = c;
25
+ }
26
+ if (i === n) return n;
27
+ }
28
+ return encoder.encodeInto(key, keyBuf).written;
29
+ }
30
+ keyBytes = normalize(key);
31
+ return keyBytes.length;
32
+ }
33
+ //#endregion
34
+ export { encodedBytes as n, encodeKey as t };
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_hasher = require("../hasher-DPXmP7SH.cjs");
2
+ const require_hasher = require("../hasher-CKLP9Oqe.cjs");
3
3
  const require_serialize = require("../serialize-CHikZ4GH.cjs");
4
4
  const require_params = require("../params-UTZbJ22c.cjs");
5
5
  //#region src/countmin/sizing.ts
@@ -1,4 +1,4 @@
1
- import { a as hash32x2Into, s as probeAt } from "../hasher-DOdmZ-LI.js";
1
+ import { a as hash32x2Into, s as probeAt } from "../hasher-BQxNrCQC.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
4
  //#region src/countmin/sizing.ts
@@ -1,7 +1,8 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_hasher = require("../hasher-DPXmP7SH.cjs");
2
+ const require_hasher = require("../hasher-CKLP9Oqe.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 seen = new Set();
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
- const id = `${String(HASH.w0)},${String(HASH.w1)},${String(HASH.w2)},${String(HASH.w3)}`;
62
- if (seen.has(id)) continue;
63
- seen.add(id);
64
- distinct.push(key);
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);
@@ -1,6 +1,7 @@
1
- import { i as hash128KeyInto, u as reduce } from "../hasher-DOdmZ-LI.js";
1
+ import { i as hash128KeyInto, u as reduce } from "../hasher-BQxNrCQC.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 seen = new Set();
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
- 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);
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
+ });
@@ -1,6 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_hasher = require("../hasher-DPXmP7SH.cjs");
2
+ const require_hasher = require("../hasher-CKLP9Oqe.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 hashList = [];
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
- const lo = scratchHash.w0 >>> 0;
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 = hashList.length / 2;
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 = Uint32Array.from(hashList);
148
+ const hashes = distinct.words;
154
149
  const fp = alloc(params.arrayLength);
155
150
  return {
156
151
  fp,
@@ -1,5 +1,6 @@
1
- import { i as hash128KeyInto, n as RLO, o as mul64, r as fmix64, t as RHI } from "../hasher-DOdmZ-LI.js";
1
+ import { i as hash128KeyInto, n as RLO, o as mul64, r as fmix64, t as RHI } from "../hasher-BQxNrCQC.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 hashList = [];
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
- const lo = scratchHash.w0 >>> 0;
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 = hashList.length / 2;
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 = Uint32Array.from(hashList);
147
+ const hashes = distinct.words;
153
148
  const fp = alloc(params.arrayLength);
154
149
  return {
155
150
  fp,
@@ -1,4 +1,4 @@
1
- import { t as normalize } from "./bytes-Be7tq1F7.js";
1
+ import { n as encodedBytes, t as encodeKey } from "./bytes-oOWlu7N5.js";
2
2
  //#region src/core/hasher.ts
3
3
  let RLO = 0;
4
4
  let RHI = 0;
@@ -166,24 +166,9 @@ function computeLanes(bytes, seed, len) {
166
166
  LANES.w2 = h3;
167
167
  LANES.w3 = h4;
168
168
  }
169
- const keyEncoder = new TextEncoder();
170
- let keyBuf = new Uint8Array(256);
171
- let encBytes = keyBuf;
172
- let encLen = 0;
173
- function encodeKey(key) {
174
- if (typeof key === "string") {
175
- const cap = key.length * 3;
176
- if (keyBuf.length < cap) keyBuf = new Uint8Array(cap);
177
- encLen = keyEncoder.encodeInto(key, keyBuf).written;
178
- encBytes = keyBuf;
179
- return;
180
- }
181
- encBytes = normalize(key);
182
- encLen = encBytes.length;
183
- }
184
169
  function keyToLanes(key, seed) {
185
- encodeKey(key);
186
- computeLanes(encBytes, seed, encLen);
170
+ const len = encodeKey(key);
171
+ computeLanes(encodedBytes(), seed, len);
187
172
  }
188
173
  function hash128KeyInto(key, seed, out) {
189
174
  keyToLanes(key, seed);
@@ -1,4 +1,4 @@
1
- const require_bytes = require("./bytes-D2duG1jq.cjs");
1
+ const require_bytes = require("./bytes-DWGupBUE.cjs");
2
2
  //#region src/core/hasher.ts
3
3
  let RLO = 0;
4
4
  let RHI = 0;
@@ -166,24 +166,9 @@ function computeLanes(bytes, seed, len) {
166
166
  LANES.w2 = h3;
167
167
  LANES.w3 = h4;
168
168
  }
169
- const keyEncoder = new TextEncoder();
170
- let keyBuf = new Uint8Array(256);
171
- let encBytes = keyBuf;
172
- let encLen = 0;
173
- function encodeKey(key) {
174
- if (typeof key === "string") {
175
- const cap = key.length * 3;
176
- if (keyBuf.length < cap) keyBuf = new Uint8Array(cap);
177
- encLen = keyEncoder.encodeInto(key, keyBuf).written;
178
- encBytes = keyBuf;
179
- return;
180
- }
181
- encBytes = require_bytes.normalize(key);
182
- encLen = encBytes.length;
183
- }
184
169
  function keyToLanes(key, seed) {
185
- encodeKey(key);
186
- computeLanes(encBytes, seed, encLen);
170
+ const len = require_bytes.encodeKey(key);
171
+ computeLanes(require_bytes.encodedBytes(), seed, len);
187
172
  }
188
173
  function hash128KeyInto(key, seed, out) {
189
174
  keyToLanes(key, seed);
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_hasher = require("../hasher-DPXmP7SH.cjs");
2
+ const require_hasher = require("../hasher-CKLP9Oqe.cjs");
3
3
  const require_serialize = require("../serialize-CHikZ4GH.cjs");
4
4
  const require_params = require("../params-UTZbJ22c.cjs");
5
5
  function hllSizing(relativeError) {
package/dist/hll/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { i as hash128KeyInto } from "../hasher-DOdmZ-LI.js";
1
+ import { i as hash128KeyInto } from "../hasher-BQxNrCQC.js";
2
2
  import { a as TruncatedError, c as assertBodyLength, 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, t as ParamError } from "../params-CeajSrwv.js";
4
4
  function hllSizing(relativeError) {
package/dist/index.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  //#endregion
3
3
  //#region src/index.ts
4
- const VERSION = "0.14.0";
4
+ const VERSION = "0.14.2";
5
5
  //#endregion
6
6
  exports.VERSION = VERSION;
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  //#endregion
2
2
  //#region src/index.ts
3
- const VERSION = "0.14.0";
3
+ const VERSION = "0.14.2";
4
4
  //#endregion
5
5
  export { VERSION };
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_sizing = require("../sizing-Ch0SDdza.cjs");
3
- const require_hasher = require("../hasher-DPXmP7SH.cjs");
3
+ const require_hasher = require("../hasher-CKLP9Oqe.cjs");
4
4
  const require_serialize = require("../serialize-CHikZ4GH.cjs");
5
5
  const require_params = require("../params-UTZbJ22c.cjs");
6
6
  //#region src/scalable/scalable.ts
@@ -1,5 +1,5 @@
1
1
  import { n as BitSet, t as bloomSizing } from "../sizing-zxCBlyhO.js";
2
- import { i as hash128KeyInto, l as probeLanesInto, s as probeAt } from "../hasher-DOdmZ-LI.js";
2
+ import { i as hash128KeyInto, l as probeLanesInto, s as probeAt } from "../hasher-BQxNrCQC.js";
3
3
  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";
4
4
  import { i as assertProbability, o as assertUint32, r as assertPositiveInt, t as ParamError } from "../params-CeajSrwv.js";
5
5
  //#region src/scalable/scalable.ts
@@ -1,14 +1,13 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_bytes = require("../bytes-D2duG1jq.cjs");
2
+ const require_bytes = require("../bytes-DWGupBUE.cjs");
3
3
  const require_serialize = require("../serialize-CHikZ4GH.cjs");
4
4
  const require_params = require("../params-UTZbJ22c.cjs");
5
5
  //#region src/topk/halfsip.ts
6
- function halfSipHash13(bytes, k0, k1) {
6
+ function halfSipHash13(bytes, k0, k1, len = bytes.length) {
7
7
  let v0 = k0 | 0;
8
8
  let v1 = k1 | 0;
9
9
  let v2 = 1819895653 ^ k0 | 0;
10
10
  let v3 = 1952801890 ^ k1 | 0;
11
- const len = bytes.length;
12
11
  const end = len & -4;
13
12
  for (let i = 0; i < end; i += 4) {
14
13
  const m = (bytes[i] ?? 0) | (bytes[i + 1] ?? 0) << 8 | (bytes[i + 2] ?? 0) << 16 | (bytes[i + 3] ?? 0) << 24;
@@ -250,29 +249,28 @@ var TopK = class TopK {
250
249
  while (size < this.#capacity && topKLoadLimit(size) < entries) size *= 2;
251
250
  return size;
252
251
  }
253
- #slotHolds(slot, bytes) {
254
- const len = this.#keyLengths[slot] ?? 0;
255
- if (len !== bytes.length) return false;
252
+ #slotHolds(slot, bytes, len) {
253
+ if ((this.#keyLengths[slot] ?? 0) !== len) return false;
256
254
  const at = this.#keyOffsets[slot] ?? 0;
257
255
  for (let i = 0; i < len; i++) if (this.#arena[at + i] !== bytes[i]) return false;
258
256
  return true;
259
257
  }
260
- #storeKey(slot, bytes) {
258
+ #storeKey(slot, bytes, len = bytes.length) {
261
259
  let arena = this.#arena;
262
- if (this.#arenaLen + bytes.length > arena.length) {
260
+ if (this.#arenaLen + len > arena.length) {
263
261
  let size = arena.length;
264
- while (size < this.#arenaLen + bytes.length) size *= 2;
262
+ while (size < this.#arenaLen + len) size *= 2;
265
263
  const grown = new Uint8Array(size);
266
264
  grown.set(arena.subarray(0, this.#arenaLen));
267
265
  arena = grown;
268
266
  this.#arena = grown;
269
267
  }
270
- arena.set(bytes, this.#arenaLen);
268
+ arena.set(len === bytes.length ? bytes : bytes.subarray(0, len), this.#arenaLen);
271
269
  this.#keyOffsets[slot] = this.#arenaLen;
272
- this.#keyLengths[slot] = bytes.length;
273
- this.#arenaLen += bytes.length;
270
+ this.#keyLengths[slot] = len;
271
+ this.#arenaLen += len;
274
272
  }
275
- #slotFor(bytes) {
273
+ #slotFor(bytes, len = bytes.length) {
276
274
  if (!this.#keyed) {
277
275
  const key = crypto.getRandomValues(new Uint32Array(2));
278
276
  this.#k0 = key[0] ?? 0;
@@ -280,22 +278,23 @@ var TopK = class TopK {
280
278
  this.#keyed = true;
281
279
  }
282
280
  const mask = this.#size - 1;
283
- let slot = halfSipHash13(bytes, this.#k0, this.#k1) & mask;
281
+ let slot = halfSipHash13(bytes, this.#k0, this.#k1, len) & mask;
284
282
  for (;;) {
285
283
  if ((this.#counts[slot] ?? 0) === 0) return slot;
286
- if (this.#slotHolds(slot, bytes)) return slot;
284
+ if (this.#slotHolds(slot, bytes, len)) return slot;
287
285
  slot = slot + 1 & mask;
288
286
  }
289
287
  }
290
288
  add(key, count = 1) {
291
289
  require_params.assertPositiveInt(count, "count");
292
290
  if (this.#total + count > Number.MAX_SAFE_INTEGER) throw new TopKOverflowError(`adding ${String(count)} would carry the total past ${String(Number.MAX_SAFE_INTEGER)}`);
293
- const bytes = require_bytes.normalize(key);
294
- const slot = this.#slotFor(bytes);
291
+ const len = require_bytes.encodeKey(key);
292
+ const bytes = require_bytes.encodedBytes();
293
+ const slot = this.#slotFor(bytes, len);
295
294
  const stored = this.#counts[slot] ?? 0;
296
295
  if (stored + count > 4294967295) throw new TopKOverflowError(`adding ${String(count)} would carry a stored count past ${String(4294967295)}`);
297
296
  if (stored === 0) {
298
- this.#storeKey(slot, bytes);
297
+ this.#storeKey(slot, bytes, len);
299
298
  this.#entries++;
300
299
  }
301
300
  this.#counts[slot] = stored + count;
@@ -306,8 +305,8 @@ var TopK = class TopK {
306
305
  }
307
306
  }
308
307
  count(key) {
309
- const bytes = require_bytes.normalize(key);
310
- const stored = this.#counts[this.#slotFor(bytes)] ?? 0;
308
+ const len = require_bytes.encodeKey(key);
309
+ const stored = this.#counts[this.#slotFor(require_bytes.encodedBytes(), len)] ?? 0;
311
310
  return stored === 0 ? 0 : stored + this.#offset;
312
311
  }
313
312
  top(k) {
@@ -1,13 +1,12 @@
1
- import { t as normalize } from "../bytes-Be7tq1F7.js";
1
+ import { n as encodedBytes, t as encodeKey } from "../bytes-oOWlu7N5.js";
2
2
  import { a as TruncatedError, c as assertBodyLength, 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
4
  //#region src/topk/halfsip.ts
5
- function halfSipHash13(bytes, k0, k1) {
5
+ function halfSipHash13(bytes, k0, k1, len = bytes.length) {
6
6
  let v0 = k0 | 0;
7
7
  let v1 = k1 | 0;
8
8
  let v2 = 1819895653 ^ k0 | 0;
9
9
  let v3 = 1952801890 ^ k1 | 0;
10
- const len = bytes.length;
11
10
  const end = len & -4;
12
11
  for (let i = 0; i < end; i += 4) {
13
12
  const m = (bytes[i] ?? 0) | (bytes[i + 1] ?? 0) << 8 | (bytes[i + 2] ?? 0) << 16 | (bytes[i + 3] ?? 0) << 24;
@@ -249,29 +248,28 @@ var TopK = class TopK {
249
248
  while (size < this.#capacity && topKLoadLimit(size) < entries) size *= 2;
250
249
  return size;
251
250
  }
252
- #slotHolds(slot, bytes) {
253
- const len = this.#keyLengths[slot] ?? 0;
254
- if (len !== bytes.length) return false;
251
+ #slotHolds(slot, bytes, len) {
252
+ if ((this.#keyLengths[slot] ?? 0) !== len) return false;
255
253
  const at = this.#keyOffsets[slot] ?? 0;
256
254
  for (let i = 0; i < len; i++) if (this.#arena[at + i] !== bytes[i]) return false;
257
255
  return true;
258
256
  }
259
- #storeKey(slot, bytes) {
257
+ #storeKey(slot, bytes, len = bytes.length) {
260
258
  let arena = this.#arena;
261
- if (this.#arenaLen + bytes.length > arena.length) {
259
+ if (this.#arenaLen + len > arena.length) {
262
260
  let size = arena.length;
263
- while (size < this.#arenaLen + bytes.length) size *= 2;
261
+ while (size < this.#arenaLen + len) size *= 2;
264
262
  const grown = new Uint8Array(size);
265
263
  grown.set(arena.subarray(0, this.#arenaLen));
266
264
  arena = grown;
267
265
  this.#arena = grown;
268
266
  }
269
- arena.set(bytes, this.#arenaLen);
267
+ arena.set(len === bytes.length ? bytes : bytes.subarray(0, len), this.#arenaLen);
270
268
  this.#keyOffsets[slot] = this.#arenaLen;
271
- this.#keyLengths[slot] = bytes.length;
272
- this.#arenaLen += bytes.length;
269
+ this.#keyLengths[slot] = len;
270
+ this.#arenaLen += len;
273
271
  }
274
- #slotFor(bytes) {
272
+ #slotFor(bytes, len = bytes.length) {
275
273
  if (!this.#keyed) {
276
274
  const key = crypto.getRandomValues(new Uint32Array(2));
277
275
  this.#k0 = key[0] ?? 0;
@@ -279,22 +277,23 @@ var TopK = class TopK {
279
277
  this.#keyed = true;
280
278
  }
281
279
  const mask = this.#size - 1;
282
- let slot = halfSipHash13(bytes, this.#k0, this.#k1) & mask;
280
+ let slot = halfSipHash13(bytes, this.#k0, this.#k1, len) & mask;
283
281
  for (;;) {
284
282
  if ((this.#counts[slot] ?? 0) === 0) return slot;
285
- if (this.#slotHolds(slot, bytes)) return slot;
283
+ if (this.#slotHolds(slot, bytes, len)) return slot;
286
284
  slot = slot + 1 & mask;
287
285
  }
288
286
  }
289
287
  add(key, count = 1) {
290
288
  assertPositiveInt(count, "count");
291
289
  if (this.#total + count > Number.MAX_SAFE_INTEGER) throw new TopKOverflowError(`adding ${String(count)} would carry the total past ${String(Number.MAX_SAFE_INTEGER)}`);
292
- const bytes = normalize(key);
293
- const slot = this.#slotFor(bytes);
290
+ const len = encodeKey(key);
291
+ const bytes = encodedBytes();
292
+ const slot = this.#slotFor(bytes, len);
294
293
  const stored = this.#counts[slot] ?? 0;
295
294
  if (stored + count > 4294967295) throw new TopKOverflowError(`adding ${String(count)} would carry a stored count past ${String(4294967295)}`);
296
295
  if (stored === 0) {
297
- this.#storeKey(slot, bytes);
296
+ this.#storeKey(slot, bytes, len);
298
297
  this.#entries++;
299
298
  }
300
299
  this.#counts[slot] = stored + count;
@@ -305,8 +304,8 @@ var TopK = class TopK {
305
304
  }
306
305
  }
307
306
  count(key) {
308
- const bytes = normalize(key);
309
- const stored = this.#counts[this.#slotFor(bytes)] ?? 0;
307
+ const len = encodeKey(key);
308
+ const stored = this.#counts[this.#slotFor(encodedBytes(), len)] ?? 0;
310
309
  return stored === 0 ? 0 : stored + this.#offset;
311
310
  }
312
311
  top(k) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "distillate",
3
- "version": "0.14.0",
3
+ "version": "0.14.2",
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.1",
117
- "@types/node": "^22.20.3",
118
- "@vitest/coverage-v8": "^5.0.1",
119
- "fast-check": "^4.10.1",
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.13",
123
+ "tsx": "^4.23.15",
124
124
  "typedoc": "^0.28.20",
125
125
  "typescript": "^5.9.3",
126
- "vitest": "^5.0.1"
126
+ "vitest": "^5.0.2"
127
127
  },
128
128
  "engines": {
129
129
  "node": ">=22"
@@ -1,9 +0,0 @@
1
- //#region src/core/bytes.ts
2
- const encoder = new TextEncoder();
3
- function normalize(input) {
4
- if (typeof input === "string") return encoder.encode(input);
5
- if (input instanceof Uint8Array) return input;
6
- return new Uint8Array(input);
7
- }
8
- //#endregion
9
- export { normalize as t };
@@ -1,14 +0,0 @@
1
- //#region src/core/bytes.ts
2
- const encoder = new TextEncoder();
3
- function normalize(input) {
4
- if (typeof input === "string") return encoder.encode(input);
5
- if (input instanceof Uint8Array) return input;
6
- return new Uint8Array(input);
7
- }
8
- //#endregion
9
- Object.defineProperty(exports, "normalize", {
10
- enumerable: true,
11
- get: function() {
12
- return normalize;
13
- }
14
- });