diff --git a/src/utils/hash.c b/src/utils/hash.c index 09030910..6837a92d 100644 --- a/src/utils/hash.c +++ b/src/utils/hash.c @@ -2,6 +2,48 @@ #include "hash.h" #include "time.h" +NOINLINE u64 bqn_hashArr(B x, const u64 secret[4]) { // TODO manual separation of atom & arr probably won't be worth it when there are actually sane typed array hashing things + usz xia = a(x)->ia; + if (xia==0) return ~secret[3]; // otherwise squeeze will care about fills + x = any_squeeze(inc(x)); + u8 xr = rnk(x); + u8 xe = TI(x,elType); + u64 shHash; + if (xr<=1) shHash = wyhash64(xia, xe); + else shHash = wyhash(a(x)->sh, xr*sizeof(usz), xe, secret); + bool isTemp = false; + void* data; + u64 bytes; + switch(xe) { default: UD; + case el_bit: bcl(x,xia); data = bitarr_ptr(x); bytes = BIT_N(xia); break; + case el_i8: case el_c8: data = tyany_ptr(x); bytes = xia*1; break; + case el_i16: case el_c16: data = tyany_ptr(x); bytes = xia*2; break; + case el_i32: case el_c32: data = tyany_ptr(x); bytes = xia*4; break; + case el_f64: data = f64any_ptr(x); bytes = xia*8; break; + case el_B:; + TALLOC(u64, dataTmp, xia); + isTemp = true; + SGetU(x) + for (usz i = 0; i < xia; i++) dataTmp[i] = bqn_hash(GetU(x, i), secret); + data = dataTmp; + bytes = xia*sizeof(B); + break; + } + u64 r = wyhash(data, bytes, shHash, secret); + if (isTemp) TFREE(data); + dec(x); + return r; +} + +NOINLINE u64 bqn_hash(B x, const u64 secret[4]) { + if (isArr(x)) return bqn_hashArr(x, secret); + if (q_f64(x)) return wyhash64(secret[0], x.u); + if (isC32(x)) return wyhash64(secret[1], x.u); + assert(isVal(x)); + return wyhash64(secret[2], x.u); +} + + u64 wy_secret[4]; void hash_init() { diff --git a/src/utils/hash.h b/src/utils/hash.h index 23248e02..4aeb476d 100644 --- a/src/utils/hash.h +++ b/src/utils/hash.h @@ -10,38 +10,8 @@ static void bcl(B x, usz ia) { // clean up bitarr tail bits to zero xp[ia>>6]&= (1ULL<<(ia&63)) - 1; } } -static u64 bqn_hash(B x, const u64 secret[4]) { // doesn't consume - if (isAtm(x)) { - if (q_f64(x)) return wyhash64(secret[0], x.u); - if (isC32(x)) return wyhash64(secret[1], x.u); - assert(isVal(x)); - return wyhash64(secret[2], x.u); - } - inc(x); - x = any_squeeze(x); - u64 shHash = wyhash(a(x)->sh, rnk(x)*sizeof(usz), 0, secret); - u8 xe = TI(x,elType); - usz xia = a(x)->ia; - u64 r; - if (xe==el_bit) { bcl(x,xia); r = wyhash(bitarr_ptr(x), BIT_N(xia), shHash, secret); } - else if (xe==el_i8 ) { r = wyhash(i8any_ptr (x), xia*1, shHash, secret); } - else if (xe==el_i16) { r = wyhash(i16any_ptr(x), xia*2, shHash, secret); } - else if (xe==el_i32) { r = wyhash(i32any_ptr(x), xia*4, shHash, secret); } - else if (xe==el_c8 ) { r = wyhash(c8any_ptr (x), xia*1, shHash, secret); } - else if (xe==el_c16) { r = wyhash(c16any_ptr(x), xia*2, shHash, secret); } - else if (xe==el_c32) { r = wyhash(c32any_ptr(x), xia*4, shHash, secret); } - else if (xe==el_f64) { r = wyhash(f64any_ptr(x), xia*8, shHash, secret); } - else { - assert(xe==el_B); - TALLOC(u64, data, xia); - SGetU(x) - for (usz i = 0; i < xia; i++) data[i] = bqn_hash(GetU(x, i), secret); - r = wyhash(data, xia*8, shHash, secret); - TFREE(data); - } - dec(x); - return r; -} + +u64 bqn_hash(B x, const u64 secret[4]); // doesn't consume static u64 bqn_hashP(B x, const u64 secret[4]) { // bqn_hash but never zero u64 r = bqn_hash(x, secret); diff --git a/src/utils/wyhash.h b/src/utils/wyhash.h index 76facf28..f085bfbb 100644 --- a/src/utils/wyhash.h +++ b/src/utils/wyhash.h @@ -115,7 +115,7 @@ static inline uint64_t _wyr4(const uint8_t *p) { #endif static inline uint64_t _wyr3(const uint8_t *p, size_t k) { return (((uint64_t)p[0])<<16)|(((uint64_t)p[k>>1])<<8)|p[k-1];} //wyhash main function -static inline uint64_t wyhash(const void *key, size_t len, uint64_t seed, const uint64_t *secret){ +FORCE_INLINE uint64_t wyhash(const void *key, size_t len, uint64_t seed, const uint64_t *secret){ const uint8_t *p=(const uint8_t *)key; seed^=*secret; uint64_t a, b; if(_likely_(len<=16)){ if(_likely_(len>=4)){ a=(_wyr4(p)<<32)|_wyr4(p+((len>>3)<<2)); b=(_wyr4(p+len-4)<<32)|_wyr4(p+len-4-((len>>3)<<2)); }