content: /**
   * Copyright 2020 Alibaba Group Holding Limited.
   *
   * <p>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
   *
   * <p>http://www.apache.org/licenses/LICENSE-2.0
   *
   * <p>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.alibaba.graphscope.groot.common.util;
  
  import java.nio.Buffer;
  import java.nio.ByteBuffer;
  import java.util.List;
  
  /**
   * murmur hash 2.0.
   *
   * <p>The murmur hash is a relatively fast hash function from http://murmurhash.googlepages.com/ for
   * platforms with efficient multiplication.
   *
   * <p>This is a re-implementation of the original C code plus some additional features.
   */
  public final class PkHashUtils {
  
      private static final ThreadLocal<ByteBuffer> THREAD_BUFFER =
              ThreadLocal.withInitial(() -> ByteBuffer.allocate(64 << 10));
  
      public static long hash(int labelId, List<byte[]> pks) {
          ByteBuffer buffer = THREAD_BUFFER.get();
          clear(buffer);
          buffer.putInt(labelId);
          for (byte[] pk : pks) {
              buffer.putInt(pk.length);
              buffer.put(pk);
          }
          flip(buffer);
          return hash64(buffer.array(), buffer.limit());
      }
  
      public static long hash(long srcId, long dstId, int labelId, List<byte[]> pks) {
          ByteBuffer buffer = THREAD_BUFFER.get();
          clear(buffer);
          buffer.putLong(srcId);
          buffer.putLong(dstId);
          buffer.putInt(labelId);
          for (byte[] pk : pks) {
              buffer.putInt(pk.length);
              buffer.put(pk);
          }
          flip(buffer);
          return hash64(buffer.array(), buffer.limit());
      }
  
      public static long hash(long srcId, long dstId, int labelId, long nanoTime) {
          ByteBuffer buffer = THREAD_BUFFER.get();
          clear(buffer);
          buffer.putLong(srcId);
          buffer.putLong(dstId);
          buffer.putInt(labelId);
          buffer.putLong(nanoTime);
          flip(buffer);
          return hash64(buffer.array(), buffer.limit());
      }
  
      /**
       * Generates 64-bit hash from byte array of the given length and seed.
       *
       * @param data byte array to hash
       * @param length length of the array to hash
       * @param seed initial seed value
       * @return 64-bit hash of the given array
       */
      private static long hash64(final byte[] data, int length, int seed) {
          final long m = 0xc6a4a7935bd1e995L;
          final int r = 47;
  
          long h = (seed & 0xffffffffL) ^ (length * m);
          int length8 = length / 8;
  
          for (int i = 0; i < length8; i++) {
              final int i8 = i * 8;
              long k =
                      ((long) data[i8 + 0] & 0xff)
                              + (((long) data[i8 + 1] & 0xff) << 8)
                              + (((long) data[i8 + 2] & 0xff) << 16)
                              + (((long) data[i8 + 3] & 0xff) << 24)
                              + (((long) data[i8 + 4] & 0xff) << 32)
                              + (((long) data[i8 + 5] & 0xff) << 40)
                              + (((long) data[i8 + 6] & 0xff) << 48)
                              + (((long) data[i8 + 7] & 0xff) << 56);
  
              k *= m;
              k ^= k >>> r;
              k *= m;
  
              h ^= k;
              h *= m;
          }
  
          switch (length % 8) {
              case 7:
                  h ^= (long) (data[(length & ~7) + 6] & 0xff) << 48;
              case 6:
                  h ^= (long) (data[(length & ~7) + 5] & 0xff) << 40;
              case 5:
                  h ^= (long) (data[(length & ~7) + 4] & 0xff) << 32;
              case 4:
                  h ^= (long) (data[(length & ~7) + 3] & 0xff) << 24;
              case 3:
                  h ^= (long) (data[(length & ~7) + 2] & 0xff) << 16;
              case 2:
                  h ^= (long) (data[(length & ~7) + 1] & 0xff) << 8;
              case 1:
                  h ^= (long) (data[length & ~7] & 0xff);
                  h *= m;
          }
  
          h ^= h >>> r;
          h *= m;
          h ^= h >>> r;
  
          return h;
      }
  
      /**
       * Generates 64-bit hash from byte array with default seed value.
       *
       * @param data byte array to hash
       * @param length length of the array to hash
       * @return 64-bit hash of the given string
       */
      private static long hash64(final byte[] data, int length) {
          return hash64(data, length, 0xc70f6907);
      }
  
      public static void clear(Buffer buffer) {
          buffer.clear();
      }
  
      public static void flip(Buffer buffer) {
          buffer.flip();
      }
  }
  