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

net.openhft.chronicle.hash.hashing.Hasher Maven / Gradle / Ivy

/*
 *     Copyright (C) 2015  higherfrequencytrading.com
 *
 *     This program is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU Lesser General Public License as published by
 *     the Free Software Foundation, either version 3 of the License.
 *
 *     This program is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU Lesser General Public License for more details.
 *
 *     You should have received a copy of the GNU Lesser General Public License
 *     along with this program.  If not, see .
 */

package net.openhft.chronicle.hash.hashing;

import net.openhft.lang.io.Bytes;

import static net.openhft.chronicle.hash.hashing.UnsafeAccess.BYTE_BASE;
import static net.openhft.chronicle.hash.hashing.UnsafeAccess.CHAR_BASE;

public final class Hasher {

    // MurmurHash3, derived from
    // https://github.com/google/guava/blob/fa95e381e665d8ee9639543b99ed38020c8de5ef
    // /guava/src/com/google/common/hash/Murmur3_128HashFunction.java

    private static final long C1 = 0x87c37b91114253d5L;
    private static final long C2 = 0x4cf5ad432745937fL;

    private Hasher() {
    }

    /**
     * Returns the hash code for {@code len} continuous bytes of the given {@code input} object,
     * starting from the given offset. The abstraction of input as ordered byte sequence and
     * "offset within the input" is defined by the given {@code access} strategy.
     * 

*

This method doesn't promise to throw a {@code RuntimeException} if {@code * [off, off + len - 1]} subsequence exceeds the bounds of the bytes sequence, defined by {@code * access} strategy for the given {@code input}, so use this method with caution. * * @param input the object to read bytes from * @param access access which defines the abstraction of the given input * as ordered byte sequence * @param offset offset to the first byte of the subsequence to hash * @param length length of the subsequence to hash * @param the type of the input * @return hash code for the specified bytes subsequence */ public static long hash(T input, Access access, long offset, long length) { assert offset >= 0L && length >= 0L; long h1 = 0L; long h2 = 0L; long remaining = length; while (remaining >= 16L) { long k1 = access.getLong(input, offset); long k2 = access.getLong(input, offset + 8L); offset += 16L; remaining -= 16L; h1 ^= mixK1(k1); h1 = Long.rotateLeft(h1, 27); h1 += h2; h1 = h1 * 5L + 0x52dce729L; h2 ^= mixK2(k2); h2 = Long.rotateLeft(h2, 31); h2 += h1; h2 = h2 * 5L + 0x38495ab5L; } if (remaining > 0L) { long k1 = 0L; long k2 = 0L; switch ((int) remaining) { case 15: k2 ^= ((long) access.getUnsignedByte(input, offset + 14L)) << 48;// fall through case 14: k2 ^= ((long) access.getUnsignedByte(input, offset + 13L)) << 40;// fall through case 13: k2 ^= ((long) access.getUnsignedByte(input, offset + 12L)) << 32;// fall through case 12: k2 ^= ((long) access.getUnsignedByte(input, offset + 11L)) << 24;// fall through case 11: k2 ^= ((long) access.getUnsignedByte(input, offset + 10L)) << 16;// fall through case 10: k2 ^= ((long) access.getUnsignedByte(input, offset + 9L)) << 8; // fall through case 9: k2 ^= ((long) access.getUnsignedByte(input, offset + 8L)); // fall through case 8: k1 ^= access.getLong(input, offset); break; case 7: k1 ^= ((long) access.getUnsignedByte(input, offset + 6L)) << 48; // fall through case 6: k1 ^= ((long) access.getUnsignedByte(input, offset + 5L)) << 40; // fall through case 5: k1 ^= ((long) access.getUnsignedByte(input, offset + 4L)) << 32; // fall through case 4: k1 ^= access.getUnsignedInt(input, offset); break; case 3: k1 ^= ((long) access.getUnsignedByte(input, offset + 2L)) << 16; // fall through case 2: k1 ^= ((long) access.getUnsignedByte(input, offset + 1L)) << 8; // fall through case 1: k1 ^= ((long) access.getUnsignedByte(input, offset)); case 0: break; default: throw new AssertionError("Should never get here."); } h1 ^= mixK1(k1); h2 ^= mixK2(k2); } return finalize(length, h1, h2); } private static long finalize(long length, long h1, long h2) { h1 ^= length; h2 ^= length; h1 += h2; h2 += h1; h1 = fmix64(h1); h2 = fmix64(h2); h1 += h2; return h1; } private static long fmix64(long k) { k ^= k >>> 33; k *= 0xff51afd7ed558ccdL; k ^= k >>> 33; k *= 0xc4ceb9fe1a85ec53L; k ^= k >>> 33; return k; } private static long mixK1(long k1) { k1 *= C1; k1 = Long.rotateLeft(k1, 31); k1 *= C2; return k1; } private static long mixK2(long k2) { k2 *= C2; k2 = Long.rotateLeft(k2, 33); k2 *= C1; return k2; } public static long hash(Bytes bytes) { return hash(bytes, bytes.position(), bytes.limit()); } public static long hash(Bytes bytes, long offset, long limit) { return hash(bytes, Accesses.toBytes(), offset, limit - offset); } public static long hash(byte[] array) { return hash(array, Accesses.unsafe(), BYTE_BASE, (long) array.length); } public static long hash(char[] array) { return hash(array, Accesses.unsafe(), CHAR_BASE, array.length * 2L); } public static long hash(int value) { long k1 = Primitives.unsignedInt(value); long h1 = 0L ^ mixK1(k1); long h2 = 0L; return finalize(4L, h1, h2); } public static long hash(long value) { long k1 = value; long h1 = 0L ^ mixK1(k1); long h2 = 0L; return finalize(8L, h1, h2); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy