aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar jhmaster <32803471+jhmaster2000@users.noreply.github.com> 2023-08-08 03:30:05 -0300
committerGravatar GitHub <noreply@github.com> 2023-08-07 23:30:05 -0700
commit182e600eb79655e85b3f0371bc46fc4de8e70094 (patch)
treeb91231bc9155cc769cc81a7b2f0892c47bd26d2c
parentcb873cc0818d02216ac7285c58fe59883220d1a9 (diff)
downloadbun-182e600eb79655e85b3f0371bc46fc4de8e70094.tar.gz
bun-182e600eb79655e85b3f0371bc46fc4de8e70094.tar.zst
bun-182e600eb79655e85b3f0371bc46fc4de8e70094.zip
Fix `Bun.hash` functions (#4054)
* fix `Bun.hash` functions to behave as expected * update Bun.hash tests * properly test the returned hash * include murmur32v2 * update Bun.hash docs * run fmt
-rw-r--r--docs/api/hashing.md9
-rw-r--r--examples/hashing.js19
-rw-r--r--src/bun.js/api/bun.zig12
-rw-r--r--test/js/bun/util/hash.test.js39
4 files changed, 42 insertions, 37 deletions
diff --git a/docs/api/hashing.md b/docs/api/hashing.md
index 3c15e1346..13a285693 100644
--- a/docs/api/hashing.md
+++ b/docs/api/hashing.md
@@ -77,7 +77,7 @@ The standard `Bun.hash` functions uses [Wyhash](https://github.com/wangyi-fudan/
```ts
Bun.hash("some data here");
-// 976213160445840
+// 11562320457524636935n
```
The input can be a string, `TypedArray`, `DataView`, `ArrayBuffer`, or `SharedArrayBuffer`.
@@ -91,14 +91,14 @@ Bun.hash(arr.buffer);
Bun.hash(new DataView(arr.buffer));
```
-Optionally, an integer seed can be specified as the second parameter.
+Optionally, an integer seed can be specified as the second parameter. For 64-bit hashes seeds above `Number.MAX_SAFE_INTEGER` should be given as BigInt to avoid loss of precision.
```ts
Bun.hash("some data here", 1234);
-// 1173484059023252
+// 15724820720172937558n
```
-Additional hashing algorithms are available as properties on `Bun.hash`. The API is the same for each.
+Additional hashing algorithms are available as properties on `Bun.hash`. The API is the same for each, only changing the return type from number for 32-bit hashes to bigint for 64-bit hashes.
```ts
Bun.hash.wyhash("data", 1234); // equivalent to Bun.hash()
@@ -107,6 +107,7 @@ Bun.hash.adler32("data", 1234);
Bun.hash.cityHash32("data", 1234);
Bun.hash.cityHash64("data", 1234);
Bun.hash.murmur32v3("data", 1234);
+Bun.hash.murmur32v2("data", 1234);
Bun.hash.murmur64v2("data", 1234);
```
diff --git a/examples/hashing.js b/examples/hashing.js
index cf4772ffe..3f23d1312 100644
--- a/examples/hashing.js
+++ b/examples/hashing.js
@@ -1,18 +1,19 @@
-// Accepts a string, TypedArray, or Blob (file blob supported is not implemented but planned)
+// Accepts a string, TypedArray, or Blob (file blob support is not implemented but planned)
const input = "hello world".repeat(400);
// Bun.hash() defaults to Wyhash because it's fast
console.log(Bun.hash(input));
console.log(Bun.hash.wyhash(input));
-// and returns a number
-// all of these hashing functions return numbers, not typed arrays.
-console.log(Bun.hash.adler32(input));
-console.log(Bun.hash.crc32(input));
-console.log(Bun.hash.cityHash32(input));
-console.log(Bun.hash.cityHash64(input));
-console.log(Bun.hash.murmur32v3(input));
-console.log(Bun.hash.murmur64v2(input));
+// and returns a bigint
+// all of these hashing functions return number if 32-bit or bigint if 64-bit, not typed arrays.
+console.log(Bun.hash.adler32(input)); // number
+console.log(Bun.hash.crc32(input)); // number
+console.log(Bun.hash.cityHash32(input)); // number
+console.log(Bun.hash.cityHash64(input)); // bigint
+console.log(Bun.hash.murmur32v3(input)); // number
+console.log(Bun.hash.murmur32v2(input)); // number
+console.log(Bun.hash.murmur64v2(input)); // bigint
// Second argument accepts a seed where relevant
console.log(Bun.hash(input, 12345));
diff --git a/src/bun.js/api/bun.zig b/src/bun.js/api/bun.zig
index 5210063ea..fe0aafc25 100644
--- a/src/bun.js/api/bun.zig
+++ b/src/bun.js/api/bun.zig
@@ -3192,24 +3192,24 @@ pub const Hash = struct {
} else {
var seed: u64 = 0;
if (args.nextEat()) |arg| {
- if (arg.isNumber()) {
- seed = arg.toU32();
+ if (arg.isNumber() or arg.isBigInt()) {
+ seed = arg.toUInt64NoTruncate();
}
}
if (comptime std.meta.trait.isNumber(@TypeOf(function_args[0]))) {
- function_args[0] = @as(@TypeOf(function_args[0]), @intCast(seed));
+ function_args[0] = @as(@TypeOf(function_args[0]), @truncate(seed));
function_args[1] = input;
} else {
- function_args[1] = @as(@TypeOf(function_args[1]), @intCast(seed));
function_args[0] = input;
+ function_args[1] = @as(@TypeOf(function_args[1]), @truncate(seed));
}
const value = @call(.auto, Function, function_args);
if (@TypeOf(value) == u32) {
- return JSC.JSValue.jsNumber(@as(i32, @bitCast(value))).asObjectRef();
+ return JSC.JSValue.jsNumber(@as(u32, @bitCast(value))).asObjectRef();
}
- return JSC.JSValue.jsNumber(value).asObjectRef();
+ return JSC.JSValue.fromUInt64NoTruncate(ctx.ptr(), value).asObjectRef();
}
}
};
diff --git a/test/js/bun/util/hash.test.js b/test/js/bun/util/hash.test.js
index 87a5a9ce3..29c683801 100644
--- a/test/js/bun/util/hash.test.js
+++ b/test/js/bun/util/hash.test.js
@@ -1,47 +1,50 @@
-import fs from "fs";
import { it, expect } from "bun:test";
-import path from "path";
import { gcTick } from "harness";
it(`Bun.hash()`, () => {
gcTick();
- Bun.hash("hello world");
- Bun.hash(new TextEncoder().encode("hello world"));
+ expect(Bun.hash("hello world")).toBe(0x668d5e431c3b2573n);
+ expect(Bun.hash(new TextEncoder().encode("hello world"))).toBe(0x668d5e431c3b2573n);
});
it(`Bun.hash.wyhash()`, () => {
- Bun.hash.wyhash("hello world");
+ expect(Bun.hash.wyhash("hello world")).toBe(0x668d5e431c3b2573n);
gcTick();
- Bun.hash.wyhash(new TextEncoder().encode("hello world"));
+ expect(Bun.hash.wyhash(new TextEncoder().encode("hello world"))).toBe(0x668d5e431c3b2573n);
});
it(`Bun.hash.adler32()`, () => {
- Bun.hash.adler32("hello world");
+ expect(Bun.hash.adler32("hello world")).toBe(0x1a0b045d);
gcTick();
- Bun.hash.adler32(new TextEncoder().encode("hello world"));
+ expect(Bun.hash.adler32(new TextEncoder().encode("hello world"))).toBe(0x1a0b045d);
});
it(`Bun.hash.crc32()`, () => {
- Bun.hash.crc32("hello world");
+ expect(Bun.hash.crc32("hello world")).toBe(0x0d4a1185);
gcTick();
- Bun.hash.crc32(new TextEncoder().encode("hello world"));
+ expect(Bun.hash.crc32(new TextEncoder().encode("hello world"))).toBe(0x0d4a1185);
});
it(`Bun.hash.cityHash32()`, () => {
- Bun.hash.cityHash32("hello world");
+ expect(Bun.hash.cityHash32("hello world")).toBe(0x19a7581a);
gcTick();
- Bun.hash.cityHash32(new TextEncoder().encode("hello world"));
+ expect(Bun.hash.cityHash32(new TextEncoder().encode("hello world"))).toBe(0x19a7581a);
gcTick();
});
it(`Bun.hash.cityHash64()`, () => {
- Bun.hash.cityHash64("hello world");
+ expect(Bun.hash.cityHash64("hello world")).toBe(0xc7920bbdbecee42fn);
gcTick();
- Bun.hash.cityHash64(new TextEncoder().encode("hello world"));
+ expect(Bun.hash.cityHash64(new TextEncoder().encode("hello world"))).toBe(0xc7920bbdbecee42fn);
gcTick();
});
it(`Bun.hash.murmur32v3()`, () => {
- Bun.hash.murmur32v3("hello world");
+ expect(Bun.hash.murmur32v3("hello world")).toBe(0x5e928f0f);
gcTick();
- Bun.hash.murmur32v3(new TextEncoder().encode("hello world"));
+ expect(Bun.hash.murmur32v3(new TextEncoder().encode("hello world"))).toBe(0x5e928f0f);
+});
+it(`Bun.hash.murmur32v2()`, () => {
+ expect(Bun.hash.murmur32v2("hello world")).toBe(0x44a81419);
+ gcTick();
+ expect(Bun.hash.murmur32v2(new TextEncoder().encode("hello world"))).toBe(0x44a81419);
});
it(`Bun.hash.murmur64v2()`, () => {
- Bun.hash.murmur64v2("hello world");
+ expect(Bun.hash.murmur64v2("hello world")).toBe(0xd3ba2368a832afcen);
gcTick();
- Bun.hash.murmur64v2(new TextEncoder().encode("hello world"));
+ expect(Bun.hash.murmur64v2(new TextEncoder().encode("hello world"))).toBe(0xd3ba2368a832afcen);
});