// Path: java/com/google/zetasketch/internal/hash/LittleEndianByteArray.java
// static long load64(byte[] input, int offset) {
//   // We don't want this in production code as this is the most critical part of the loop.
//   assert input.length >= offset + 8;
//   // Delegates to the fast (unsafe) version or the fallback.
//   return byteArray.getLongLittleEndian(input, offset);
// }
// 
// Path: java/com/google/zetasketch/internal/hash/LittleEndianByteArray.java
// static long load64Safely(byte[] input, int offset, int length) {
//   long result = 0;
//   // Due to the way we shift, we can stop iterating once we've run out of data, the rest
//   // of the result already being filled with zeros.
// 
//   // This loop is critical to performance, so please check HashBenchmark if altering it.
//   int limit = Math.min(length, 8);
//   for (int i = 0; i < limit; i++) {
//     // Shift value left while iterating logically through the array.
//     result |= (input[offset + i] & 0xFFL) << (i * 8);
//   }
//   return result;
// }


import static com.google.common.base.Preconditions.checkPositionIndexes;
import static com.google.zetasketch.internal.hash.LittleEndianByteArray.load64;
import static com.google.zetasketch.internal.hash.LittleEndianByteArray.load64Safely;
import static java.lang.Long.rotateRight;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.hash.HashCode;
    a = load64(bytes, offset + 16) + load64(bytes, offset + length - 32);
    z = load64(bytes, offset + length - 8);
    b = rotateRight(a + z, 52);
    c = rotateRight(a, 37);
    a += load64(bytes, offset + length - 24);
    c += rotateRight(a, 7);
    a += load64(bytes, offset + length - 16);
    long wf = a + z;
    long ws = b + rotateRight(a, 31) + c;
    long r = shiftMix((vf + ws) * K2 + (wf + vs) * K0);
    return shiftMix(r * K0 + vs) * K2;
  }

  @VisibleForTesting
  static long murmurHash64WithSeed(byte[] bytes, int offset, int length, long seed) {
    final long mul = K3;
    final int topBit = 0x7;

    int lengthAligned = length & ~topBit;
    int lengthRemainder = length & topBit;
    long hash = seed ^ (length * mul);

    for (int i = 0; i < lengthAligned; i += 8) {
      long loaded = load64(bytes, offset + i);
      long data = shiftMix(loaded * mul) * mul;
      hash ^= data;
      hash *= mul;
    }

    if (lengthRemainder != 0) {
// Path: java/com/google/zetasketch/internal/hash/LittleEndianByteArray.java
// static long load64(byte[] input, int offset) {
//   // We don't want this in production code as this is the most critical part of the loop.
//   assert input.length >= offset + 8;
//   // Delegates to the fast (unsafe) version or the fallback.
//   return byteArray.getLongLittleEndian(input, offset);
// }
// 
// Path: java/com/google/zetasketch/internal/hash/LittleEndianByteArray.java
// static long load64Safely(byte[] input, int offset, int length) {
//   long result = 0;
//   // Due to the way we shift, we can stop iterating once we've run out of data, the rest
//   // of the result already being filled with zeros.
// 
//   // This loop is critical to performance, so please check HashBenchmark if altering it.
//   int limit = Math.min(length, 8);
//   for (int i = 0; i < limit; i++) {
//     // Shift value left while iterating logically through the array.
//     result |= (input[offset + i] & 0xFFL) << (i * 8);
//   }
//   return result;
// }


// Path: java/com/google/zetasketch/internal/hash/Fingerprint2011.java
import static com.google.common.base.Preconditions.checkPositionIndexes;
import static com.google.zetasketch.internal.hash.LittleEndianByteArray.load64;
import static com.google.zetasketch.internal.hash.LittleEndianByteArray.load64Safely;
import static java.lang.Long.rotateRight;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.hash.HashCode;

    a = load64(bytes, offset + 16) + load64(bytes, offset + length - 32);
    z = load64(bytes, offset + length - 8);
    b = rotateRight(a + z, 52);
    c = rotateRight(a, 37);
    a += load64(bytes, offset + length - 24);
    c += rotateRight(a, 7);
    a += load64(bytes, offset + length - 16);
    long wf = a + z;
    long ws = b + rotateRight(a, 31) + c;
    long r = shiftMix((vf + ws) * K2 + (wf + vs) * K0);
    return shiftMix(r * K0 + vs) * K2;
  }

  @VisibleForTesting
  static long murmurHash64WithSeed(byte[] bytes, int offset, int length, long seed) {
    final long mul = K3;
    final int topBit = 0x7;

    int lengthAligned = length & ~topBit;
    int lengthRemainder = length & topBit;
    long hash = seed ^ (length * mul);

    for (int i = 0; i < lengthAligned; i += 8) {
      long loaded = load64(bytes, offset + i);
      long data = shiftMix(loaded * mul) * mul;
      hash ^= data;
      hash *= mul;
    }

    if (lengthRemainder != 0) {
      long data = load64Safely(bytes, offset + lengthAligned, lengthRemainder);