Skip to content

Commit 5ea38c3

Browse files
committed
feat(xxhash): init xxhash32 and xxhash64
1 parent ff17f0e commit 5ea38c3

File tree

38 files changed

+875
-0
lines changed

38 files changed

+875
-0
lines changed

.cargo/config.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
[target.x86_64-pc-windows-msvc]
2+
rustflags = ["-C", "target-cpu=skylake"]
3+
14
[target.aarch64-unknown-linux-gnu]
25
linker = "aarch64-linux-gnu-gcc"
36

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,16 @@ cargo-features = ["strip"]
22

33
[workspace]
44
members = [
5+
"./crates/alloc",
56
"./packages/bcrypt",
67
"./packages/crc32",
78
"./packages/deno-lint",
89
"./packages/jieba",
10+
"./packages/xxhash",
911
]
1012

1113
[profile.release]
14+
codegen-units = 1
1215
lto = true
16+
overflow-checks = false
1317
strip = 'symbols'

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
"devDependencies": {
2525
"@napi-rs/cli": "^1.3.3",
2626
"@swc-node/register": "^1.3.6",
27+
"@types/node": "^16.11.1",
2728
"@typescript-eslint/eslint-plugin": "^4.33.0",
2829
"@typescript-eslint/parser": "^4.33.0",
2930
"ava": "^3.15.0",

packages/xxhash/Cargo.toml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[package]
2+
authors = ["LongYinan <[email protected]>"]
3+
edition = "2021"
4+
name = "xxhash"
5+
version = "0.1.0"
6+
7+
[lib]
8+
crate-type = ["cdylib"]
9+
10+
[dependencies]
11+
global_alloc = {path = "../../crates/alloc"}
12+
napi = {version = "1", features = ["napi6"]}
13+
napi-derive = "1"
14+
xxhash-rust = {version = "0.8", features = ["xxh32", "const_xxh32", "xxh64", "const_xxh64", "xxh3", "const_xxh3"]}
15+
16+
[build-dependencies]
17+
napi-build = "1"

packages/xxhash/README.md

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
# `@node-rs/xxhash`
2+
3+
![](https://github.com/napi-rs/node-rs/workflows/CI/badge.svg)
4+
![](https://img.shields.io/npm/dm/@node-rs/xxhash.svg?sanitize=true)
5+
[![Install size](https://packagephobia.com/badge?p=@node-rs/xxhash)](https://packagephobia.com/result?p=@node-rs/xxhash)
6+
7+
> 🚀 Help me to become a full-time open-source developer by [sponsoring me on Github](https://github.com/sponsors/Brooooooklyn)
8+
9+
Fastest `xxhash` implementation in Node.js.
10+
11+
## Install this package
12+
13+
```
14+
yarn add @node-rs/xxhash
15+
pnpm add @node-rs/xxhash
16+
npm install @node-rs/xxhash
17+
```
18+
19+
## Support matrix
20+
21+
| | node12 | node14 | node16 |
22+
| --------------------- | ------ | ------ | ------ |
23+
| Windows x64 ||||
24+
| Windows x32 ||||
25+
| Windows arm64 ||||
26+
| macOS x64 ||||
27+
| macOS arm64 (m chips) ||||
28+
| Linux x64 gnu ||||
29+
| Linux x64 musl ||||
30+
| Linux arm gnu ||||
31+
| Linux arm64 gnu ||||
32+
| Linux arm64 musl ||||
33+
| Android arm64 ||||
34+
| FreeBSD x64 ||||
35+
36+
## API
37+
38+
```ts
39+
export type BufferLike =
40+
| Buffer
41+
| string
42+
| Uint8Array
43+
| ArrayBuffer
44+
| SharedArrayBuffer
45+
| ReadonlyArray<number>
46+
| number[]
47+
48+
export function xxh32(input: BufferLike, seed?: number): number
49+
export function xxh64(input: BufferLike, seed?: BigInt): BigInt
50+
51+
export class Xxh32 {
52+
constructor(seed?: number)
53+
update(input: BufferLike): this
54+
digest(): number
55+
}
56+
57+
export class Xxh64 {
58+
constructor(seed?: BigInt)
59+
update(input: BufferLike): this
60+
digest(): BigInt
61+
}
62+
```
63+
64+
## Performance
65+
66+
### Hardware
67+
68+
```
69+
OS: Windows 10 x86_64
70+
Host: Micro-Star International Co., Ltd. MS-7C35
71+
Kernel: 10.0.19043
72+
Terminal: Windows Terminal
73+
CPU: AMD Ryzen 9 5950X (32) @ 3.400GHz
74+
Memory: 32688MiB
75+
```
76+
77+
### Result
78+
79+
```
80+
@node-rs/xxhash h32 x 4,663 ops/sec ±6.22% (81 runs sampled)
81+
xxhashjs h32 x 1,880 ops/sec ±7.11% (75 runs sampled)
82+
xxh32 bench suite: Fastest is @node-rs/xxhash h32
83+
84+
@node-rs/xxhash h32 x 13,452 ops/sec ±2.73% (80 runs sampled)
85+
xxhashjs h32 x 2,496 ops/sec ±0.39% (97 runs sampled)
86+
xxh32 multi steps bench suite: Fastest is @node-rs/xxhash h32
87+
88+
@node-rs/xxhash 64 x 15,806 ops/sec ±3.14% (79 runs sampled)
89+
xxhashjs h64 x 69.11 ops/sec ±5.99% (60 runs sampled)
90+
xxh64 bench suite: Fastest is @node-rs/xxhash 64
91+
92+
@node-rs/xxhash 64 x 13,841 ops/sec ±3.17% (82 runs sampled)
93+
xxhashjs h64 x 79.71 ops/sec ±4.34% (70 runs sampled)
94+
xxh64 multi steps bench suite: Fastest is @node-rs/xxhash 64
95+
```
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import test from 'ava'
2+
import { h32 } from 'xxhashjs'
3+
4+
import { xxh32, Xxh32 } from '../index'
5+
6+
const FX = Buffer.from('@node-rs/xxhash vs xxhashjs')
7+
const SEED = 0xabcdef01
8+
9+
test('xxh32 without seed', (t) => {
10+
t.is(xxh32(FX), h32(FX, 0).toNumber())
11+
})
12+
13+
test('xxh32 with seed', (t) => {
14+
t.is(xxh32(FX, SEED), h32(FX, SEED).toNumber())
15+
})
16+
17+
test('xxh32 string', (t) => {
18+
t.is(xxh32(FX.toString('utf8')), h32(FX, 0).toNumber())
19+
})
20+
21+
test('xxh32 Uint8Array', (t) => {
22+
t.is(xxh32(new Uint8Array(FX.buffer)), h32(FX.buffer, 0).toNumber())
23+
})
24+
25+
test('Xxh32 oneshot', (t) => {
26+
t.is(new Xxh32().update(FX).digest(), h32(FX, 0).toNumber())
27+
})
28+
29+
test('Xxh32 multi steps', (t) => {
30+
t.is(
31+
new Xxh32().update(FX).update(FX).update(FX).digest(),
32+
h32(0).update(FX).update(FX).update(FX).digest().toNumber(),
33+
)
34+
})
35+
36+
test('Xxh32 string', (t) => {
37+
t.is(new Xxh32().update(FX.toString('utf8')).digest(), h32(FX, 0).toNumber())
38+
})
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import test from 'ava'
2+
import { h64 } from 'xxhashjs'
3+
4+
import { xxh64, Xxh64 } from '../index'
5+
6+
const FX = Buffer.from('@node-rs/xxhash vs xxhashjs')
7+
const SEED = 0xabcdef01
8+
9+
test('xxh64 without seed', (t) => {
10+
t.is(xxh64(FX).toString(16), h64(FX, 0).toString(16))
11+
})
12+
13+
test('xxh64 with seed', (t) => {
14+
t.is(xxh64(FX, BigInt(SEED)).toString(16), h64(FX, SEED).toString(16))
15+
})
16+
17+
test('xxh64 string', (t) => {
18+
t.is(xxh64(FX.toString('utf8')).toString(16), h64(FX, 0).toString(16))
19+
})
20+
21+
test('xxh64 Uint8Array', (t) => {
22+
t.is(xxh64(new Uint8Array(FX.buffer)).toString(16), h64(FX.buffer, 0).toString(16))
23+
})
24+
25+
test('Xxh64 oneshot', (t) => {
26+
t.is(new Xxh64().update(FX).digest().toString(16), h64(FX, 0).toString(16))
27+
})
28+
29+
test('Xxh64 multi steps', (t) => {
30+
t.is(
31+
new Xxh64().update(FX).update(FX).update(FX).digest().toString(16),
32+
h64(0).update(FX).update(FX).update(FX).digest().toString(16),
33+
)
34+
})
35+
36+
test('Xxh64 string', (t) => {
37+
t.is(new Xxh64().update(FX.toString('utf8')).digest().toString(16), h64(FX, 0).toString(16))
38+
})
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
const { readFileSync } = require('fs')
2+
const { join } = require('path')
3+
4+
const { Suite } = require('benchmark')
5+
const chalk = require('chalk')
6+
const { h32: h32js, h64: h64js } = require('xxhashjs')
7+
8+
const { xxh32, xxh64, Xxh32, Xxh64 } = require('../index')
9+
10+
const FX = readFileSync(join(__dirname, '..', '..', '..', 'yarn.lock'))
11+
12+
new Suite('xxh32')
13+
.add('@node-rs/xxhash h32', () => {
14+
xxh32(FX)
15+
})
16+
.add('xxhashjs h32', () => {
17+
h32js(FX, 0).toNumber()
18+
})
19+
.on('cycle', function (event) {
20+
console.info(String(event.target))
21+
})
22+
.on('complete', function () {
23+
console.info(`${this.name} bench suite: Fastest is ${chalk.green(this.filter('fastest').map('name'))}`)
24+
})
25+
.run()
26+
27+
new Suite('xxh32 multi steps')
28+
.add('@node-rs/xxhash h32', () => {
29+
new Xxh32().update(FX).digest()
30+
})
31+
.add('xxhashjs h32', () => {
32+
h32js().update(FX).digest().toNumber()
33+
})
34+
.on('cycle', function (event) {
35+
console.info(String(event.target))
36+
})
37+
.on('complete', function () {
38+
console.info(`${this.name} bench suite: Fastest is ${chalk.green(this.filter('fastest').map('name'))}`)
39+
})
40+
.run()
41+
42+
new Suite('xxh64')
43+
.add('@node-rs/xxhash 64', () => {
44+
xxh64(FX).toString(16)
45+
})
46+
.add('xxhashjs h64', () => {
47+
h64js(FX, 0).toString(16)
48+
})
49+
.on('cycle', function (event) {
50+
console.info(String(event.target))
51+
})
52+
.on('complete', function () {
53+
console.info(`${this.name} bench suite: Fastest is ${chalk.green(this.filter('fastest').map('name'))}`)
54+
})
55+
.run()
56+
57+
new Suite('xxh64 multi steps')
58+
.add('@node-rs/xxhash 64', () => {
59+
new Xxh64().update(FX).digest().toString(16)
60+
})
61+
.add('xxhashjs h64', () => {
62+
h64js(0).update(FX).digest().toString(16)
63+
})
64+
.on('cycle', function (event) {
65+
console.info(String(event.target))
66+
})
67+
.on('complete', function () {
68+
console.info(`${this.name} bench suite: Fastest is ${chalk.green(this.filter('fastest').map('name'))}`)
69+
})
70+
.run()

packages/xxhash/build.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
extern crate napi_build;
2+
3+
fn main() {
4+
napi_build::setup();
5+
}

packages/xxhash/index.d.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
export type BufferLike =
2+
| Buffer
3+
| string
4+
| Uint8Array
5+
| ArrayBuffer
6+
| SharedArrayBuffer
7+
| ReadonlyArray<number>
8+
| number[]
9+
10+
export function xxh32(input: BufferLike, seed?: number): number
11+
export function xxh64(input: BufferLike, seed?: BigInt): BigInt
12+
13+
export class Xxh32 {
14+
constructor(seed?: number)
15+
update(input: BufferLike): this
16+
digest(): number
17+
}
18+
19+
export class Xxh64 {
20+
constructor(seed?: BigInt)
21+
update(input: BufferLike): this
22+
digest(): BigInt
23+
}

0 commit comments

Comments
 (0)