Skip to content

Commit 13c607a

Browse files
committed
wip try to match rust & assembly
1 parent e3d8cdc commit 13c607a

File tree

3 files changed

+60
-48
lines changed

3 files changed

+60
-48
lines changed

packages/gearhash-wasm/assembly/next-match.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,24 @@ export class MatchResult {
1212
export function nextMatch(buf: Uint8Array, mask: u64, hash: u64 = 0): MatchResult {
1313
for (let i = 0; i < buf.length; i++) {
1414
const b = buf[i];
15-
hash = (hash << 1) + DEFAULT_TABLE[b];
15+
// Use proper unsigned operations to match Rust's wrapping_add behavior
16+
hash = ((hash << 1) as u64) + (DEFAULT_TABLE[b] as u64);
17+
18+
// console.log(
19+
// "hash " +
20+
// hash.toString(16) +
21+
// " " +
22+
// (hash << 1).toString(16) +
23+
// " " +
24+
// b.toString(16) +
25+
// " " +
26+
// (DEFAULT_TABLE[b] as u64).toString(16)
27+
// );
28+
// console.log("mask " + mask.toString(16));
29+
// console.log("hash & mask " + (hash & mask).toString(16));
1630

1731
if ((hash & mask) == 0) {
32+
// console.log("match found at position " + (i + 1).toString());
1833
return { position: i + 1, hash };
1934
}
2035
}

packages/gearhash-wasm/tests/index.js

Lines changed: 27 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,26 @@
1-
import { nextMatch } from "../build/debug.js";
1+
import { nextMatch, nextMatches } from "../build/debug.js";
22

3-
// Simple deterministic RNG for reproducible results (same as Rust version)
3+
// Simple deterministic RNG for reproducible results (32-bit version)
44
class SimpleRng {
55
constructor(seed) {
6-
this.state = BigInt(seed);
6+
this.state = seed;
77
}
88

9-
nextU64() {
10-
// Simple xorshift algorithm (same as Rust version)
11-
this.state ^= this.state << 13n;
12-
this.state ^= this.state >> 7n;
13-
this.state ^= this.state << 17n;
9+
nextU32() {
10+
// Simple 32-bit xorshift algorithm (same as Rust version)
11+
this.state ^= this.state << 13;
12+
this.state ^= this.state >> 17;
13+
this.state ^= this.state << 5;
1414
return this.state;
1515
}
1616

17+
nextU64() {
18+
// Generate two 32-bit values and combine them
19+
const low = this.nextU32();
20+
const high = this.nextU32();
21+
return (BigInt(high) << 32n) | BigInt(low);
22+
}
23+
1724
fillBytes(dest) {
1825
for (let i = 0; i < dest.length; i += 8) {
1926
const value = this.nextU64();
@@ -50,38 +57,20 @@ function testGearhash() {
5057
console.log("Chunk | Offset | Size | Hash");
5158
console.log("------|--------|------|------------------");
5259

53-
while (offset < inputBuf.length) {
54-
const chunkStart = offset;
55-
56-
const result = nextMatch(inputBuf.subarray(offset), BENCH_MASK, hash);
57-
if (result.matchSize > 0) {
58-
offset += result.matchSize;
59-
totalProcessed += result.matchSize;
60-
chunkCount += 1;
61-
hash = result.hash;
60+
const result = nextMatches(inputBuf, BENCH_MASK, 0);
61+
const matches = [...result.matches, { position: result.remaining, hash: result.hash }];
6262

63-
console.log(
64-
`${chunkCount.toString().padStart(5)} | ${chunkStart.toString().padStart(6)} | ${result.matchSize
65-
.toString()
66-
.padStart(4)} | 0x${hash.toString(16).padStart(16, "0")}`
67-
);
68-
} else {
69-
// No more matches, process remaining bytes
70-
const remaining = inputBuf.length - offset;
71-
// Update hash for remaining bytes
72-
for (let i = 0; i < remaining; i++) {
73-
hash = ((hash << 1n) + BigInt(inputBuf[offset + i])) & 0xffffffffffffffffn;
74-
}
75-
totalProcessed += remaining;
76-
chunkCount += 1;
63+
for (const match of matches) {
64+
offset += match.position;
65+
totalProcessed += match.position;
66+
chunkCount += 1;
67+
hash = match.hash;
7768

78-
console.log(
79-
`${chunkCount.toString().padStart(5)} | ${offset.toString().padStart(6)} | ${remaining
80-
.toString()
81-
.padStart(4)} | 0x${hash.toString(16).padStart(16, "0")} (final)`
82-
);
83-
break;
84-
}
69+
console.log(
70+
`${chunkCount.toString().padStart(5)} | ${offset.toString().padStart(6)} | ${match.position
71+
.toString()
72+
.padStart(4)} | 0x${match.hash.toString(16).padStart(16, "0")}`
73+
);
8574
}
8675

8776
console.log("\nSummary:");

packages/gearhash-wasm/vendor/test_gearhash.rs

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,30 @@
11
use gearhash::{Hasher, DEFAULT_TABLE};
22

3-
// Simple deterministic RNG for reproducible results
3+
// Simple deterministic RNG for reproducible results (32-bit version)
44
struct SimpleRng {
5-
state: u64,
5+
state: u32,
66
}
77

88
impl SimpleRng {
9-
fn new(seed: u64) -> Self {
9+
fn new(seed: u32) -> Self {
1010
Self { state: seed }
1111
}
1212

13-
fn next_u64(&mut self) -> u64 {
14-
// Simple xorshift algorithm
13+
fn next_u32(&mut self) -> u32 {
14+
// Simple 32-bit xorshift algorithm
1515
self.state ^= self.state << 13;
16-
self.state ^= self.state >> 7;
17-
self.state ^= self.state << 17;
16+
self.state ^= self.state >> 17;
17+
self.state ^= self.state << 5;
1818
self.state
1919
}
2020

21+
fn next_u64(&mut self) -> u64 {
22+
// Generate two 32-bit values and combine them
23+
let low = self.next_u32() as u64;
24+
let high = self.next_u32() as u64;
25+
(high << 32) | low
26+
}
27+
2128
fn fill_bytes(&mut self, dest: &mut [u8]) {
2229
for chunk in dest.chunks_mut(8) {
2330
let value = self.next_u64();
@@ -28,7 +35,7 @@ impl SimpleRng {
2835
}
2936
}
3037

31-
const BENCH_INPUT_SEED: u64 = 0xbecd17f;
38+
const BENCH_INPUT_SEED: u32 = 0xbecd17f;
3239
const BENCH_MASK: u64 = 0x0000d90003530000;
3340
const INPUT_SIZE: usize = 100_000;
3441

@@ -64,10 +71,11 @@ fn test_gearhash() {
6471

6572
println!("{:5} | {:6} | {:4} | 0x{:016x}",
6673
chunk_count, chunk_start, match_size, hasher.get_hash());
74+
75+
hasher.set_hash(0);
6776
} else {
6877
// No more matches, process remaining bytes
6978
let remaining = input_buf.len() - offset;
70-
hasher.update(&input_buf[offset..]);
7179
total_processed += remaining;
7280
chunk_count += 1;
7381

0 commit comments

Comments
 (0)