package net.torvald.random; import net.torvald.unsafe.UnsafeHelper; /** * Code from https://richardstartin.github.io/posts/xxhash * https://github.com/richardstartin/xxhash-benchmark * Created by minjaesong on 2021-10-28. */ public class XXHash64 { static final long PRIME64_1 = 0x9E3779B185EBCA87L; static final long PRIME64_2 = 0xC2B2AE3D27D4EB4FL; static final long PRIME64_3 = 0x165667B19E3779F9L; static final long PRIME64_4 = 0x85EBCA77C2B2AE63L; static final long PRIME64_5 = 0x27D4EB2F165667C5L; public static long hash(byte[] input, long seed) { long hash; long remaining = input.length; int offset = 0; if (remaining >= 32) { long v1 = seed + PRIME64_1 + PRIME64_2; long v2 = seed + PRIME64_2; long v3 = seed; long v4 = seed - PRIME64_1; do { v1 += getLong(input, offset) * PRIME64_2; v1 = Long.rotateLeft(v1, 31); v1 *= PRIME64_1; v2 += getLong(input, offset + 8) * PRIME64_2; v2 = Long.rotateLeft(v2, 31); v2 *= PRIME64_1; v3 += getLong(input, offset + 16) * PRIME64_2; v3 = Long.rotateLeft(v3, 31); v3 *= PRIME64_1; v4 += getLong(input, offset + 24) * PRIME64_2; v4 = Long.rotateLeft(v4, 31); v4 *= PRIME64_1; offset += 32; remaining -= 32; } while (remaining >= 32); hash = Long.rotateLeft(v1, 1) + Long.rotateLeft(v2, 7) + Long.rotateLeft(v3, 12) + Long.rotateLeft(v4, 18); v1 *= PRIME64_2; v1 = Long.rotateLeft(v1, 31); v1 *= PRIME64_1; hash ^= v1; hash = hash * PRIME64_1 + PRIME64_4; v2 *= PRIME64_2; v2 = Long.rotateLeft(v2, 31); v2 *= PRIME64_1; hash ^= v2; hash = hash * PRIME64_1 + PRIME64_4; v3 *= PRIME64_2; v3 = Long.rotateLeft(v3, 31); v3 *= PRIME64_1; hash ^= v3; hash = hash * PRIME64_1 + PRIME64_4; v4 *= PRIME64_2; v4 = Long.rotateLeft(v4, 31); v4 *= PRIME64_1; hash ^= v4; hash = hash * PRIME64_1 + PRIME64_4; } else { hash = seed + PRIME64_5; } hash += input.length; while (remaining >= 8) { long k1 = getLong(input, offset); k1 *= PRIME64_2; k1 = Long.rotateLeft(k1, 31); k1 *= PRIME64_1; hash ^= k1; hash = Long.rotateLeft(hash, 27) * PRIME64_1 + PRIME64_4; offset += 8; remaining -= 8; } if (remaining >= 4) { hash ^= getInt(input, offset) * PRIME64_1; hash = Long.rotateLeft(hash, 23) * PRIME64_2 + PRIME64_3; offset += 4; remaining -= 4; } while (remaining != 0) { hash ^= input[offset] * PRIME64_5; hash = Long.rotateLeft(hash, 11) * PRIME64_1; --remaining; ++offset; } hash ^= hash >>> 33; hash *= PRIME64_2; hash ^= hash >>> 29; hash *= PRIME64_3; hash ^= hash >>> 32; return hash; } protected static long getLong(byte[] data, int offset) { return UnsafeHelper.INSTANCE.getUnsafe().getLong(data, offset + UnsafeHelper.INSTANCE.getArrayOffset(data)); } protected static int getInt(byte[] data, int offset) { return UnsafeHelper.INSTANCE.getUnsafe().getInt(data, offset + UnsafeHelper.INSTANCE.getArrayOffset(data)); } }