/* -------------------------------------------------------------------- */ uint32_t jlu32w(uint32_t h, const uint32_t *k, size_t size) { uint32_t a = _JLU3_INIT(h, (size * sizeof(*k))); uint32_t b = a; uint32_t c = a; if (k == NULL) goto exit; /*----------------------------------------------- handle most of the key */ while (size > 3) { a += k[0]; b += k[1]; c += k[2]; _JLU3_MIX(a,b,c); size -= 3; k += 3; } /*----------------------------------------- handle the last 3 uint32_t's */ switch (size) { case 3 : c+=k[2]; case 2 : b+=k[1]; case 1 : a+=k[0]; _JLU3_FINAL(a,b,c); /*@fallthrough@*/ case 0: break; } /*---------------------------------------------------- report the result */ exit: return c; }
/* -------------------------------------------------------------------- */ uint32_t jlu32l(uint32_t h, const void *key, size_t size) { union { const void *ptr; size_t i; } u; uint32_t a = _JLU3_INIT(h, size); uint32_t b = a; uint32_t c = a; if (key == NULL) goto exit; u.ptr = key; if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) { const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */ #ifdef VALGRIND const uint8_t *k8; #endif /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */ while (size > 12) { a += k[0]; b += k[1]; c += k[2]; _JLU3_MIX(a,b,c); size -= 12; k += 3; } /*------------------------- handle the last (probably partial) block */ /* * "k[2]&0xffffff" actually reads beyond the end of the string, but * then masks off the part it's not allowed to read. Because the * string is aligned, the masked-off tail is in the same word as the * rest of the string. Every machine with memory protection I've seen * does it on word boundaries, so is OK with this. But VALGRIND will * still catch it and complain. The masking trick does make the hash * noticably faster for short strings (like English words). */ #ifndef VALGRIND switch (size) { case 12: c += k[2]; b+=k[1]; a+=k[0]; break; case 11: c += k[2]&0xffffff; b+=k[1]; a+=k[0]; break; case 10: c += k[2]&0xffff; b+=k[1]; a+=k[0]; break; case 9: c += k[2]&0xff; b+=k[1]; a+=k[0]; break; case 8: b += k[1]; a+=k[0]; break; case 7: b += k[1]&0xffffff; a+=k[0]; break; case 6: b += k[1]&0xffff; a+=k[0]; break; case 5: b += k[1]&0xff; a+=k[0]; break; case 4: a += k[0]; break; case 3: a += k[0]&0xffffff; break; case 2: a += k[0]&0xffff; break; case 1: a += k[0]&0xff; break; case 0: goto exit; } #else /* make valgrind happy */ k8 = (const uint8_t *)k; switch (size) { case 12: c += k[2]; b+=k[1]; a+=k[0] break; case 11: c += ((uint32_t)k8[10])<<16; /*@fallthrough@*/ case 10: c += ((uint32_t)k8[9])<<8; /*@fallthrough@*/ case 9: c += k8[8]; /*@fallthrough@*/ case 8: b += k[1]; a+=k[0]; break; case 7: b += ((uint32_t)k8[6])<<16; /*@fallthrough@*/ case 6: b += ((uint32_t)k8[5])<<8; /*@fallthrough@*/ case 5: b += k8[4]; /*@fallthrough@*/ case 4: a += k[0]; break; case 3: a += ((uint32_t)k8[2])<<16; /*@fallthrough@*/ case 2: a += ((uint32_t)k8[1])<<8; /*@fallthrough@*/ case 1: a += k8[0]; break; case 0: goto exit; } #endif /* !valgrind */ } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {