// 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;
/*
 * Copyright 2019 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.zetasketch.internal.hash;



/**
 * Note to maintainers: This implementation relies on signed arithmetic being bit-wise equivalent
 * to unsigned arithmetic in all cases except:
 *
 * <ul>
 *   <li>comparisons (signed values can be negative)
 *   <li>division (avoided here)
 *   <li>shifting (right shift must be unsigned)
 * </ul>
 *
 */
final class Fingerprint2011 extends AbstractNonStreamingHashFunction {

  // Some primes between 2^63 and 2^64 for various uses.
  private static final long K0 = 0xa5b85c5e198ed849L;
  private static final long K1 = 0x8d58ac26afe12e47L;
  private static final long K2 = 0xc47b6e9e3a970ed3L;
  private static final long K3 = 0xc6a4a7935bd1e995L;

  @Override
  public HashCode hashBytes(byte[] input, int off, int len) {
    checkPositionIndexes(off, off + len, input.length);
    return HashCode.fromLong(fingerprint(input, off, len));
  }

  @Override
  public int bits() {
    return 64;
  }

  @Override
  public String toString() {
    return "Hashing.fingerprint2011()";
  }

  // End of public functions.

  @VisibleForTesting
  static long fingerprint(byte[] bytes, int offset, int length) {
    long result;

    if (length <= 32) {
      result = murmurHash64WithSeed(bytes, offset, length, K0 ^ K1 ^ K2);
    } else if (length <= 64) {
      result = hashLength33To64(bytes, offset, length);
    } else {
      result = fullFingerprint(bytes, offset, length);
    }

// 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;

/*
 * Copyright 2019 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.zetasketch.internal.hash;



/**
 * Note to maintainers: This implementation relies on signed arithmetic being bit-wise equivalent
 * to unsigned arithmetic in all cases except:
 *
 * <ul>
 *   <li>comparisons (signed values can be negative)
 *   <li>division (avoided here)
 *   <li>shifting (right shift must be unsigned)
 * </ul>
 *
 */
final class Fingerprint2011 extends AbstractNonStreamingHashFunction {

  // Some primes between 2^63 and 2^64 for various uses.
  private static final long K0 = 0xa5b85c5e198ed849L;
  private static final long K1 = 0x8d58ac26afe12e47L;
  private static final long K2 = 0xc47b6e9e3a970ed3L;
  private static final long K3 = 0xc6a4a7935bd1e995L;

  @Override
  public HashCode hashBytes(byte[] input, int off, int len) {
    checkPositionIndexes(off, off + len, input.length);
    return HashCode.fromLong(fingerprint(input, off, len));
  }

  @Override
  public int bits() {
    return 64;
  }

  @Override
  public String toString() {
    return "Hashing.fingerprint2011()";
  }

  // End of public functions.

  @VisibleForTesting
  static long fingerprint(byte[] bytes, int offset, int length) {
    long result;

    if (length <= 32) {
      result = murmurHash64WithSeed(bytes, offset, length, K0 ^ K1 ^ K2);
    } else if (length <= 64) {
      result = hashLength33To64(bytes, offset, length);
    } else {
      result = fullFingerprint(bytes, offset, length);
    }

    long u = length >= 8 ? load64(bytes, offset) : K0;