fastbloom 0.1.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 ADDED
@@ -0,0 +1,84 @@
1
+ # fastbloom
2
+
3
+ A **blazingly fast** Bloom Filter for Node.js, implemented in Rust with native concurrency support.
4
+
5
+ **~40x faster** than the popular `bloom-filters` npm package, thanks to Rust's performance and parallel processing capabilities.
6
+
7
+ ## Features
8
+
9
+ - **Exceptionally Fast**: Built on top of the `fastbloom` Rust crate with atomic operations, achieving ~40x speedup compared to `bloom-filters` npm package
10
+ - **Concurrent Operations**: Thread-safe implementation using `AtomicBloomFilter` - all operations can be called concurrently from multiple threads
11
+ - **Parallel Bulk Operations**: Uses `rayon` for parallel processing of bulk additions, maximizing multi-core CPU utilization
12
+ - **Optimal Sizing**: Automatically calculates the optimal bit array size and number of hash functions based on your desired capacity and false positive rate
13
+ - **N-API**: Uses N-API for stable Node.js ABI compatibility across Node.js versions
14
+ - **Zero-Cost Abstractions**: Direct Rust implementation with minimal JavaScript overhead
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install
20
+ ```
21
+
22
+ ## Build
23
+
24
+ You need to have Rust installed (`cargo`).
25
+
26
+ ```bash
27
+ npm run build
28
+ ```
29
+
30
+ This will compile the Rust code and generate the `index.js` binding file.
31
+
32
+ ## Usage
33
+
34
+ ```javascript
35
+ const { BloomFilter } = require('./index.js');
36
+
37
+ // 1. Initialize
38
+ // Capacity: 1,000,000 items
39
+ // False Positive Rate: 1% (0.01)
40
+ const filter = new BloomFilter(1000000, 0.01);
41
+
42
+ // 2. Add items (thread-safe)
43
+ filter.add('hello');
44
+ filter.add('world');
45
+
46
+ // 3. Check for existence (thread-safe)
47
+ console.log(filter.has('hello')); // true
48
+ console.log(filter.has('universe')); // false
49
+
50
+ // 4. Bulk add (parallel processing for maximum performance)
51
+ filter.bulk_add(['apple', 'banana', 'cherry', 'date', 'elderberry']);
52
+ ```
53
+
54
+ ## API
55
+
56
+ ### `new BloomFilter(capacity, false_positive_rate)`
57
+
58
+ Creates a new Bloom Filter with the specified parameters.
59
+
60
+ - **capacity** (`number`): The expected number of items to be stored (must be > 0)
61
+ - **false_positive_rate** (`number`): The desired false positive rate between 0 and 1 (e.g., 0.01 for 1%)
62
+
63
+ **Throws**: Error if capacity is not greater than 0 or if false positive rate is not between 0 and 1.
64
+
65
+ ### `add(item)`
66
+
67
+ Adds an item to the Bloom Filter. **Thread-safe** - can be called concurrently.
68
+
69
+ - **item** (`string`): The item to add
70
+
71
+ ### `has(item)`
72
+
73
+ Checks if an item is possibly in the Bloom Filter. **Thread-safe** - can be called concurrently.
74
+
75
+ - **item** (`string`): The item to check
76
+ - **Returns**: `boolean` - `true` if the item is possibly in the filter, `false` if definitely not
77
+
78
+ ### `bulk_add(items)`
79
+
80
+ Adds multiple items to the Bloom Filter using **parallel processing**. **Thread-safe** - can be called concurrently.
81
+
82
+ - **items** (`string[]`): Array of items to add
83
+
84
+ This method uses `rayon` for parallel iteration, making it significantly faster than calling `add()` repeatedly for large datasets.
Binary file
package/index.d.ts ADDED
@@ -0,0 +1,33 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+
4
+ /* auto-generated by NAPI-RS */
5
+
6
+ export declare class BloomFilter {
7
+ /**
8
+ * Creates a new Bloom Filter with the specified capacity and false positive rate.
9
+ * @param capacity - The expected number of items to be stored in the Bloom Filter.
10
+ * @param false_positive_rate - The desired false positive rate (between 0 and 1).
11
+ * @throws Will throw an error if the capacity is not greater than 0 or if the false positive rate is not between 0 and 1.
12
+ * @returns A new instance of the Bloom Filter.
13
+ */
14
+ constructor(capacity: number, falsePositiveRate: number)
15
+ /**
16
+ * Adds an item to the Bloom Filter. This method is thread-safe and can be called concurrently from multiple threads.
17
+ * @param item - The item to be added to the Bloom Filter.
18
+ * @returns void
19
+ */
20
+ add(item: string): void
21
+ /**
22
+ * Checks if an item is possibly in the Bloom Filter. This method is thread-safe and can be called concurrently from multiple threads.
23
+ * @param item - The item to be checked for membership in the Bloom Filter.
24
+ * @returns A boolean indicating whether the item is possibly in the Bloom Filter (true) or definitely not in the Bloom Filter (false).
25
+ */
26
+ has(item: string): boolean
27
+ /**
28
+ * Adds multiple items to the Bloom Filter in parallel. This method is thread-safe and can be called concurrently from multiple threads.
29
+ * @param items - An array of items to be added to the Bloom Filter.
30
+ * @returns void
31
+ */
32
+ bulkAdd(items: Array<string>): void
33
+ }
package/index.js ADDED
@@ -0,0 +1,315 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+ /* prettier-ignore */
4
+
5
+ /* auto-generated by NAPI-RS */
6
+
7
+ const { existsSync, readFileSync } = require('fs')
8
+ const { join } = require('path')
9
+
10
+ const { platform, arch } = process
11
+
12
+ let nativeBinding = null
13
+ let localFileExisted = false
14
+ let loadError = null
15
+
16
+ function isMusl() {
17
+ // For Node 10
18
+ if (!process.report || typeof process.report.getReport !== 'function') {
19
+ try {
20
+ const lddPath = require('child_process').execSync('which ldd').toString().trim()
21
+ return readFileSync(lddPath, 'utf8').includes('musl')
22
+ } catch (e) {
23
+ return true
24
+ }
25
+ } else {
26
+ const { glibcVersionRuntime } = process.report.getReport().header
27
+ return !glibcVersionRuntime
28
+ }
29
+ }
30
+
31
+ switch (platform) {
32
+ case 'android':
33
+ switch (arch) {
34
+ case 'arm64':
35
+ localFileExisted = existsSync(join(__dirname, 'fastbloom.android-arm64.node'))
36
+ try {
37
+ if (localFileExisted) {
38
+ nativeBinding = require('./fastbloom.android-arm64.node')
39
+ } else {
40
+ nativeBinding = require('fastbloom-android-arm64')
41
+ }
42
+ } catch (e) {
43
+ loadError = e
44
+ }
45
+ break
46
+ case 'arm':
47
+ localFileExisted = existsSync(join(__dirname, 'fastbloom.android-arm-eabi.node'))
48
+ try {
49
+ if (localFileExisted) {
50
+ nativeBinding = require('./fastbloom.android-arm-eabi.node')
51
+ } else {
52
+ nativeBinding = require('fastbloom-android-arm-eabi')
53
+ }
54
+ } catch (e) {
55
+ loadError = e
56
+ }
57
+ break
58
+ default:
59
+ throw new Error(`Unsupported architecture on Android ${arch}`)
60
+ }
61
+ break
62
+ case 'win32':
63
+ switch (arch) {
64
+ case 'x64':
65
+ localFileExisted = existsSync(
66
+ join(__dirname, 'fastbloom.win32-x64-msvc.node')
67
+ )
68
+ try {
69
+ if (localFileExisted) {
70
+ nativeBinding = require('./fastbloom.win32-x64-msvc.node')
71
+ } else {
72
+ nativeBinding = require('fastbloom-win32-x64-msvc')
73
+ }
74
+ } catch (e) {
75
+ loadError = e
76
+ }
77
+ break
78
+ case 'ia32':
79
+ localFileExisted = existsSync(
80
+ join(__dirname, 'fastbloom.win32-ia32-msvc.node')
81
+ )
82
+ try {
83
+ if (localFileExisted) {
84
+ nativeBinding = require('./fastbloom.win32-ia32-msvc.node')
85
+ } else {
86
+ nativeBinding = require('fastbloom-win32-ia32-msvc')
87
+ }
88
+ } catch (e) {
89
+ loadError = e
90
+ }
91
+ break
92
+ case 'arm64':
93
+ localFileExisted = existsSync(
94
+ join(__dirname, 'fastbloom.win32-arm64-msvc.node')
95
+ )
96
+ try {
97
+ if (localFileExisted) {
98
+ nativeBinding = require('./fastbloom.win32-arm64-msvc.node')
99
+ } else {
100
+ nativeBinding = require('fastbloom-win32-arm64-msvc')
101
+ }
102
+ } catch (e) {
103
+ loadError = e
104
+ }
105
+ break
106
+ default:
107
+ throw new Error(`Unsupported architecture on Windows: ${arch}`)
108
+ }
109
+ break
110
+ case 'darwin':
111
+ localFileExisted = existsSync(join(__dirname, 'fastbloom.darwin-universal.node'))
112
+ try {
113
+ if (localFileExisted) {
114
+ nativeBinding = require('./fastbloom.darwin-universal.node')
115
+ } else {
116
+ nativeBinding = require('fastbloom-darwin-universal')
117
+ }
118
+ break
119
+ } catch {}
120
+ switch (arch) {
121
+ case 'x64':
122
+ localFileExisted = existsSync(join(__dirname, 'fastbloom.darwin-x64.node'))
123
+ try {
124
+ if (localFileExisted) {
125
+ nativeBinding = require('./fastbloom.darwin-x64.node')
126
+ } else {
127
+ nativeBinding = require('fastbloom-darwin-x64')
128
+ }
129
+ } catch (e) {
130
+ loadError = e
131
+ }
132
+ break
133
+ case 'arm64':
134
+ localFileExisted = existsSync(
135
+ join(__dirname, 'fastbloom.darwin-arm64.node')
136
+ )
137
+ try {
138
+ if (localFileExisted) {
139
+ nativeBinding = require('./fastbloom.darwin-arm64.node')
140
+ } else {
141
+ nativeBinding = require('fastbloom-darwin-arm64')
142
+ }
143
+ } catch (e) {
144
+ loadError = e
145
+ }
146
+ break
147
+ default:
148
+ throw new Error(`Unsupported architecture on macOS: ${arch}`)
149
+ }
150
+ break
151
+ case 'freebsd':
152
+ if (arch !== 'x64') {
153
+ throw new Error(`Unsupported architecture on FreeBSD: ${arch}`)
154
+ }
155
+ localFileExisted = existsSync(join(__dirname, 'fastbloom.freebsd-x64.node'))
156
+ try {
157
+ if (localFileExisted) {
158
+ nativeBinding = require('./fastbloom.freebsd-x64.node')
159
+ } else {
160
+ nativeBinding = require('fastbloom-freebsd-x64')
161
+ }
162
+ } catch (e) {
163
+ loadError = e
164
+ }
165
+ break
166
+ case 'linux':
167
+ switch (arch) {
168
+ case 'x64':
169
+ if (isMusl()) {
170
+ localFileExisted = existsSync(
171
+ join(__dirname, 'fastbloom.linux-x64-musl.node')
172
+ )
173
+ try {
174
+ if (localFileExisted) {
175
+ nativeBinding = require('./fastbloom.linux-x64-musl.node')
176
+ } else {
177
+ nativeBinding = require('fastbloom-linux-x64-musl')
178
+ }
179
+ } catch (e) {
180
+ loadError = e
181
+ }
182
+ } else {
183
+ localFileExisted = existsSync(
184
+ join(__dirname, 'fastbloom.linux-x64-gnu.node')
185
+ )
186
+ try {
187
+ if (localFileExisted) {
188
+ nativeBinding = require('./fastbloom.linux-x64-gnu.node')
189
+ } else {
190
+ nativeBinding = require('fastbloom-linux-x64-gnu')
191
+ }
192
+ } catch (e) {
193
+ loadError = e
194
+ }
195
+ }
196
+ break
197
+ case 'arm64':
198
+ if (isMusl()) {
199
+ localFileExisted = existsSync(
200
+ join(__dirname, 'fastbloom.linux-arm64-musl.node')
201
+ )
202
+ try {
203
+ if (localFileExisted) {
204
+ nativeBinding = require('./fastbloom.linux-arm64-musl.node')
205
+ } else {
206
+ nativeBinding = require('fastbloom-linux-arm64-musl')
207
+ }
208
+ } catch (e) {
209
+ loadError = e
210
+ }
211
+ } else {
212
+ localFileExisted = existsSync(
213
+ join(__dirname, 'fastbloom.linux-arm64-gnu.node')
214
+ )
215
+ try {
216
+ if (localFileExisted) {
217
+ nativeBinding = require('./fastbloom.linux-arm64-gnu.node')
218
+ } else {
219
+ nativeBinding = require('fastbloom-linux-arm64-gnu')
220
+ }
221
+ } catch (e) {
222
+ loadError = e
223
+ }
224
+ }
225
+ break
226
+ case 'arm':
227
+ if (isMusl()) {
228
+ localFileExisted = existsSync(
229
+ join(__dirname, 'fastbloom.linux-arm-musleabihf.node')
230
+ )
231
+ try {
232
+ if (localFileExisted) {
233
+ nativeBinding = require('./fastbloom.linux-arm-musleabihf.node')
234
+ } else {
235
+ nativeBinding = require('fastbloom-linux-arm-musleabihf')
236
+ }
237
+ } catch (e) {
238
+ loadError = e
239
+ }
240
+ } else {
241
+ localFileExisted = existsSync(
242
+ join(__dirname, 'fastbloom.linux-arm-gnueabihf.node')
243
+ )
244
+ try {
245
+ if (localFileExisted) {
246
+ nativeBinding = require('./fastbloom.linux-arm-gnueabihf.node')
247
+ } else {
248
+ nativeBinding = require('fastbloom-linux-arm-gnueabihf')
249
+ }
250
+ } catch (e) {
251
+ loadError = e
252
+ }
253
+ }
254
+ break
255
+ case 'riscv64':
256
+ if (isMusl()) {
257
+ localFileExisted = existsSync(
258
+ join(__dirname, 'fastbloom.linux-riscv64-musl.node')
259
+ )
260
+ try {
261
+ if (localFileExisted) {
262
+ nativeBinding = require('./fastbloom.linux-riscv64-musl.node')
263
+ } else {
264
+ nativeBinding = require('fastbloom-linux-riscv64-musl')
265
+ }
266
+ } catch (e) {
267
+ loadError = e
268
+ }
269
+ } else {
270
+ localFileExisted = existsSync(
271
+ join(__dirname, 'fastbloom.linux-riscv64-gnu.node')
272
+ )
273
+ try {
274
+ if (localFileExisted) {
275
+ nativeBinding = require('./fastbloom.linux-riscv64-gnu.node')
276
+ } else {
277
+ nativeBinding = require('fastbloom-linux-riscv64-gnu')
278
+ }
279
+ } catch (e) {
280
+ loadError = e
281
+ }
282
+ }
283
+ break
284
+ case 's390x':
285
+ localFileExisted = existsSync(
286
+ join(__dirname, 'fastbloom.linux-s390x-gnu.node')
287
+ )
288
+ try {
289
+ if (localFileExisted) {
290
+ nativeBinding = require('./fastbloom.linux-s390x-gnu.node')
291
+ } else {
292
+ nativeBinding = require('fastbloom-linux-s390x-gnu')
293
+ }
294
+ } catch (e) {
295
+ loadError = e
296
+ }
297
+ break
298
+ default:
299
+ throw new Error(`Unsupported architecture on Linux: ${arch}`)
300
+ }
301
+ break
302
+ default:
303
+ throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`)
304
+ }
305
+
306
+ if (!nativeBinding) {
307
+ if (loadError) {
308
+ throw loadError
309
+ }
310
+ throw new Error(`Failed to load native binding`)
311
+ }
312
+
313
+ const { BloomFilter } = nativeBinding
314
+
315
+ module.exports.BloomFilter = BloomFilter
package/package.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "fastbloom",
3
+ "version": "0.1.0",
4
+ "description": "High performance Bloom Filter implemented in Rust using fastbloom crate",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "build": "napi build --platform --release",
8
+ "test": "node test.js"
9
+ },
10
+ "dependencies": {
11
+ "@napi-rs/cli": "^2.18.0"
12
+ },
13
+ "files": [
14
+ "index.js",
15
+ "index.d.ts",
16
+ "*.node"
17
+ ],
18
+ "napi": {
19
+ "name": "fastbloom",
20
+ "triples": {
21
+ "defaults": true,
22
+ "additional": [
23
+ "x86_64-unknown-linux-musl",
24
+ "aarch64-unknown-linux-gnu",
25
+ "aarch64-apple-darwin",
26
+ "aarch64-pc-windows-msvc"
27
+ ]
28
+ }
29
+ }
30
+ }