package com.towel.util;
/**
* Build a HASH value based on the added values. If none value is added,
* DEFAULT_BASE is the hash returned in getHash() method.
* <p>
* The calculation used is proposed by Joshua Block in Effective Java p. 38
* <p>
* Above there's a sample of how to use hashBuilder:
*
* <pre>
* public class Person {
* private String name;
* private int age;
*
* public Person(String name, int age) {
* this.name = name;
* this.age = age;
* }
*
* public int getAge() {
* return age;
* }
*
* public int getName() {
* return name;
* }
*
* public int hashCode() {
* return new HashBuilder(name).add(age).hashCode();
* }
* }
* </pre>
*/
public class HashBuilder {
public static final int DEFAULT_BASE = 17;
public static final int DEFAULT_SEED = 37;
private int seed;
private int base;
private int result;
public HashBuilder() {
this(DEFAULT_BASE, DEFAULT_SEED);
}
public HashBuilder(int firstValue) {
this();
add(firstValue);
}
public HashBuilder(long firstValue) {
this();
add(firstValue);
}
public HashBuilder(char firstValue) {
this();
add(firstValue);
}
public HashBuilder(boolean firstValue) {
this();
add(firstValue);
}
public HashBuilder(float firstValue) {
this();
add(firstValue);
}
public HashBuilder(double firstValue) {
this();
add(firstValue);
}
public HashBuilder(Object firstValue) {
this();
add(firstValue);
}
public HashBuilder(int base, int seed) {
if (base < 3)
throw new IllegalArgumentException("Base must be bigger than 2!");
if (seed < 3)
throw new IllegalArgumentException("Seed must be bigger than 2!");
this.seed = seed;
this.base = base;
result = base;
}
public void reset() {
result = base;
}
public HashBuilder add(int value) {
result = seed * result + value;
return this;
}
public HashBuilder add(char value) {
return add((short) value);
}
public HashBuilder add(long value) {
return add((int) (value ^ (value >>> 32)));
}
public HashBuilder add(boolean value) {
return add(value ? 1 : 0);
}
public HashBuilder add(float value) {
return add(Float.floatToIntBits(value));
}
public HashBuilder add(double value) {
return add(Double.doubleToLongBits(value));
}
public HashBuilder add(Object value) {
return add(value == null ? 0 : value.hashCode());
}
public HashBuilder add(byte[] value) {
for (byte b : value)
add(b);
return this;
}
public HashBuilder add(short[] value) {
for (short s : value)
add(s);
return this;
}
public HashBuilder add(int[] value) {
for (int i : value)
add(i);
return this;
}
public HashBuilder add(char[] value) {
for (char c : value)
add(c);
return this;
}
public HashBuilder add(long[] value) {
for (long l : value)
add(l);
return this;
}
public HashBuilder add(boolean[] value) {
for (boolean b : value)
add(b);
return this;
}
public HashBuilder add(float[] value) {
for (float f : value)
add(f);
return this;
}
public HashBuilder add(double[] value) {
for (double d : value)
add(d);
return this;
}
public HashBuilder add(Object[] value) {
for (Object o : value)
add(o);
return this;
}
@Override
public boolean equals(Object value) {
if (value == this)
return true;
if (!(value instanceof HashBuilder))
return false;
HashBuilder other = (HashBuilder) value;
return other.result == result && other.base == base
&& other.seed == seed;
}
@Override
public int hashCode() {
return result;
}
}