@sepiariver/unique-set 2.0.2 → 2.0.3

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 CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Extends the native `Set` class to deeply compare using [fast-deep-equal](https://www.npmjs.com/package/fast-deep-equal), with optional Bloom filter optimization.
4
4
 
5
- Supports ESM and CommonJS. Thanks @sakgoyal for contributing to and instigating ESM support.
5
+ Supports ESM and CommonJS. Thanks [@sakgoyal](https://github.com/sakgoyal) for contributing to and instigating ESM support.
6
6
 
7
7
  ```js
8
8
  import { BloomSet, UniqueSet } from '@sepiariver/unique-set';
package/dist/index.mjs CHANGED
@@ -1,5 +1,48 @@
1
1
  // index.ts
2
2
  import equal from "fast-deep-equal/es6/index.js";
3
+ var serialize = (item) => {
4
+ if (typeof item === "number" && isNaN(item)) {
5
+ return "NaN";
6
+ }
7
+ if (item && typeof item === "object") {
8
+ if (Array.isArray(item)) {
9
+ return `[${item.map(serialize).join("")}]`;
10
+ } else {
11
+ return `{${Object.entries(item).sort(([a], [b]) => a.localeCompare(b)).map(([k, v]) => `${k}:${serialize(v)}`).join("")}}`;
12
+ }
13
+ }
14
+ return String(item);
15
+ };
16
+ var fnv1a = (str) => {
17
+ if (typeof str !== "string") {
18
+ str = String(str);
19
+ }
20
+ let hash = 2166136261;
21
+ for (let i = 0; i < str.length; i++) {
22
+ hash ^= str.charCodeAt(i);
23
+ hash = hash * 16777619 >>> 0;
24
+ }
25
+ return hash >>> 0;
26
+ };
27
+ var findNextPrime = (num) => {
28
+ if (num < 2) return 2;
29
+ if ((num & 1) === 0) num++;
30
+ while (!isPrime(num)) {
31
+ num += 2;
32
+ }
33
+ return num;
34
+ };
35
+ var isPrime = (num) => {
36
+ if (num < 2) return false;
37
+ if (num === 2 || num === 3) return true;
38
+ if ((num & 1) === 0) return false;
39
+ if (num % 3 === 0) return false;
40
+ const sqrt = Math.sqrt(num);
41
+ for (let i = 5; i <= sqrt; i += 6) {
42
+ if (num % i === 0 || num % (i + 2) === 0) return false;
43
+ }
44
+ return true;
45
+ };
3
46
  var UniqueSet = class extends Set {
4
47
  /*** @throws TypeError If the input is not iterable. */
5
48
  constructor(iterable = []) {
@@ -62,7 +105,7 @@ var BloomSet = class extends Set {
62
105
  if (typeof size !== "number" || size <= 0) {
63
106
  size = 6553577;
64
107
  }
65
- this.#aSize = this.#findNextPrime(size);
108
+ this.#aSize = findNextPrime(size);
66
109
  if (typeof hashCount !== "number" || hashCount <= 0) {
67
110
  hashCount = 7;
68
111
  }
@@ -73,45 +116,10 @@ var BloomSet = class extends Set {
73
116
  }
74
117
  }
75
118
  /** @internal */
76
- #findNextPrime(num) {
77
- if (num < 2) return 2;
78
- if (num % 2 === 0) num++;
79
- while (!this.#isPrime(num)) {
80
- num += 2;
81
- }
82
- return num;
83
- }
84
- /** @internal */
85
- #isPrime(num) {
86
- if (num < 2) return false;
87
- if (num === 2 || num === 3) return true;
88
- if (num % 2 === 0 || num % 3 === 0) return false;
89
- const sqrt = Math.floor(Math.sqrt(num));
90
- for (let i = 5; i <= sqrt; i += 6) {
91
- if (num % i === 0 || num % (i + 2) === 0) return false;
92
- }
93
- return true;
94
- }
95
- /** @internal */
96
- #serialize(item) {
97
- if (typeof item === "number" && isNaN(item)) {
98
- return "NaN";
99
- }
100
- if (item && typeof item === "object") {
101
- const serialize = this.#serialize.bind(this);
102
- if (Array.isArray(item)) {
103
- return `[${item.map(serialize).join(",")}]`;
104
- } else {
105
- return `{${Object.entries(item).sort(([a], [b]) => a.localeCompare(b)).map(([k, v]) => `${k}:${serialize(v)}`).join(",")}}`;
106
- }
107
- }
108
- return String(item);
109
- }
110
- /** @internal */
111
119
  #hashes(item) {
112
120
  const hashes = [];
113
- const str = this.#serialize(item);
114
- let hash = this.#fnv1a(str);
121
+ const str = serialize(item);
122
+ let hash = fnv1a(str);
115
123
  for (let i = 0; i < this.#hashCount; i++) {
116
124
  hash %= this.#aSize;
117
125
  hashes.push(hash);
@@ -121,18 +129,6 @@ var BloomSet = class extends Set {
121
129
  return hashes;
122
130
  }
123
131
  /** @internal */
124
- #fnv1a(str) {
125
- if (typeof str !== "string") {
126
- str = String(str);
127
- }
128
- let hash = 2166136261;
129
- for (let i = 0; i < str.length; i++) {
130
- hash ^= str.charCodeAt(i);
131
- hash = hash * 16777619 >>> 0;
132
- }
133
- return hash >>> 0;
134
- }
135
- /** @internal */
136
132
  #setBits(hashes) {
137
133
  for (const hash of hashes) {
138
134
  const index = Math.floor(hash / 8);
package/index.ts CHANGED
@@ -1,5 +1,63 @@
1
1
  import equal from "fast-deep-equal/es6/index.js";
2
2
 
3
+ /** Utility functions */
4
+
5
+ const serialize = (item: any | number | object): string => {
6
+ if (typeof item === "number" && isNaN(item)) {
7
+ return "NaN";
8
+ }
9
+
10
+ if (item && typeof item === "object") {
11
+ if (Array.isArray(item)) {
12
+ return `[${item.map(serialize).join("")}]`;
13
+ } else {
14
+ return `{${Object.entries(item)
15
+ .sort(([a], [b]) => a.localeCompare(b))
16
+ .map(([k, v]) => `${k}:${serialize(v)}`)
17
+ .join("")}}`;
18
+ }
19
+ }
20
+
21
+ return String(item);
22
+ };
23
+
24
+ const fnv1a = (str: string) => {
25
+ if (typeof str !== "string") {
26
+ str = String(str);
27
+ }
28
+ let hash = 2166136261; // FNV offset basis for 32-bit
29
+ for (let i = 0; i < str.length; i++) {
30
+ hash ^= str.charCodeAt(i);
31
+ hash = (hash * 16777619) >>> 0; // Multiply by the FNV prime and ensure 32-bit unsigned
32
+ }
33
+ return hash >>> 0;
34
+ };
35
+
36
+ const findNextPrime = (num: number) => {
37
+ if (num < 2) return 2;
38
+ if ((num & 1) === 0) num++; // Odd numbers only
39
+
40
+ while (!isPrime(num)) {
41
+ num += 2; // Odd numbers only
42
+ }
43
+
44
+ return num;
45
+ };
46
+
47
+ const isPrime = (num: number): boolean => {
48
+ if (num < 2) return false;
49
+ if (num === 2 || num === 3) return true;
50
+ if ((num & 1) === 0) return false;
51
+ if (num % 3 === 0) return false;
52
+
53
+ const sqrt = Math.sqrt(num);
54
+ for (let i = 5; i <= sqrt; i += 6) {
55
+ if (num % i === 0 || num % (i + 2) === 0) return false;
56
+ }
57
+
58
+ return true;
59
+ };
60
+
3
61
  /** A `Set` extension that ensures uniqueness of items using deep equality checks. */
4
62
  export class UniqueSet<T> extends Set<T> {
5
63
  /*** @throws TypeError If the input is not iterable. */
@@ -72,7 +130,7 @@ export class BloomSet<T> extends Set<T> {
72
130
  if (typeof size !== "number" || size <= 0) {
73
131
  size = 6553577; // Targeting < 1 collision per 100,000 elements, ~819 KB memory, needs 7 hashes
74
132
  }
75
- this.#aSize = this.#findNextPrime(size);
133
+ this.#aSize = findNextPrime(size);
76
134
 
77
135
  if (typeof hashCount !== "number" || hashCount <= 0) {
78
136
  hashCount = 7;
@@ -85,58 +143,11 @@ export class BloomSet<T> extends Set<T> {
85
143
  }
86
144
  }
87
145
 
88
- /** @internal */
89
- #findNextPrime(num: number) {
90
- if (num < 2) return 2;
91
- if (num % 2 === 0) num++; // Odd numbers only
92
-
93
- while (!this.#isPrime(num)) {
94
- num += 2; // Odd numbers only
95
- }
96
-
97
- return num;
98
- }
99
-
100
- /** @internal */
101
- #isPrime(num: number) {
102
- if (num < 2) return false;
103
- if (num === 2 || num === 3) return true;
104
- if (num % 2 === 0 || num % 3 === 0) return false;
105
-
106
- const sqrt = Math.floor(Math.sqrt(num));
107
- for (let i = 5; i <= sqrt; i += 6) {
108
- if (num % i === 0 || num % (i + 2) === 0) return false;
109
- }
110
-
111
- return true;
112
- }
113
-
114
- /** @internal */
115
- #serialize(item: T | number | object): string {
116
- if (typeof item === "number" && isNaN(item)) {
117
- return "NaN";
118
- }
119
-
120
- if (item && typeof item === "object") {
121
- const serialize = this.#serialize.bind(this);
122
- if (Array.isArray(item)) {
123
- return `[${item.map(serialize).join(",")}]`;
124
- } else {
125
- return `{${Object.entries(item)
126
- .sort(([a], [b]) => a.localeCompare(b))
127
- .map(([k, v]) => `${k}:${serialize(v)}`)
128
- .join(",")}}`;
129
- }
130
- }
131
-
132
- return String(item);
133
- }
134
-
135
146
  /** @internal */
136
147
  #hashes(item: T) {
137
148
  const hashes: number[] = [];
138
- const str = this.#serialize(item);
139
- let hash = this.#fnv1a(str); // Base hash
149
+ const str = serialize(item);
150
+ let hash = fnv1a(str); // Base hash
140
151
 
141
152
  // Bloom into hashCount hash values
142
153
  for (let i = 0; i < this.#hashCount; i++) {
@@ -151,19 +162,6 @@ export class BloomSet<T> extends Set<T> {
151
162
  return hashes;
152
163
  }
153
164
 
154
- /** @internal */
155
- #fnv1a(str: string) {
156
- if (typeof str !== "string") {
157
- str = String(str);
158
- }
159
- let hash = 2166136261; // FNV offset basis for 32-bit
160
- for (let i = 0; i < str.length; i++) {
161
- hash ^= str.charCodeAt(i);
162
- hash = (hash * 16777619) >>> 0; // Multiply by the FNV prime and ensure 32-bit unsigned
163
- }
164
- return hash >>> 0;
165
- }
166
-
167
165
  /** @internal */
168
166
  #setBits(hashes: number[]): void {
169
167
  for (const hash of hashes) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sepiariver/unique-set",
3
- "version": "2.0.2",
3
+ "version": "2.0.3",
4
4
  "description": "Extends the native Set class to deeply compare using fast-deep-equal, with optional Bloom filter optimization. This version exports 2 classes instead of a default, breaking b/c with version 1.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",