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 +84 -0
- package/fastbloom.linux-x64-gnu.node +0 -0
- package/index.d.ts +33 -0
- package/index.js +315 -0
- package/package.json +30 -0
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
|
+
}
|