/*
* JBoss, Home of Professional Open Source.
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership. Some portions may be licensed
* to Red Hat, Inc. under one or more contributor license agreements.
*
* This library 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 2.1 of the License, or (at your option) any later version.
*
* This library 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 library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA.
*/
package org.teiid.core.util;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.RandomAccess;
/**
* <P>This class provides utility functions for generating good
* hash codes. Hash codes generated with these methods should
* have a reasonably good distribution when placed in a hash
* structure such as Hashtable, HashSet, or HashMap.</P>
*
* <P>General usage is something like:</P>
* <PRE>
* public int hashCode() {
* int hc = 0; // or = super.hashCode();
* hc = HashCodeUtil.hashCode(hc, intField);
* hc = HashCodeUtil.hashCode(hc, objectField);
* // etc, etc
* return hc;
* }
* </PRE>
*/
public final class HashCodeUtil {
// Prime number used in improving distribution: 1,000,003
private static final int PRIME = 1000003;
public static final int hashCode(int previous, boolean x) {
return (PRIME*previous) + (x ? 1 : 0);
}
public static final int hashCode(int previous, int x) {
return (PRIME*previous) + x;
}
public static final int hashCode(int previous, long x) {
// convert to two ints
return (PRIME*previous) +
(int) (PRIME*(x >>> 32) + (x & 0xFFFFFFFF));
}
public static final int hashCode(int previous, float x) {
return hashCode(previous, (x == 0.0F) ? 0 : Float.floatToIntBits(x));
}
public static final int hashCode(int previous, double x) {
// convert to long
return hashCode(previous, (x == 0.0) ? 0L : Double.doubleToLongBits(x));
}
public static final int hashCode(int previous, Object... x) {
if(x == null) {
return PRIME*previous;
}
int hc = previous;
for(int i=0; i<x.length; i++) {
hc = (x[i] == null) ? (PRIME*hc) : (PRIME*hc) + x[i].hashCode();
}
return hc;
}
/**
* Compute a hash code on a large array by walking the list
* and combining the hash code at every exponential index:
* 1, 2, 4, 8, ... This has been shown to give a good hash
* for good time complexity.
*/
public static final int expHashCode(int previous, Object[] x) {
if(x == null) {
return PRIME*previous;
}
int hc = (PRIME*previous) + x.length;
int index = 1;
int xlen = x.length+1; // switch to 1-based
while(index < xlen) {
hc = hashCode(hc, x[index-1]);
index = index << 1; // left shift by 1 to double
}
return hc;
}
/**
* Compute a hash code on a large collection by walking the list
* and combining the hash code at every exponential index:
* 1, 2, 4, 8, ... This has been shown to give a good hash
* for good time complexity.
*/
public static final int expHashCode(int previous, Collection<?> x) {
if(x == null || x.size() == 0) {
return PRIME*previous;
}
int size = x.size(); // size of collection
int hc = (PRIME*previous) + size; // hash code so far
if (x instanceof RandomAccess && x instanceof List<?>) {
List<?> l = List.class.cast(x);
int index = 1;
int xlen = x.size()+1; // switch to 1-based
while(index < xlen) {
hc = hashCode(hc, l.get(index-1));
index = index << 1; // left shift by 1 to double
}
} else {
int skip = 0; // skip between samples
int total = 0; // collection examined already
Iterator<?> iter = x.iterator(); // collection iterator
Object obj = iter.next(); // last iterated object, primed at first
while(total < size) {
for(int i=0; i<skip; i++) { // skip to next sample
obj = iter.next();
}
hc = hashCode(hc, obj); // add sample to hashcode
skip = (skip == 0) ? 1 : skip << 1; // left shift by 1 to double
total += skip; // update total
}
}
return hc;
}
public static final int expHashCode(CharSequence x) {
return expHashCode(x, true);
}
public static final int expHashCode(CharSequence x, boolean caseSensitive) {
if(x == null) {
return 0;
}
int hc = x.length();
int index = 1;
int xlen = x.length()+1; // switch to 1-based
while(index < xlen) {
int charHash = x.charAt(index-1);
if (!caseSensitive) {
charHash = Character.toUpperCase(charHash);
}
hc = PRIME * hc + charHash;
index = index << 1; // left shift by 1 to double
}
return hc;
}
}