package de.axone.equals;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public abstract class AbstractStrongHashCodeBuilder<T> implements StrongHashCodeBuilder<T> {
private static final byte TRUE = 73;
private static final byte FALSE = 117;
@Override
public StrongHashCodeBuilder<T> append( boolean v ) {
return append( new byte[]{ v ? TRUE : FALSE } );
}
@Override
public StrongHashCodeBuilder<T> append( byte v ) {
return append( new byte[]{ v } );
}
@Override
public StrongHashCodeBuilder<T> append( char v ) {
return append( new byte[]{ (byte)(v>>8), (byte)(v&0xff) } );
}
@Override
public StrongHashCodeBuilder<T> append( short v ) {
return append( new byte[]{ (byte)((v&0xff00)>>8), (byte)(v&0xff) } );
}
@Override
public StrongHashCodeBuilder<T> append( int v ) {
return append( new byte[]{
(byte)(((v&(0xff<<24))>>24)&0xff), (byte)((v&(0xff<<16))>>16),
(byte)((v&(0xff<<8))>>8), (byte)(v&0xff)
} );
}
@Override
public StrongHashCodeBuilder<T> append( long v ) {
return append( new byte[]{
(byte)(((v&(0xffL<<56))>>56)&0xff), (byte)((v&(0xffL<<48))>>48),
(byte)((v&(0xffL<<40))>>40), (byte)((v&(0xffL<<32))>>32),
(byte)((v&(0xffL<<24))>>24), (byte)((v&(0xffL<<16))>>16),
(byte)((v&(0xffL<<8))>>8), (byte)(v&0xffL)
} );
}
@Override
public StrongHashCodeBuilder<T> append( float v ) {
return append( Float.floatToIntBits( v ) );
}
@Override
public StrongHashCodeBuilder<T> append( double v ) {
return append( Double.doubleToLongBits( v ) );
}
@Override
public StrongHashCodeBuilder<T> append( boolean[] a ) {
if( a == null ) appendNull();
else if( a.length == 0 ) appendEmpty();
else for( boolean v : a ) append( v );
return this;
}
@Override
public StrongHashCodeBuilder<T> append( char[] a ) {
if( a == null ) appendNull();
else if( a.length == 0 ) appendEmpty();
else for( char v : a ) append( v );
return this;
}
@Override
public StrongHashCodeBuilder<T> append( short[] a ) {
if( a == null ) appendNull();
else if( a.length == 0 ) appendEmpty();
else for( short v : a ) append( v );
return this;
}
@Override
public StrongHashCodeBuilder<T> append( int[] a ) {
if( a == null ) appendNull();
else if( a.length == 0 ) appendEmpty();
else for( int v : a ) append( v );
return this;
}
@Override
public StrongHashCodeBuilder<T> append( long[] a ) {
if( a == null ) appendNull();
else if( a.length == 0 ) appendEmpty();
else for( long v : a ) append( v );
return this;
}
@Override
public StrongHashCodeBuilder<T> append( float[] a ) {
if( a == null ) appendNull();
else if( a.length == 0 ) appendEmpty();
else for( float v : a ) append( v );
return this;
}
@Override
public StrongHashCodeBuilder<T> append( double[] a ) {
if( a == null ) appendNull();
else if( a.length == 0 ) appendEmpty();
else for( double v : a ) append( v );
return this;
}
@Override
public StrongHashCodeBuilder<T> append( String s ){
return append( s.toCharArray() );
}
protected StrongHashCodeBuilder<T> append( StrongPair p ){
append( p.a ); append( p.b );
return this;
}
@Override
public StrongHashCodeBuilder<T> append( Object o ) {
if( o == null ) appendNull();
else if( o instanceof Boolean ) append( (boolean)(Boolean)o );
else if( o instanceof Byte ) append( (byte)(Byte)o );
else if( o instanceof Character ) append( (char)(Character)o );
else if( o instanceof Short ) append( (short)(Short)o );
else if( o instanceof Integer ) append( (int)(Integer)o );
else if( o instanceof Long ) append( (long)(Long)o );
else if( o instanceof Float ) append( (float)(Float)o );
else if( o instanceof Double ) append( (double)(Double)o );
else if( o instanceof String ) append( (String)o );
else if( o instanceof StrongPair ) append( (StrongPair)o );
else if( o instanceof StrongHash ) append( ((StrongHash)o).strongHashCode() );
else if( o.getClass().isArray() ) append( (Object[])o );
else if( o instanceof Set ) append( (Set<?>)o );
else if( o instanceof Collection ) append( (Collection<?>)o );
else if( o instanceof Map ) append( (Map<?,?>)o );
// Special enum treatment to get it stable over vm-restarts.
else if( o instanceof Enum ) append( ((Enum<?>)o).name() );
// Special treatment for currency which has no hashcode method
// This leads to a somewhat changed behaviour since this is stable
// over program runs and calling hashcode isn't.
/* Moved to equals because is needed in normal hashcode, too
else if( o instanceof Currency ){
//E.rr( ((Currency)o).getCurrencyCode() );
append( ((Currency)o).getCurrencyCode() );
}
*/
else{
/*
if( o instanceof Currency ){
(new Throwable()).printStackTrace();
}
E.rr( o + ": (" + o.getClass().getSimpleName() + ")" + o.hashCode() );
*/
append( o.hashCode() ); // Fallback to normal hashcode if we can't do better
}
return this;
}
@Override
public StrongHashCodeBuilder<T> append( Object[] a ) {
if( a == null ) appendNull();
else for( Object v : a ) append( v );
return this;
}
// In Sets order doesn't matter
public StrongHashCodeBuilder<T> append( Set<?> a ){
//E.rr( a );
if( a==null ) appendNull();
else if( a.size() == 0 ) appendEmpty();
else {
T hash = empty();
for( Object v : a ){
StrongHashCodeBuilder<T> b = builder();
b.append( v );
hash = combineHash( hash, b.toHashCode() );
//E.rr( v + "::==" + Base64.encodeBase64String( (byte[])hash ).trim() );
}
//E.rr( Base64.encodeBase64String( (byte[])hash ).trim() );
appendParent( hash );
}
return this;
}
// Here order does matter
public StrongHashCodeBuilder<T> append( Collection<?> a ){
if( a==null ) appendNull();
else if( a.size() == 0 ) appendEmpty();
else for( Object v : a ){
append( v );
}
return this;
}
// Treat map as unordered set of Pairs
public StrongHashCodeBuilder<T> append( Map<?,?> a ){
if( a==null ) appendNull();
else if( a.size() == 0 ) appendEmpty();
else {
Set<StrongPair> set = new HashSet<StrongPair>( a.size() );
for( Map.Entry<?,?> entry : a.entrySet() ) {
set.add( new StrongPair( entry.getKey(), entry.getValue() ) );
}
append( set );
}
return this;
}
public abstract StrongHashCodeBuilder<T> appendNull();
public abstract StrongHashCodeBuilder<T> appendEmpty();
public abstract T combineHash( T hash1, T hash2 );
public abstract T empty();
public abstract StrongHashCodeBuilder<T> appendParent( T hash );
abstract StrongHashCodeBuilder<T> builder();
protected static final class StrongPair {
final Object a, b;
StrongPair( Object a, Object b ){
this.a = a;
this.b = b;
}
}
@Override
public int hashCode(){
throw new RuntimeException( "You didn't mean to call that!" );
}
}