react-native-xxhash 0.1.8 → 0.1.10
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 +3 -1
- package/cpp/react-native-xxhash.cpp +15 -10
- package/cpp/react-native-xxhash.h +32 -10
- package/ios/Xxhash.mm +44 -2
- package/lib/commonjs/index.js +6 -3
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/index.js +7 -4
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/index.tsx +11 -8
package/README.md
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
A React Native library for hashing strings using the fast and deterministic xxHash algorithm, written in C++ with JSI for high performance. This library provides support for both 64-bit and 128-bit hashing.
|
|
4
4
|
|
|
5
|
-
|
|
6
5
|
## Features
|
|
7
6
|
|
|
8
7
|
- **High Performance**: xxHash is one of the fastest non-cryptographic hash functions.
|
|
@@ -10,6 +9,9 @@ A React Native library for hashing strings using the fast and deterministic xxHa
|
|
|
10
9
|
- **128-bit and 64-bit Support**: Choose between 128-bit and 64-bit hash outputs based on your use case.
|
|
11
10
|
- **Cross-Platform**: Supports both iOS and Android in React Native projects.
|
|
12
11
|
|
|
12
|
+
# Benchmarks (https://xxhash.com)
|
|
13
|
+
<img width="772" height="712" alt="Screenshot 2025-10-23 at 09 48 25" src="https://github.com/user-attachments/assets/792c220b-54cc-45d7-8e62-e26757d11e85" />
|
|
14
|
+
|
|
13
15
|
## Installation
|
|
14
16
|
|
|
15
17
|
To install the library, use either `npm` or `yarn`:
|
|
@@ -1,40 +1,45 @@
|
|
|
1
1
|
#include "react-native-xxhash.h"
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
constexpr size_t XXH128_HEX_LEN = 32;
|
|
4
|
+
constexpr size_t XXH64_HEX_LEN = 16;
|
|
5
|
+
constexpr size_t XXH128_HEX_LEN_NT = XXH128_HEX_LEN + 1;
|
|
6
|
+
constexpr size_t XXH64_HEX_LEN_NT = XXH64_HEX_LEN + 1;
|
|
7
|
+
|
|
8
|
+
void xxhash::install(jsi::Runtime *rt_ptr) {
|
|
9
|
+
jsi::Runtime &runtime = *rt_ptr;
|
|
5
10
|
|
|
6
11
|
jsi::Function hash128 = jsi::Function::createFromHostFunction(
|
|
7
12
|
runtime, jsi::PropNameID::forAscii(runtime, "hash128"), 1,
|
|
8
|
-
[](jsi::Runtime&
|
|
13
|
+
[](jsi::Runtime &rt, const jsi::Value &thisVal, const jsi::Value *args,
|
|
9
14
|
size_t count) {
|
|
10
|
-
const jsi::Value&
|
|
15
|
+
const jsi::Value &arg = args[0];
|
|
11
16
|
|
|
12
17
|
if (!arg.isString()) [[unlikely]] {
|
|
13
18
|
throw jsi::JSError(rt, "Argument is not a 'string'");
|
|
14
19
|
}
|
|
15
20
|
|
|
16
|
-
char result[
|
|
21
|
+
char result[XXH128_HEX_LEN_NT];
|
|
17
22
|
|
|
18
23
|
xxhash::make_hash_128(arg.asString(rt).utf8(rt), result);
|
|
19
24
|
|
|
20
|
-
return jsi::String::
|
|
25
|
+
return jsi::String::createFromAscii(rt, result, XXH128_HEX_LEN);
|
|
21
26
|
});
|
|
22
27
|
|
|
23
28
|
jsi::Function hash64 = jsi::Function::createFromHostFunction(
|
|
24
29
|
runtime, jsi::PropNameID::forAscii(runtime, "hash64"), 1,
|
|
25
|
-
[](jsi::Runtime&
|
|
30
|
+
[](jsi::Runtime &rt, const jsi::Value &thisVal, const jsi::Value *args,
|
|
26
31
|
size_t count) {
|
|
27
|
-
const jsi::Value&
|
|
32
|
+
const jsi::Value &arg = args[0];
|
|
28
33
|
|
|
29
34
|
if (!arg.isString()) [[unlikely]] {
|
|
30
35
|
throw jsi::JSError(rt, "Argument is not a 'string'");
|
|
31
36
|
}
|
|
32
37
|
|
|
33
|
-
char result[
|
|
38
|
+
char result[XXH64_HEX_LEN_NT];
|
|
34
39
|
|
|
35
40
|
xxhash::make_hash_64(arg.asString(rt).utf8(rt), result);
|
|
36
41
|
|
|
37
|
-
return jsi::String::
|
|
42
|
+
return jsi::String::createFromAscii(rt, result, XXH64_HEX_LEN);
|
|
38
43
|
});
|
|
39
44
|
|
|
40
45
|
runtime.global().setProperty(runtime, "__xxhash128", std::move(hash128));
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#pragma once
|
|
2
2
|
#ifndef XXHASH_H
|
|
3
3
|
#define XXHASH_H
|
|
4
|
-
#include
|
|
4
|
+
#include "xxhash.h"
|
|
5
5
|
#include <iomanip>
|
|
6
|
+
#include <jsi/jsi.h>
|
|
6
7
|
#include <sstream>
|
|
7
|
-
#include "xxhash.h"
|
|
8
8
|
|
|
9
9
|
using namespace facebook;
|
|
10
10
|
|
|
@@ -12,16 +12,38 @@ namespace xxhash {
|
|
|
12
12
|
|
|
13
13
|
inline void make_hash_64(const std::string_view str, char result[17]) noexcept {
|
|
14
14
|
XXH64_hash_t hash = XXH3_64bits(str.data(), str.size());
|
|
15
|
-
std::snprintf(result, 17, "%016llx", hash);
|
|
16
|
-
};
|
|
17
15
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
16
|
+
static constexpr char hex[] = "0123456789abcdef";
|
|
17
|
+
|
|
18
|
+
for (int i = 0; i < 16; ++i) {
|
|
19
|
+
const uint8_t nibble = (hash >> ((15 - i) * 4)) & 0xF;
|
|
20
|
+
result[i] = hex[nibble];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
result[16] = '\0';
|
|
22
24
|
};
|
|
23
25
|
|
|
24
|
-
void
|
|
25
|
-
|
|
26
|
+
inline void make_hash_128(std::string_view str, char result[33]) noexcept {
|
|
27
|
+
const XXH128_hash_t hash = XXH3_128bits(str.data(), str.size());
|
|
28
|
+
|
|
29
|
+
static constexpr char hex[] = "0123456789abcdef";
|
|
30
|
+
|
|
31
|
+
// high64 → first 16
|
|
32
|
+
for (int i = 0; i < 16; ++i) {
|
|
33
|
+
const uint8_t nibble = (hash.high64 >> ((15 - i) * 4)) & 0xF;
|
|
34
|
+
result[i] = hex[nibble];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// low64 → next 16
|
|
38
|
+
for (int i = 0; i < 16; ++i) {
|
|
39
|
+
const uint8_t nibble = (hash.low64 >> ((15 - i) * 4)) & 0xF;
|
|
40
|
+
result[16 + i] = hex[nibble];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
result[32] = '\0';
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
void install(jsi::Runtime *rt);
|
|
47
|
+
} // namespace xxhash
|
|
26
48
|
|
|
27
49
|
#endif /* XXHASH_H */
|
package/ios/Xxhash.mm
CHANGED
|
@@ -5,6 +5,27 @@
|
|
|
5
5
|
#import <React/RCTUtils.h>
|
|
6
6
|
#import <jsi/jsi.h>
|
|
7
7
|
|
|
8
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
9
|
+
#import <ReactCommon/RCTTurboModuleWithJSIBindings.h>
|
|
10
|
+
#import <ReactCommon/TurboModule.h>
|
|
11
|
+
#import <ReactCommon/CallInvoker.h>
|
|
12
|
+
#endif
|
|
13
|
+
|
|
14
|
+
using namespace facebook;
|
|
15
|
+
|
|
16
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
17
|
+
namespace {
|
|
18
|
+
class XxhashTurboModule : public facebook::react::TurboModule {
|
|
19
|
+
public:
|
|
20
|
+
XxhashTurboModule(std::shared_ptr<facebook::react::CallInvoker> jsInvoker)
|
|
21
|
+
: facebook::react::TurboModule("xxhash", std::move(jsInvoker)) {}
|
|
22
|
+
};
|
|
23
|
+
} // namespace
|
|
24
|
+
|
|
25
|
+
@interface Xxhash () <RCTTurboModule, RCTTurboModuleWithJSIBindings>
|
|
26
|
+
@end
|
|
27
|
+
#endif
|
|
28
|
+
|
|
8
29
|
@implementation Xxhash
|
|
9
30
|
RCT_EXPORT_MODULE(xxhash)
|
|
10
31
|
|
|
@@ -12,12 +33,19 @@ RCT_EXPORT_MODULE(xxhash)
|
|
|
12
33
|
@synthesize methodQueue = _methodQueue;
|
|
13
34
|
|
|
14
35
|
+ (BOOL)requiresMainQueueSetup {
|
|
15
|
-
return
|
|
36
|
+
return NO;
|
|
16
37
|
}
|
|
17
38
|
|
|
18
39
|
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(install){
|
|
19
40
|
NSLog(@"Installing JSI bindings for xxhash ...");
|
|
20
|
-
|
|
41
|
+
|
|
42
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
43
|
+
if (self.bridge == nil) {
|
|
44
|
+
return @true;
|
|
45
|
+
}
|
|
46
|
+
#endif
|
|
47
|
+
|
|
48
|
+
RCTBridge* bridge = self.bridge ?: [RCTBridge currentBridge];
|
|
21
49
|
RCTCxxBridge* cxxBridge = (RCTCxxBridge*)bridge;
|
|
22
50
|
|
|
23
51
|
if (cxxBridge == nil) {
|
|
@@ -34,5 +62,19 @@ RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(install){
|
|
|
34
62
|
return @true;
|
|
35
63
|
}
|
|
36
64
|
|
|
65
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
66
|
+
- (void)installJSIBindingsWithRuntime:(jsi::Runtime &)runtime
|
|
67
|
+
callInvoker:(const std::shared_ptr<react::CallInvoker> &)callInvoker {
|
|
68
|
+
xxhash::install(&runtime);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
- (void)installJSIBindingsWithRuntime:(jsi::Runtime &)runtime {
|
|
72
|
+
xxhash::install(&runtime);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
- (std::shared_ptr<react::TurboModule>)getTurboModule:(const react::ObjCTurboModule::InitParams &)params {
|
|
76
|
+
return std::make_shared<XxhashTurboModule>(params.jsInvoker);
|
|
77
|
+
}
|
|
78
|
+
#endif
|
|
37
79
|
|
|
38
80
|
@end
|
package/lib/commonjs/index.js
CHANGED
|
@@ -7,10 +7,13 @@ exports.hash64 = exports.hash128 = void 0;
|
|
|
7
7
|
var _reactNative = require("react-native");
|
|
8
8
|
let xxhashModule = globalThis.__xxhash128;
|
|
9
9
|
if (!xxhashModule) {
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
const XxhashModule = _reactNative.TurboModuleRegistry.get('xxhash') ?? _reactNative.NativeModules.xxhash;
|
|
11
|
+
if (XxhashModule) {
|
|
12
|
+
XxhashModule.install?.();
|
|
12
13
|
xxhashModule = globalThis.__xxhash128;
|
|
13
|
-
|
|
14
|
+
if (xxhashModule) {
|
|
15
|
+
console.log('✅ xxhash initialized successfully');
|
|
16
|
+
}
|
|
14
17
|
}
|
|
15
18
|
}
|
|
16
19
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_reactNative","require","xxhashModule","globalThis","__xxhash128","NativeModules","xxhash","install","console","log","hash128","input","Error","exports","hash64","__xxhash64"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;;;;;AAAA,IAAAA,YAAA,GAAAC,OAAA;AAOA,IAAIC,YAAY,
|
|
1
|
+
{"version":3,"names":["_reactNative","require","xxhashModule","globalThis","__xxhash128","XxhashModule","TurboModuleRegistry","get","NativeModules","xxhash","install","console","log","hash128","input","Error","exports","hash64","__xxhash64"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;;;;;AAAA,IAAAA,YAAA,GAAAC,OAAA;AAOA,IAAIC,YAAY,GAAIC,UAAU,CAASC,WAAwD;AAE/F,IAAG,CAACF,YAAY,EAAC;EACf,MAAMG,YAAiB,GAAGC,gCAAmB,CAACC,GAAG,CAAC,QAAQ,CAAC,IAAIC,0BAAa,CAACC,MAAM;EACnF,IAAGJ,YAAY,EAAC;IACdA,YAAY,CAACK,OAAO,GAAG,CAAC;IACxBR,YAAY,GAAIC,UAAU,CAASC,WAAW;IAC9C,IAAGF,YAAY,EAAC;MACdS,OAAO,CAACC,GAAG,CAAC,mCAAmC,CAAC;IAClD;EACF;AACF;;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACQ,MAAMC,OAAO,GAAIC,KAAa,IAAa;EACjD,IAAG,CAACA,KAAK,EAAC;IACR,MAAM,IAAIC,KAAK,CAAC,mBAAmB,CAAC;EACtC;EAEA,IAAG,OAAOD,KAAK,KAAK,QAAQ,EAAC;IAC3B,MAAM,IAAIC,KAAK,CAAC,wBAAwB,CAAC;EAC3C;EAEA,OAAOZ,UAAU,CAACC,WAAW,CAACU,KAAK,CAAC;AACrC,CAAC;;AAEF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAhBAE,OAAA,CAAAH,OAAA,GAAAA,OAAA;AAkBQ,MAAMI,MAAM,GAAIH,KAAa,IAAa;EAChD,IAAG,CAACA,KAAK,EAAC;IACR,MAAM,IAAIC,KAAK,CAAC,mBAAmB,CAAC;EACtC;EAEA,IAAG,OAAOD,KAAK,KAAK,QAAQ,EAAC;IAC3B,MAAM,IAAIC,KAAK,CAAC,wBAAwB,CAAC;EAC3C;EAEA,OAAOZ,UAAU,CAACe,UAAU,CAACJ,KAAK,CAAC;AACpC,CAAC;AAAAE,OAAA,CAAAC,MAAA,GAAAA,MAAA","ignoreList":[]}
|
package/lib/module/index.js
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
import { NativeModules } from 'react-native';
|
|
3
|
+
import { NativeModules, TurboModuleRegistry } from 'react-native';
|
|
4
4
|
let xxhashModule = globalThis.__xxhash128;
|
|
5
5
|
if (!xxhashModule) {
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
const XxhashModule = TurboModuleRegistry.get('xxhash') ?? NativeModules.xxhash;
|
|
7
|
+
if (XxhashModule) {
|
|
8
|
+
XxhashModule.install?.();
|
|
8
9
|
xxhashModule = globalThis.__xxhash128;
|
|
9
|
-
|
|
10
|
+
if (xxhashModule) {
|
|
11
|
+
console.log('✅ xxhash initialized successfully');
|
|
12
|
+
}
|
|
10
13
|
}
|
|
11
14
|
}
|
|
12
15
|
|
package/lib/module/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["NativeModules","xxhashModule","globalThis","__xxhash128","xxhash","install","console","log","hash128","input","Error","hash64","__xxhash64"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,SAAQA,aAAa,QAAO,cAAc;
|
|
1
|
+
{"version":3,"names":["NativeModules","TurboModuleRegistry","xxhashModule","globalThis","__xxhash128","XxhashModule","get","xxhash","install","console","log","hash128","input","Error","hash64","__xxhash64"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,SAAQA,aAAa,EAAEC,mBAAmB,QAAO,cAAc;AAO/D,IAAIC,YAAY,GAAIC,UAAU,CAASC,WAAwD;AAE/F,IAAG,CAACF,YAAY,EAAC;EACf,MAAMG,YAAiB,GAAGJ,mBAAmB,CAACK,GAAG,CAAC,QAAQ,CAAC,IAAIN,aAAa,CAACO,MAAM;EACnF,IAAGF,YAAY,EAAC;IACdA,YAAY,CAACG,OAAO,GAAG,CAAC;IACxBN,YAAY,GAAIC,UAAU,CAASC,WAAW;IAC9C,IAAGF,YAAY,EAAC;MACdO,OAAO,CAACC,GAAG,CAAC,mCAAmC,CAAC;IAClD;EACF;AACF;;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACC,OAAO,MAAMC,OAAO,GAAIC,KAAa,IAAa;EACjD,IAAG,CAACA,KAAK,EAAC;IACR,MAAM,IAAIC,KAAK,CAAC,mBAAmB,CAAC;EACtC;EAEA,IAAG,OAAOD,KAAK,KAAK,QAAQ,EAAC;IAC3B,MAAM,IAAIC,KAAK,CAAC,wBAAwB,CAAC;EAC3C;EAEA,OAAOV,UAAU,CAACC,WAAW,CAACQ,KAAK,CAAC;AACrC,CAAC;;AAEF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEC,OAAO,MAAME,MAAM,GAAIF,KAAa,IAAa;EAChD,IAAG,CAACA,KAAK,EAAC;IACR,MAAM,IAAIC,KAAK,CAAC,mBAAmB,CAAC;EACtC;EAEA,IAAG,OAAOD,KAAK,KAAK,QAAQ,EAAC;IAC3B,MAAM,IAAIC,KAAK,CAAC,wBAAwB,CAAC;EAC3C;EAEA,OAAOV,UAAU,CAACY,UAAU,CAACH,KAAK,CAAC;AACpC,CAAC","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.tsx"],"names":[],"mappings":"AACA,OAAO,CAAC,MAAM,CAAC;IACb,IAAI,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IAC3C,IAAI,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;CAC3C;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.tsx"],"names":[],"mappings":"AACA,OAAO,CAAC,MAAM,CAAC;IACb,IAAI,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IAC3C,IAAI,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;CAC3C;AAiBD;;;;;;;;;;;;;;;;GAgBG;AACF,eAAO,MAAM,OAAO,UAAW,MAAM,KAAG,MAUvC,CAAA;AAEF;;;;;;;;;;;;;;;;GAgBG;AAEF,eAAO,MAAM,MAAM,UAAW,MAAM,KAAG,MAUtC,CAAA"}
|
package/package.json
CHANGED
package/src/index.tsx
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
|
-
import {NativeModules} from 'react-native'
|
|
1
|
+
import {NativeModules, TurboModuleRegistry} from 'react-native'
|
|
2
2
|
declare global {
|
|
3
3
|
var __xxhash128: (input: string) => string;
|
|
4
4
|
var __xxhash64: (input: string) => string;
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
let xxhashModule = globalThis.__xxhash128;
|
|
8
|
+
let xxhashModule = (globalThis as any).__xxhash128 as typeof globalThis.__xxhash128 | undefined;
|
|
9
9
|
|
|
10
10
|
if(!xxhashModule){
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
const XxhashModule: any = TurboModuleRegistry.get('xxhash') ?? NativeModules.xxhash;
|
|
12
|
+
if(XxhashModule){
|
|
13
|
+
XxhashModule.install?.();
|
|
14
|
+
xxhashModule = (globalThis as any).__xxhash128;
|
|
15
|
+
if(xxhashModule){
|
|
16
|
+
console.log('✅ xxhash initialized successfully')
|
|
17
|
+
}
|
|
15
18
|
}
|
|
16
19
|
}
|
|
17
20
|
|
|
@@ -43,7 +46,7 @@ if(!xxhashModule){
|
|
|
43
46
|
}
|
|
44
47
|
|
|
45
48
|
return globalThis.__xxhash128(input);
|
|
46
|
-
}
|
|
49
|
+
}
|
|
47
50
|
|
|
48
51
|
/**
|
|
49
52
|
* Hashes the input string using the xxhash64 algorithm.
|
|
@@ -73,4 +76,4 @@ if(!xxhashModule){
|
|
|
73
76
|
}
|
|
74
77
|
|
|
75
78
|
return globalThis.__xxhash64(input);
|
|
76
|
-
}
|
|
79
|
+
}
|