/*
* Copyright (C) 2012-2013 University of Freiburg
*
* This file is part of SMTInterpol.
*
* SMTInterpol 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, or
* (at your option) any later version.
*
* SMTInterpol 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 SMTInterpol. If not, see .
*/
package de.uni_freiburg.informatik.ultimate.util;
/**
* This implements Jenkins und Hsieh hash functions. It is based on the code at
* http://www.burtleburtle.net/bob/c/lookup3.c.
*
*
* @author Jürgen Christ, Jochen Hoenicke
*
*/
public final class HashUtils {
private final static int BASE = 0xdeadbeef;
private HashUtils() {
// Hide constructor
}
public static int hashJenkins(final int init, final byte[] vals) {
if (vals == null || vals.length == 0) {
return init;
}
int a,b,c;
a = b = c = BASE + (vals.length << 2) + init;
int pos = 0;
while (vals.length - pos > 12) {
a += (vals[pos] & 0xff) + ((vals[pos + 1] & 0xff) << 8) + ((vals[pos + 2] & 0xff) << 16)
+ ((vals[pos + 3] & 0xff) << 24);
b += (vals[pos + 4] & 0xff) + ((vals[pos + 5] & 0xff) << 8) + ((vals[pos + 6] & 0xff) << 16)
+ ((vals[pos + 7] & 0xff) << 24);
c += (vals[pos + 8] & 0xff) + ((vals[pos + 9] & 0xff) << 8) + ((vals[pos + 10] & 0xff) << 16)
+ ((vals[pos + 11] & 0xff) << 24);
// This is the mix function of Jenkins hash.
// Note that we need >>> for unsigned shift.
// rot(c,4) is ((c << 4) | (c >>> 28)).
a -= c;
a ^= ((c << 4) | (c >>> 28));
c += b;
b -= a;
b ^= ((a << 6) | (a >>> 26));
a += c;
c -= b;
c ^= ((b << 8) | (b >>> 24));
b += a;
a -= c;
a ^= ((c << 16) | (c >>> 16));
c += b;
b -= a;
b ^= ((a << 19) | (a >>> 13));
a += c;
c -= b;
c ^= ((b << 4) | (b >>> 28));
b += a;
pos += 3;
}
switch (vals.length - pos) {
case 12:
c += (vals[pos + 11] & 0xff) << 24;
//$FALL-THROUGH$
case 11:
c += (vals[pos + 10] & 0xff) << 16;
//$FALL-THROUGH$
case 10:
c += (vals[pos + 9] & 0xff) << 8;
//$FALL-THROUGH$
case 9:
c += (vals[pos + 8] & 0xff);
//$FALL-THROUGH$
case 8:
b += (vals[pos + 7] & 0xff) << 24;
//$FALL-THROUGH$
case 7:
b += (vals[pos + 6] & 0xff) << 16;
//$FALL-THROUGH$
case 6:
b += (vals[pos + 5] & 0xff) << 8;
//$FALL-THROUGH$
case 5:
b += (vals[pos + 4] & 0xff);
//$FALL-THROUGH$
case 4:
a += (vals[pos + 3] & 0xff) << 24;
//$FALL-THROUGH$
case 3:
a += (vals[pos + 2] & 0xff) << 16;
//$FALL-THROUGH$
case 2:
a += (vals[pos + 1] & 0xff) << 8;
//$FALL-THROUGH$
case 1:
a += (vals[pos] & 0xff);
// This is the final mix function of Jenkins hash.
c ^= b;
c -= ((b << 14) | (b >>> 18));
a ^= c;
a -= ((c << 11) | (c >>> 21));
b ^= a;
b -= ((a << 25) | (a >>> 7));
c ^= b;
c -= ((b << 16) | (b >>> 16));
a ^= c;
a -= ((c << 4) | (c >>> 28));
b ^= a;
b -= ((a << 14) | (a >>> 18));
c ^= b;
c -= ((b << 24) | (b >>> 8));
//$FALL-THROUGH$
case 0:
//$FALL-THROUGH$
default:
break;
}
return c;
}
public static int hashJenkins(final int init, final Object... vals) {
if (vals == null || vals.length == 0) {
return init;
}
int a,b,c;
a = b = c = BASE + (vals.length << 2) + init;
int pos = 0;
while (vals.length - pos > 3) {
a += vals[pos].hashCode();
b += vals[pos + 1].hashCode();
c += vals[pos + 2].hashCode();
// This is the mix function of Jenkins hash.
// Note that we need >>> for unsigned shift.
// rot(c,4) is ((c << 4) | (c >>> 28)).
a -= c;
a ^= ((c << 4) | (c >>> 28));
c += b;
b -= a;
b ^= ((a << 6) | (a >>> 26));
a += c;
c -= b;
c ^= ((b << 8) | (b >>> 24));
b += a;
a -= c;
a ^= ((c << 16) | (c >>> 16));
c += b;
b -= a;
b ^= ((a << 19) | (a >>> 13));
a += c;
c -= b;
c ^= ((b << 4) | (b >>> 28));
b += a;
pos += 3;
}
switch (vals.length - pos) {
case 3:
c += vals[pos++].hashCode();
// fallthrough
case 2:
b += vals[pos++].hashCode();
// fallthrough
case 1:
a += vals[pos].hashCode();
// This is the final mix function of Jenkins hash.
c ^= b;
c -= ((b << 14) | (b >>> 18));
a ^= c;
a -= ((c << 11) | (c >>> 21));
b ^= a;
b -= ((a << 25) | (a >>> 7));
c ^= b;
c -= ((b << 16) | (b >>> 16));
a ^= c;
a -= ((c << 4) | (c >>> 28));
b ^= a;
b -= ((a << 14) | (a >>> 18));
c ^= b;
c -= ((b << 24) | (b >>> 8));
// fallthrough
case 0:
// fallthrough
default:
break;
}
return c;
}
public static int hashJenkins(final int init, final Object val) {
int a,b,c;
a = b = BASE + 4 + init;
// slightly optimized version of hashJenkins(init, new Object[] {val})
a += val.hashCode();
c = -((b << 14) | (b >>> 18));
a ^= c;
a -= ((c << 11) | (c >>> 21));
b ^= a;
b -= ((a << 25) | (a >>> 7));
c ^= b;
c -= ((b << 16) | (b >>> 16));
a ^= c;
a -= ((c << 4) | (c >>> 28));
b ^= a;
b -= ((a << 14) | (a >>> 18));
c ^= b;
c -= ((b << 24) | (b >>> 8));
return c;
}
public static int hashHsieh(final int init, final Object... vals) {
if (vals == null || vals.length == 0) {
return init;
}
int hash = init;
/* Main loop */
for (final Object o : vals) {
final int thingHash = o.hashCode();
hash += (thingHash >>> 16);
final int tmp = ((thingHash & 0xffff) << 11) ^ hash;
hash = (hash << 16) ^ tmp;
hash += (hash >>> 11);
}
/* Force "avalanching" of final 127 bits */
hash ^= hash << 3;
hash += hash >>> 5;
hash ^= hash << 4;
hash += hash >>> 17;
hash ^= hash << 25;
hash += hash >>> 6;
return hash;
}
public static int hashHsieh(final int init, final Object val) {
int hash = init;
final int thingHash = val.hashCode();
hash += (thingHash >>> 16);
final int tmp = ((thingHash & 0xffff) << 11) ^ hash;
hash = (hash << 16) ^ tmp;
hash += (hash >>> 11);
/* Force "avalanching" of final 127 bits */
hash ^= hash << 3;
hash += hash >>> 5;
hash ^= hash << 4;
hash += hash >>> 17;
hash ^= hash << 25;
hash += hash >>> 6;
return hash;
}
}