comparison src/com/go/trove/util/MultiKey.java @ 0:3dc0c5604566

Initial checkin of blitz 2.0 fcs - no installer yet.
author Dan Creswell <dan.creswell@gmail.com>
date Sat, 21 Mar 2009 11:00:06 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:3dc0c5604566
1 /* ====================================================================
2 * Trove - Copyright (c) 1997-2000 Walt Disney Internet Group
3 * ====================================================================
4 * The Tea Software License, Version 1.1
5 *
6 * Copyright (c) 2000 Walt Disney Internet Group. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * 3. The end-user documentation included with the redistribution,
21 * if any, must include the following acknowledgment:
22 * "This product includes software developed by the
23 * Walt Disney Internet Group (http://opensource.go.com/)."
24 * Alternately, this acknowledgment may appear in the software itself,
25 * if and wherever such third-party acknowledgments normally appear.
26 *
27 * 4. The names "Tea", "TeaServlet", "Kettle", "Trove" and "BeanDoc" must
28 * not be used to endorse or promote products derived from this
29 * software without prior written permission. For written
30 * permission, please contact opensource@dig.com.
31 *
32 * 5. Products derived from this software may not be called "Tea",
33 * "TeaServlet", "Kettle" or "Trove", nor may "Tea", "TeaServlet",
34 * "Kettle", "Trove" or "BeanDoc" appear in their name, without prior
35 * written permission of the Walt Disney Internet Group.
36 *
37 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40 * DISCLAIMED. IN NO EVENT SHALL THE WALT DISNEY INTERNET GROUP OR ITS
41 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
42 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
43 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
44 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
45 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
46 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
47 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48 * ====================================================================
49 *
50 * For more information about Tea, please see http://opensource.go.com/.
51 */
52
53 package com.go.trove.util;
54
55 import java.util.Arrays;
56
57 /******************************************************************************
58 * MultiKey allows arrays and arrays of arrays to be used as hashtable keys.
59 * Hashcode computation and equality tests will fully recurse into the array
60 * elements. MultiKey can be used in conjunction with {@link Depot} for
61 * caching against complex keys.
62 *
63 * @author Brian S O'Neill
64 * @version
65 * <!--$$Revision: 1.1 $-->, <!--$$JustDate:--> 01/07/09 <!-- $-->
66 * @see Pair
67 */
68 public class MultiKey implements java.io.Serializable {
69 /**
70 * Computes an object hashcode for any kind of object including null,
71 * arrays, and arrays of arrays.
72 */
73 static int hashCode(Object obj) {
74 if (obj == null) {
75 return 0;
76 }
77
78 Class clazz = obj.getClass();
79
80 if (!clazz.isArray()) {
81 return obj.hashCode();
82 }
83
84 // Compute hashcode of array.
85
86 int hash = clazz.hashCode();
87
88 if (obj instanceof Object[]) {
89 Object[] array = (Object[])obj;
90 for (int i = array.length; --i >= 0; ) {
91 hash = hash * 31 + hashCode(array[i]);
92 }
93 }
94 else if (obj instanceof int[]) {
95 int[] array = (int[])obj;
96 for (int i = array.length; --i >= 0; ) {
97 hash = hash * 31 + array[i];
98 }
99 }
100 else if (obj instanceof float[]) {
101 float[] array = (float[])obj;
102 for (int i = array.length; --i >= 0; ) {
103 hash = hash * 31 + Float.floatToIntBits(array[i]);
104 }
105 }
106 else if (obj instanceof long[]) {
107 long[] array = (long[])obj;
108 for (int i = array.length; --i >= 0; ) {
109 long value = array[i];
110 hash = hash * 31 + (int)(value ^ value >>> 32);
111 }
112 }
113 else if (obj instanceof double[]) {
114 double[] array = (double[])obj;
115 for (int i = array.length; --i >= 0; ) {
116 long value = Double.doubleToLongBits(array[i]);
117 hash = hash * 31 + (int)(value ^ value >>> 32);
118 }
119 }
120 else if (obj instanceof byte[]) {
121 byte[] array = (byte[])obj;
122 for (int i = array.length; --i >= 0; ) {
123 hash = hash * 31 + array[i];
124 }
125 }
126 else if (obj instanceof char[]) {
127 char[] array = (char[])obj;
128 for (int i = array.length; --i >= 0; ) {
129 hash = hash * 31 + array[i];
130 }
131 }
132 else if (obj instanceof boolean[]) {
133 boolean[] array = (boolean[])obj;
134 for (int i = array.length; --i >= 0; ) {
135 hash = hash * 31 + (array[i] ? 1 : 0);
136 }
137 }
138 else if (obj instanceof short[]) {
139 short[] array = (short[])obj;
140 for (int i = array.length; --i >= 0; ) {
141 hash = hash * 31 + array[i];
142 }
143 }
144
145 return hash;
146 }
147
148 /**
149 * Performans an object equality for any kind of objects including null,
150 * arrays, and arrays of arrays.
151 */
152 static boolean equals(Object obj1, Object obj2) {
153 if (obj1 == obj2) {
154 return true;
155 }
156 else if (obj1 == null || obj2 == null) {
157 return false;
158 }
159
160 Class clazz1 = obj1.getClass();
161
162 if (!(clazz1.isArray())) {
163 return obj1.equals(obj2);
164 }
165
166 if (clazz1 != obj2.getClass()) {
167 return false;
168 }
169
170 // Perform array equality test.
171 if (obj1 instanceof Object[]) {
172 // Don't use Arrays.equals for objects since it doesn't
173 // recurse into arrays of arrays.
174 Object[] array1 = (Object[])obj1;
175 Object[] array2 = (Object[])obj2;
176
177 int i;
178 if ((i = array1.length) != array2.length) {
179 return false;
180 }
181
182 while (--i >= 0) {
183 if (!equals(array1[i], array2[i])) {
184 return false;
185 }
186 }
187
188 return true;
189 }
190 else if (obj1 instanceof int[]) {
191 return Arrays.equals((int[])obj1, (int[])obj2);
192 }
193 else if (obj1 instanceof float[]) {
194 return Arrays.equals((float[])obj1, (float[])obj2);
195 }
196 else if (obj1 instanceof long[]) {
197 return Arrays.equals((long[])obj1, (long[])obj2);
198 }
199 else if (obj1 instanceof double[]) {
200 return Arrays.equals((double[])obj1, (double[])obj2);
201 }
202 else if (obj1 instanceof byte[]) {
203 return Arrays.equals((byte[])obj1, (byte[])obj2);
204 }
205 else if (obj1 instanceof char[]) {
206 return Arrays.equals((char[])obj1, (char[])obj2);
207 }
208 else if (obj1 instanceof boolean[]) {
209 return Arrays.equals((boolean[])obj1, (boolean[])obj2);
210 }
211 else if (obj1 instanceof short[]) {
212 return Arrays.equals((short[])obj1, (short[])obj2);
213 }
214 else {
215 return obj1.equals(obj2);
216 }
217 }
218
219 private final Object mComponent;
220 private final int mHash;
221
222 /**
223 * Contruct a new MultiKey against a component which may be any kind of
224 * object including an array, or an array of arrays, or null.
225 */
226 public MultiKey(Object component) {
227 mComponent = component;
228 mHash = MultiKey.hashCode(component);
229 }
230
231 /**
232 * Returns the original component used to construct this MultiKey.
233 */
234 public Object getComponent() {
235 return mComponent;
236 }
237
238 public int hashCode() {
239 return mHash;
240 }
241
242 public boolean equals(Object other) {
243 if (this == other) {
244 return true;
245 }
246 else if (other instanceof MultiKey) {
247 MultiKey key = (MultiKey)other;
248 return MultiKey.equals(mComponent, key.mComponent);
249 }
250 else {
251 return false;
252 }
253 }
254
255 public String toString() {
256 StringBuffer buf = new StringBuffer();
257 append(buf, mComponent);
258 return buf.toString();
259 }
260
261 private void append(StringBuffer buf, Object obj) {
262 if (obj == null) {
263 buf.append("null");
264 return;
265 }
266
267 if (!obj.getClass().isArray()) {
268 buf.append(obj);
269 return;
270 }
271
272 buf.append('[');
273
274 if (obj instanceof Object[]) {
275 Object[] array = (Object[])obj;
276 for (int i=0; i<array.length; i++) {
277 if (i > 0) {
278 buf.append(',');
279 }
280 append(buf, array[i]);
281 }
282 }
283 else if (obj instanceof int[]) {
284 int[] array = (int[])obj;
285 for (int i=0; i<array.length; i++) {
286 if (i > 0) {
287 buf.append(',');
288 }
289 buf.append(array[i]);
290 }
291 }
292 else if (obj instanceof float[]) {
293 float[] array = (float[])obj;
294 for (int i=0; i<array.length; i++) {
295 if (i > 0) {
296 buf.append(',');
297 }
298 buf.append(array[i]);
299 }
300 }
301 else if (obj instanceof long[]) {
302 long[] array = (long[])obj;
303 for (int i=0; i<array.length; i++) {
304 if (i > 0) {
305 buf.append(',');
306 }
307 buf.append(array[i]);
308 }
309 }
310 else if (obj instanceof double[]) {
311 double[] array = (double[])obj;
312 for (int i=0; i<array.length; i++) {
313 if (i > 0) {
314 buf.append(',');
315 }
316 buf.append(array[i]);
317 }
318 }
319 else if (obj instanceof byte[]) {
320 byte[] array = (byte[])obj;
321 for (int i=0; i<array.length; i++) {
322 if (i > 0) {
323 buf.append(',');
324 }
325 buf.append(array[i]);
326 }
327 }
328 else if (obj instanceof char[]) {
329 char[] array = (char[])obj;
330 for (int i=0; i<array.length; i++) {
331 if (i > 0) {
332 buf.append(',');
333 }
334 buf.append(array[i]);
335 }
336 }
337 else if (obj instanceof boolean[]) {
338 boolean[] array = (boolean[])obj;
339 for (int i=0; i<array.length; i++) {
340 if (i > 0) {
341 buf.append(',');
342 }
343 buf.append(array[i]);
344 }
345 }
346 else if (obj instanceof short[]) {
347 short[] array = (short[])obj;
348 for (int i=0; i<array.length; i++) {
349 if (i > 0) {
350 buf.append(',');
351 }
352 buf.append(array[i]);
353 }
354 }
355 else {
356 buf.append(obj);
357 }
358
359 buf.append(']');
360 }
361 }