| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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. |
| */ |
| package org.apache.drill.exec.expr.fn.impl; |
| |
| import io.netty.buffer.DrillBuf; |
| import io.netty.util.internal.PlatformDependent; |
| |
| |
| /** |
| * |
| * MurmurHash3 was written by Austin Appleby, and is placed in the public |
| * domain. |
| * See http://smhasher.googlecode.com/svn/trunk/MurmurHash3.cpp |
| * MurmurHash3_x64_128 |
| * MurmurHash3_x86_32 |
| */ |
| public final class MurmurHash3 extends DrillHash{ |
| |
| public static final long fmix64(long k) { |
| k ^= k >>> 33; |
| k *= 0xff51afd7ed558ccdL; |
| k ^= k >>> 33; |
| k *= 0xc4ceb9fe1a85ec53L; |
| k ^= k >>> 33; |
| return k; |
| } |
| |
| /* |
| Take 64 bit of murmur3_128's output |
| */ |
| public static long murmur3_64(long bStart, long bEnd, DrillBuf buffer, int seed) { |
| |
| long h1 = seed & 0x00000000FFFFFFFFL; |
| long h2 = seed & 0x00000000FFFFFFFFL; |
| |
| final long c1 = 0x87c37b91114253d5L; |
| final long c2 = 0x4cf5ad432745937fL; |
| long start = buffer.memoryAddress() + bStart; |
| long end = buffer.memoryAddress() + bEnd; |
| long length = bEnd - bStart; |
| long roundedEnd = start + ( length & 0xFFFFFFF0); // round down to 16 byte block |
| for (long i=start; i<roundedEnd; i+=16) { |
| long k1 = getLongLittleEndian(i); |
| long k2 = getLongLittleEndian(i+8); |
| k1 *= c1; |
| k1 = Long.rotateLeft(k1,31); |
| k1 *= c2; |
| h1 ^= k1; |
| h1 = Long.rotateLeft(h1,27); |
| h1 += h2; |
| h1 = h1*5+0x52dce729; |
| k2 *= c2; |
| k2 = Long.rotateLeft(k2,33); |
| k2 *= c1; |
| h2 ^= k2; |
| h2 = Long.rotateLeft(h2,31); |
| h2 += h1; |
| h2 = h2*5+0x38495ab5; |
| } |
| |
| long k1 = 0; |
| long k2 = 0; |
| |
| // tail |
| switch ((int)length & 15) { |
| case 15: k2 = (PlatformDependent.getByte(roundedEnd+14) & 0xffL) << 48; |
| case 14: k2 ^= (PlatformDependent.getByte(roundedEnd+13) & 0xffL) << 40; |
| case 13: k2 ^= (PlatformDependent.getByte(roundedEnd+12) & 0xffL) << 32; |
| case 12: k2 ^= (PlatformDependent.getByte(roundedEnd+11) & 0xffL) << 24; |
| case 11: k2 ^= (PlatformDependent.getByte(roundedEnd+10) & 0xffL) << 16; |
| case 10: k2 ^= (PlatformDependent.getByte(roundedEnd+ 9) & 0xffL) << 8; |
| case 9: k2 ^= (PlatformDependent.getByte(roundedEnd+ 8) & 0xffL); |
| k2 *= c2; |
| k2 = Long.rotateLeft(k2, 33); |
| k2 *= c1; |
| h2 ^= k2; |
| case 8: k1 = (long)PlatformDependent.getByte(roundedEnd+7) << 56; |
| case 7: k1 ^= (PlatformDependent.getByte(roundedEnd+6) & 0xffL) << 48; |
| case 6: k1 ^= (PlatformDependent.getByte(roundedEnd+5) & 0xffL) << 40; |
| case 5: k1 ^= (PlatformDependent.getByte(roundedEnd+4) & 0xffL) << 32; |
| case 4: k1 ^= (PlatformDependent.getByte(roundedEnd+3) & 0xffL) << 24; |
| case 3: k1 ^= (PlatformDependent.getByte(roundedEnd+2) & 0xffL) << 16; |
| case 2: k1 ^= (PlatformDependent.getByte(roundedEnd+1) & 0xffL) << 8; |
| case 1: k1 ^= (PlatformDependent.getByte(roundedEnd ) & 0xffL); |
| k1 *= c1; |
| k1 = Long.rotateLeft(k1,31); |
| k1 *= c2; |
| h1 ^= k1; |
| } |
| |
| h1 ^= length; |
| h2 ^= length; |
| |
| h1 += h2; |
| h2 += h1; |
| |
| h1 = fmix64(h1); |
| h2 = fmix64(h2); |
| |
| h1 += h2; |
| h2 += h1; |
| // murmur3_128 should return 128 bit (h1,h2), now we return only 64bits, |
| return h1; |
| } |
| |
| public static long murmur3_64(long val, int seed) { |
| |
| long h1 = seed & 0x00000000FFFFFFFFL; |
| long h2 = seed & 0x00000000FFFFFFFFL; |
| |
| final long c1 = 0x87c37b91114253d5L; |
| final long c2 = 0x4cf5ad432745937fL; |
| |
| int length = 8; |
| long k1 = 0; |
| |
| k1 = val; |
| k1 *= c1; |
| k1 = Long.rotateLeft(k1,31); |
| k1 *= c2; |
| h1 ^= k1; |
| |
| h1 ^= length; |
| h2 ^= length; |
| |
| h1 += h2; |
| h2 += h1; |
| |
| h1 = fmix64(h1); |
| h2 = fmix64(h2); |
| |
| h1 += h2; |
| |
| //h2 += h1; |
| // murmur3_128 should return 128 bit (h1,h2), now we return only 64bits, |
| return h1; |
| |
| } |
| |
| public static int murmur3_32(int bStart, int bEnd, DrillBuf buffer, int seed) { |
| |
| final long c1 = 0xcc9e2d51L; |
| final long c2 = 0x1b873593L; |
| long start = buffer.memoryAddress() + bStart; |
| long length = bEnd - bStart; |
| long UINT_MASK=0xffffffffL; |
| long lh1 = seed; |
| long roundedEnd = start + (length & 0xfffffffc); // round down to 4 byte block |
| |
| for (long i=start; i<roundedEnd; i+=4) { |
| // little endian load order |
| long lk1 = (PlatformDependent.getByte(i) & 0xff) | ((PlatformDependent.getByte(i+1) & 0xff) << 8) | |
| ((PlatformDependent.getByte(i+2) & 0xff) << 16) | (PlatformDependent.getByte(i+3) << 24); |
| |
| //k1 *= c1; |
| lk1 *= c1; |
| lk1 &= UINT_MASK; |
| |
| lk1 = ((lk1 << 15) & UINT_MASK) | (lk1 >>> 17); |
| |
| lk1 *= c2; |
| lk1 = lk1 & UINT_MASK; |
| lh1 ^= lk1; |
| lh1 = ((lh1 << 13) & UINT_MASK) | (lh1 >>> 19); |
| |
| lh1 = lh1*5+0xe6546b64L; |
| lh1 = UINT_MASK & lh1; |
| } |
| |
| // tail |
| long lk1 = 0; |
| |
| switch((byte)length & 0x03) { |
| case 3: |
| lk1 = (PlatformDependent.getByte(roundedEnd + 2) & 0xff) << 16; |
| case 2: |
| lk1 |= (PlatformDependent.getByte(roundedEnd + 1) & 0xff) << 8; |
| case 1: |
| lk1 |= (PlatformDependent.getByte(roundedEnd) & 0xff); |
| lk1 *= c1; |
| lk1 = UINT_MASK & lk1; |
| lk1 = ((lk1 << 15) & UINT_MASK) | (lk1 >>> 17); |
| |
| lk1 *= c2; |
| lk1 = lk1 & UINT_MASK; |
| |
| lh1 ^= lk1; |
| } |
| |
| // finalization |
| lh1 ^= length; |
| |
| lh1 ^= lh1 >>> 16; |
| lh1 *= 0x85ebca6b; |
| lh1 = UINT_MASK & lh1; |
| lh1 ^= lh1 >>> 13; |
| |
| lh1 *= 0xc2b2ae35; |
| lh1 = UINT_MASK & lh1; |
| lh1 ^= lh1 >>> 16; |
| |
| return (int)(lh1 & UINT_MASK); |
| } |
| |
| public static int murmur3_32(long val, int seed) { |
| final long c1 = 0xcc9e2d51L; |
| final long c2 = 0x1b873593; |
| long length = 8; |
| long UINT_MASK=0xffffffffL; |
| long lh1 = seed & UINT_MASK; |
| for (int i=0; i<2; i++) { |
| //int ik1 = (int)((val >> i*32) & UINT_MASK); |
| long lk1 = ((val >> i*32) & UINT_MASK); |
| |
| //k1 *= c1; |
| lk1 *= c1; |
| lk1 &= UINT_MASK; |
| |
| lk1 = ((lk1 << 15) & UINT_MASK) | (lk1 >>> 17); |
| |
| lk1 *= c2; |
| lk1 &= UINT_MASK; |
| |
| lh1 ^= lk1; |
| lh1 = ((lh1 << 13) & UINT_MASK) | (lh1 >>> 19); |
| |
| lh1 = lh1*5+0xe6546b64L; |
| lh1 = UINT_MASK & lh1; |
| } |
| // finalization |
| lh1 ^= length; |
| |
| lh1 ^= lh1 >>> 16; |
| lh1 *= 0x85ebca6bL; |
| lh1 = UINT_MASK & lh1; |
| lh1 ^= lh1 >>> 13; |
| lh1 *= 0xc2b2ae35L; |
| lh1 = UINT_MASK & lh1; |
| lh1 ^= lh1 >>> 16; |
| |
| return (int)lh1; |
| } |
| |
| public static long hash64(double val, long seed) { |
| return murmur3_64(Double.doubleToLongBits(val), (int) seed); |
| } |
| |
| public static long hash64(long start, long end, DrillBuf buffer, long seed) { |
| return murmur3_64(start, end, buffer, (int) seed); |
| } |
| |
| public static int hash32(double val, long seed) { |
| return murmur3_32(Double.doubleToLongBits(val), (int) seed); |
| } |
| |
| public static int hash32(int start, int end, DrillBuf buffer, int seed) { |
| return murmur3_32(start, end, buffer, seed); |
| } |
| |
| } |
| |