All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.grpc.xds.XxHash64 Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2021 Higher Frequency Trading http://www.higherfrequencytrading.com
 *
 * 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
 *
 * http://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.
 */
/*
 * Forked from zero-allocation-hashing-0.14 (https://github.com/OpenHFT/Zero-Allocation-Hashing).
 * Modified by the gRPC Authors
 */

package io.grpc.xds;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;

import java.nio.ByteOrder;

/**
 * The XxHash is a fast, non-cryptographic, 64-bit hash function that has excellent avalanche
 * and 2-way bit independence properties.
 *
 * 

This implementation is a simplified version adapted from * * OpenHFT/Zero-Allocation-Hashing. */ final class XxHash64 { static final XxHash64 INSTANCE = new XxHash64(0); // Primes if treated as unsigned private static final long P1 = -7046029288634856825L; private static final long P2 = -4417276706812531889L; private static final long P3 = 1609587929392839161L; private static final long P4 = -8796714831421723037L; private static final long P5 = 2870177450012600261L; private static final ByteOrder byteOrder = ByteOrder.nativeOrder(); private final long seed; private final long voidHash; XxHash64(long seed) { this.seed = seed; this.voidHash = finalize(seed + P5); } long hashLong(long input) { input = byteOrder == ByteOrder.LITTLE_ENDIAN ? input : Long.reverseBytes(input); long hash = seed + P5 + 8; input *= P2; input = Long.rotateLeft(input, 31); input *= P1; hash ^= input; hash = Long.rotateLeft(hash, 27) * P1 + P4; return finalize(hash); } long hashInt(int input) { input = byteOrder == ByteOrder.LITTLE_ENDIAN ? input : Integer.reverseBytes(input); long hash = seed + P5 + 4; hash ^= (input & 0xFFFFFFFFL) * P1; hash = Long.rotateLeft(hash, 23) * P2 + P3; return finalize(hash); } long hashShort(short input) { input = byteOrder == ByteOrder.LITTLE_ENDIAN ? input : Short.reverseBytes(input); long hash = seed + P5 + 2; hash ^= (input & 0xFFL) * P5; hash = Long.rotateLeft(hash, 11) * P1; hash ^= ((input >> 8) & 0xFFL) * P5; hash = Long.rotateLeft(hash, 11) * P1; return finalize(hash); } long hashChar(char input) { return hashShort((short) input); } long hashByte(byte input) { long hash = seed + P5 + 1; hash ^= (input & 0xFF) * P5; hash = Long.rotateLeft(hash, 11) * P1; return finalize(hash); } long hashVoid() { return voidHash; } long hashAsciiString(String input) { ByteSupplier supplier = new AsciiStringByteSupplier(input); return hashBytes(supplier); } long hashBytes(byte[] bytes) { ByteSupplier supplier = new PlainByteSupplier(bytes); return hashBytes(supplier); } long hashBytes(byte[] bytes, int offset, int len) { ByteSupplier supplier = new PlainByteSupplier(bytes, offset, len); return hashBytes(supplier); } private long hashBytes(ByteSupplier supplier) { long hash; if (supplier.remaining() >= 32) { long v1 = seed + P1 + P2; long v2 = seed + P2; long v3 = seed; long v4 = seed - P1; do { v1 += supplier.next64() * P2; v1 = Long.rotateLeft(v1, 31); v1 *= P1; v2 += supplier.next64() * P2; v2 = Long.rotateLeft(v2, 31); v2 *= P1; v3 += supplier.next64() * P2; v3 = Long.rotateLeft(v3, 31); v3 *= P1; v4 += supplier.next64() * P2; v4 = Long.rotateLeft(v4, 31); v4 *= P1; } while (supplier.remaining() >= 32); hash = Long.rotateLeft(v1, 1) + Long.rotateLeft(v2, 7) + Long.rotateLeft(v3, 12) + Long.rotateLeft(v4, 18); v1 *= P2; v1 = Long.rotateLeft(v1, 31); v1 *= P1; hash ^= v1; hash = (hash * P1) + P4; v2 *= P2; v2 = Long.rotateLeft(v2, 31); v2 *= P1; hash ^= v2; hash = (hash * P1) + P4; v3 *= P2; v3 = Long.rotateLeft(v3, 31); v3 *= P1; hash ^= v3; hash = (hash * P1) + P4; v4 *= P2; v4 = Long.rotateLeft(v4, 31); v4 *= P1; hash ^= v4; hash = (hash * P1) + P4; } else { hash = seed + P5; } hash += supplier.bytes(); while (supplier.remaining() >= 8) { long k1 = supplier.next64(); k1 *= P2; k1 = Long.rotateLeft(k1, 31); k1 *= P1; hash ^= k1; hash = (Long.rotateLeft(hash, 27) * P1) + P4; } if (supplier.remaining() >= 4) { //treat as unsigned ints hash ^= (supplier.next32() & 0xFFFFFFFFL) * P1; hash = (Long.rotateLeft(hash, 23) * P2) + P3; } while (supplier.remaining() != 0) { //treat as unsigned bytes hash ^= (supplier.next8() & 0xFF) * P5; hash = Long.rotateLeft(hash, 11) * P1; } return finalize(hash); } private static long finalize(long hash) { hash ^= hash >>> 33; hash *= P2; hash ^= hash >>> 29; hash *= P3; hash ^= hash >>> 32; return hash; } private static class PlainByteSupplier extends ByteSupplier { private final byte[] src; private final int len; private int pos; private int remain; private PlainByteSupplier(byte[] src) { this(src, 0, src.length); } private PlainByteSupplier(byte[] src, int offset, int len) { this.src = checkNotNull(src, "src"); checkArgument(offset <= src.length, "offset > src length"); checkArgument(offset + len <= src.length, "offset + len > src length"); this.len = len; pos = offset; remain = len; } @Override public long bytes() { return len; } @Override public long remaining() { return remain; } @Override public byte next8() { remain--; return src[pos++]; } } private static class AsciiStringByteSupplier extends ByteSupplier { private final String str; private final int bytes; private int pos; private AsciiStringByteSupplier(String str) { this.str = checkNotNull(str, "str"); this.bytes = str.length(); } @Override public long bytes() { return bytes; } @Override public long remaining() { return (long) bytes - pos; } @Override public byte next8() { return (byte) str.charAt(pos++); } } private abstract static class ByteSupplier { public long next64() { return ((next32() & 0xFFFFFFFFL) | ((next32() & 0xFFFFFFFFL) << 32)); } public int next32() { return ((next16() & 0xFFFF) | ((next16() & 0xFFFF) << 16)); } char next16() { return (char) ((next8() & 0xFF) | ((next8() & 0xFF) << 8)); } abstract byte next8(); abstract long bytes(); abstract long remaining(); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy