Skip to main content

luaur_vm/functions/
lua_s_hash.rs

1use crate::macros::mix::mix;
2
3#[allow(non_snake_case)]
4pub fn luaS_hash(mut str: *const core::ffi::c_char, mut len: usize) -> core::ffi::c_uint {
5    // Note that this hashing algorithm is replicated in BytecodeBuilder.cpp, BytecodeBuilder::getStringHash
6    let mut a: u32 = 0;
7    let mut b: u32 = 0;
8    let mut h: u32 = len as u32;
9
10    // hash prefix in 12b chunks (using aligned reads) with ARX based hash (LuaJIT v2.1, lookup3)
11    // note that we stop at length<32 to maintain compatibility with Lua 5.1
12    while len >= 32 {
13        // should compile into fast unaligned reads
14        let mut block: [u32; 3] = [0; 3];
15        unsafe {
16            core::ptr::copy_nonoverlapping(str as *const u8, block.as_mut_ptr() as *mut u8, 12);
17        }
18
19        a = a.wrapping_add(block[0]);
20        b = b.wrapping_add(block[1]);
21        h = h.wrapping_add(block[2]);
22
23        mix(14, 11, 25, &mut a, &mut b, &mut h);
24
25        unsafe {
26            str = str.add(12);
27        }
28        len -= 12;
29    }
30
31    // original Lua 5.1 hash for compatibility (exact match when len<32)
32    for i in (1..=len).rev() {
33        let char_val = unsafe { *str.add(i - 1) } as u8;
34        h ^= h
35            .wrapping_shl(5)
36            .wrapping_add(h.wrapping_shr(2))
37            .wrapping_add(char_val as u32);
38    }
39
40    h
41}