/* This file belongs to the Servoy development and deployment environment, Copyright (C) 1997-2010 Servoy BV This program is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program; if not, see http://www.gnu.org/licenses or write to the Free Software Foundation,Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 */ package com.servoy.j2db.util; import java.util.Arrays; /** * The <code>IntArrayKey</code> class is a wrapper around an <code>int[]</code> which can be used to index a Hashtable or HashMap. This class implements the * <code>hashCode</code>, and <code>equals</code> methods as specified by the <code>Hashtable</code> class. The <code>equals</code> methods implements * true equality (of the contents), not reference equality. Furthermore, it implements the <code>Cloneable</code> interface which allows the key to be copied * (with deep copy semantics, i.e. the contents are cloned as well). * * @see java.util.Hashtable * @see java.util.HashMap * @see Object#equals(Object) * @see Object#hashCode() * @see Object#clone() * @see Cloneable * */ public class IntArrayKey implements Cloneable { /** * A reference to the <code>int[]</code> which represents the contents of this class. */ protected int intArray[]; /** * Temporary array which is used to calculate the hash of <code>intArray</code>. */ protected int hash[]; /** * Boolean to indicate whether the hash was previously calculated and is currently cached. */ protected boolean isHashCached; /** * Constructs a new <code>IntArrayKey</code> with a <code>null</code> array as contents. */ public IntArrayKey() { this(null); } /** * Constructs a new <code>IntArrayKey</code> with the specified array as contents. * * @param intArray the array which will represent the contents of this key (may be <code>null</code>) */ public IntArrayKey(int intArray[]) { hash = new int[3]; setIntArray(intArray); } /** * Returns the array which represents the contents of this key. * * @return the array which represents the contents of this key */ public synchronized int[] getIntArray() { return intArray; } /** * Sets the contents of this key to the specified array. The cached value of the hash is thrown away. * * @param intArray the array to which the contents of this key will be set */ public synchronized void setIntArray(int intArray[]) { this.intArray = intArray; isHashCached = false; } /** * Returns whether or not this instance and the specified other object are equal. This is the case iff the other object is an instance of the * <code>IntArrayKey</code> class and the contents arrays are equal. * * @param other the other object to compare this instance with * * @return whether or not this instance is equal to the specified instance */ @Override public synchronized boolean equals(Object other) { if (other instanceof IntArrayKey) { return Arrays.equals(intArray, ((IntArrayKey)other).intArray); } else { return false; } } /** * Calculate the hashcode for the contents of this instance. * * @return a hashcode for the contents of this instance. */ @Override public synchronized int hashCode() { // If the hash code is cached return it immediately. if (isHashCached) { return hash[2]; } // If the array is null return the constant value 0x31337157. if (intArray == null) { return 0x31337157; } // Otherwise calculate a hash. hash[0] = hash[1] = 0x9e3779b9; hash[2] = 0x31337157 + intArray.length; int i = 0, j = 0; while (i < intArray.length) { if (j == 3) { j = 0; mix(); } hash[j++] += intArray[i++]; } mix(); isHashCached = true; return hash[2]; } /** * Mixes the values in the <code>hash</code> array to increase the dependencies of the hashcode on the different bits of the contents array. */ protected synchronized void mix() { int i = hash[0], j = hash[1], k = hash[2]; i -= j; i -= k; i ^= k >> 13; j -= k; j -= i; j ^= i << 8; k -= i; k -= j; k ^= j >> 13; i -= j; i -= k; i ^= k >> 12; j -= k; j -= i; j ^= i << 16; k -= i; k -= j; k ^= j >> 5; i -= j; i -= k; i ^= k >> 3; j -= k; j -= i; j ^= i << 10; k -= i; k -= j; k ^= j >> 15; hash[0] = i; hash[1] = j; hash[2] = k; } }