1 /* 2 * Copyright (c) 1999, 2004, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 /* 27 * Licensed Materials - Property of IBM 28 * RMI-IIOP v1.0 29 * Copyright IBM Corp. 1998 1999 All Rights Reserved 30 * 31 */ 32 33 package com.sun.corba.se.impl.util; 34 35 import java.util.Dictionary; 36 import java.util.Enumeration; 37 import java.util.NoSuchElementException; 38 39 /** 40 * IdentityHashtable is a modified copy of the 1.1.6 Hashtable class which 41 * does not rely on the hashCode() and equals() methods of the key or value; 42 * instead, it uses the System.identityHashcode() method and pointer comparison. 43 * In addition, all synchronization has been removed. 44 */ 45 public final class IdentityHashtable extends Dictionary { 46 /** 47 * The hash table data. 48 */ 49 private transient IdentityHashtableEntry table[]; 50 51 /** 52 * The total number of entries in the hash table. 53 */ 54 private transient int count; 55 56 /** 57 * Rehashes the table when count exceeds this threshold. 58 */ 59 private int threshold; 60 61 /** 62 * The load factor for the hashtable. 63 */ 64 private float loadFactor; 65 66 /** 67 * Constructs a new, empty hashtable with the specified initial 68 * capacity and the specified load factor. 69 * 70 * @param initialCapacity the initial capacity of the hashtable. 71 * @param loadFactor a number between 0.0 and 1.0. 72 * @exception IllegalArgumentException if the initial capacity is less 73 * than or equal to zero, or if the load factor is less than 74 * or equal to zero. 75 * @since 1.0 76 */ 77 public IdentityHashtable(int initialCapacity, float loadFactor) { 78 if ((initialCapacity <= 0) || (loadFactor <= 0.0)) { 79 throw new IllegalArgumentException(); 80 } 81 this.loadFactor = loadFactor; 82 table = new IdentityHashtableEntry[initialCapacity]; 83 threshold = (int)(initialCapacity * loadFactor); 84 } 85 86 /** 87 * Constructs a new, empty hashtable with the specified initial capacity 88 * and default load factor. 89 * 90 * @param initialCapacity the initial capacity of the hashtable. 91 * @since 1.0 92 */ 93 public IdentityHashtable(int initialCapacity) { 94 this(initialCapacity, 0.75f); 95 } 96 97 /** 98 * Constructs a new, empty hashtable with a default capacity and load 99 * factor. 100 * 101 * @since 1.0 102 */ 103 public IdentityHashtable() { 104 this(101, 0.75f); 105 } 106 107 /** 108 * Returns the number of keys in this hashtable. 109 * 110 * @return the number of keys in this hashtable. 111 * @since 1.0 112 */ 113 public int size() { 114 return count; 115 } 116 117 /** 118 * Tests if this hashtable maps no keys to values. 119 * 120 * @return <code>true</code> if this hashtable maps no keys to values; 121 * <code>false</code> otherwise. 122 * @since 1.0 123 */ 124 public boolean isEmpty() { 125 return count == 0; 126 } 127 128 /** 129 * Returns an enumeration of the keys in this hashtable. 130 * 131 * @return an enumeration of the keys in this hashtable. 132 * @see java.util.Enumeration 133 * @see java.util.Hashtable#elements() 134 * @since 1.0 135 */ 136 public Enumeration keys() { 137 return new IdentityHashtableEnumerator(table, true); 138 } 139 140 /** 141 * Returns an enumeration of the values in this hashtable. 142 * Use the Enumeration methods on the returned object to fetch the elements 143 * sequentially. 144 * 145 * @return an enumeration of the values in this hashtable. 146 * @see java.util.Enumeration 147 * @see java.util.Hashtable#keys() 148 * @since 1.0 149 */ 150 public Enumeration elements() { 151 return new IdentityHashtableEnumerator(table, false); 152 } 153 154 /** 155 * Tests if some key maps into the specified value in this hashtable. 156 * This operation is more expensive than the <code>containsKey</code> 157 * method. 158 * 159 * @param value a value to search for. 160 * @return <code>true</code> if some key maps to the 161 * <code>value</code> argument in this hashtable; 162 * <code>false</code> otherwise. 163 * @exception NullPointerException if the value is <code>null</code>. 164 * @see java.util.Hashtable#containsKey(java.lang.Object) 165 * @since 1.0 166 */ 167 public boolean contains(Object value) { 168 if (value == null) { 169 throw new NullPointerException(); 170 } 171 172 IdentityHashtableEntry tab[] = table; 173 for (int i = tab.length ; i-- > 0 ;) { 174 for (IdentityHashtableEntry e = tab[i] ; e != null ; e = e.next) { 175 if (e.value == value) { 176 return true; 177 } 178 } 179 } 180 return false; 181 } 182 183 /** 184 * Tests if the specified object is a key in this hashtable. 185 * 186 * @param key possible key. 187 * @return <code>true</code> if the specified object is a key in this 188 * hashtable; <code>false</code> otherwise. 189 * @see java.util.Hashtable#contains(java.lang.Object) 190 * @since 1.0 191 */ 192 public boolean containsKey(Object key) { 193 IdentityHashtableEntry tab[] = table; 194 int hash = System.identityHashCode(key); 195 int index = (hash & 0x7FFFFFFF) % tab.length; 196 for (IdentityHashtableEntry e = tab[index] ; e != null ; e = e.next) { 197 if ((e.hash == hash) && e.key == key) { 198 return true; 199 } 200 } 201 return false; 202 } 203 204 /** 205 * Returns the value to which the specified key is mapped in this hashtable. 206 * 207 * @param key a key in the hashtable. 208 * @return the value to which the key is mapped in this hashtable; 209 * <code>null</code> if the key is not mapped to any value in 210 * this hashtable. 211 * @see java.util.Hashtable#put(java.lang.Object, java.lang.Object) 212 * @since 1.0 213 */ 214 public Object get(Object key) { 215 IdentityHashtableEntry tab[] = table; 216 int hash = System.identityHashCode(key); 217 int index = (hash & 0x7FFFFFFF) % tab.length; 218 for (IdentityHashtableEntry e = tab[index] ; e != null ; e = e.next) { 219 if ((e.hash == hash) && e.key == key) { 220 return e.value; 221 } 222 } 223 return null; 224 } 225 226 /** 227 * Rehashes the contents of the hashtable into a hashtable with a 228 * larger capacity. This method is called automatically when the 229 * number of keys in the hashtable exceeds this hashtable's capacity 230 * and load factor. 231 * 232 * @since 1.0 233 */ 234 protected void rehash() { 235 int oldCapacity = table.length; 236 IdentityHashtableEntry oldTable[] = table; 237 238 int newCapacity = oldCapacity * 2 + 1; 239 IdentityHashtableEntry newTable[] = new IdentityHashtableEntry[newCapacity]; 240 241 threshold = (int)(newCapacity * loadFactor); 242 table = newTable; 243 244 //System.out.println("rehash old=" + oldCapacity + ", new=" + newCapacity + ", thresh=" + threshold + ", count=" + count); 245 246 for (int i = oldCapacity ; i-- > 0 ;) { 247 for (IdentityHashtableEntry old = oldTable[i] ; old != null ; ) { 248 IdentityHashtableEntry e = old; 249 old = old.next; 250 251 int index = (e.hash & 0x7FFFFFFF) % newCapacity; 252 e.next = newTable[index]; 253 newTable[index] = e; 254 } 255 } 256 } 257 258 /** 259 * Maps the specified <code>key</code> to the specified 260 * <code>value</code> in this hashtable. Neither the key nor the 261 * value can be <code>null</code>. 262 * <p> 263 * The value can be retrieved by calling the <code>get</code> method 264 * with a key that is equal to the original key. 265 * 266 * @param key the hashtable key. 267 * @param value the value. 268 * @return the previous value of the specified key in this hashtable, 269 * or <code>null</code> if it did not have one. 270 * @exception NullPointerException if the key or value is 271 * <code>null</code>. 272 * @see java.util.Hashtable#get(java.lang.Object) 273 * @since 1.0 274 */ 275 public Object put(Object key, Object value) { 276 // Make sure the value is not null 277 if (value == null) { 278 throw new NullPointerException(); 279 } 280 281 // Makes sure the key is not already in the hashtable. 282 IdentityHashtableEntry tab[] = table; 283 int hash = System.identityHashCode(key); 284 int index = (hash & 0x7FFFFFFF) % tab.length; 285 for (IdentityHashtableEntry e = tab[index] ; e != null ; e = e.next) { 286 if ((e.hash == hash) && e.key == key) { 287 Object old = e.value; 288 e.value = value; 289 return old; 290 } 291 } 292 293 if (count >= threshold) { 294 // Rehash the table if the threshold is exceeded 295 rehash(); 296 return put(key, value); 297 } 298 299 // Creates the new entry. 300 IdentityHashtableEntry e = new IdentityHashtableEntry(); 301 e.hash = hash; 302 e.key = key; 303 e.value = value; 304 e.next = tab[index]; 305 tab[index] = e; 306 count++; 307 return null; 308 } 309 310 /** 311 * Removes the key (and its corresponding value) from this 312 * hashtable. This method does nothing if the key is not in the hashtable. 313 * 314 * @param key the key that needs to be removed. 315 * @return the value to which the key had been mapped in this hashtable, 316 * or <code>null</code> if the key did not have a mapping. 317 * @since 1.0 318 */ 319 public Object remove(Object key) { 320 IdentityHashtableEntry tab[] = table; 321 int hash = System.identityHashCode(key); 322 int index = (hash & 0x7FFFFFFF) % tab.length; 323 for (IdentityHashtableEntry e = tab[index], prev = null ; e != null ; prev = e, e = e.next) { 324 if ((e.hash == hash) && e.key == key) { 325 if (prev != null) { 326 prev.next = e.next; 327 } else { 328 tab[index] = e.next; 329 } 330 count--; 331 return e.value; 332 } 333 } 334 return null; 335 } 336 337 /** 338 * Clears this hashtable so that it contains no keys. 339 * 340 * @since 1.0 341 */ 342 public void clear() { 343 IdentityHashtableEntry tab[] = table; 344 for (int index = tab.length; --index >= 0; ) 345 tab[index] = null; 346 count = 0; 347 } 348 349 /** 350 * Returns a rather long string representation of this hashtable. 351 * 352 * @return a string representation of this hashtable. 353 * @since 1.0 354 */ 355 public String toString() { 356 int max = size() - 1; 357 StringBuffer buf = new StringBuffer(); 358 Enumeration k = keys(); 359 Enumeration e = elements(); 360 buf.append("{"); 361 362 for (int i = 0; i <= max; i++) { 363 String s1 = k.nextElement().toString(); 364 String s2 = e.nextElement().toString(); 365 buf.append(s1 + "=" + s2); 366 if (i < max) { 367 buf.append(", "); 368 } 369 } 370 buf.append("}"); 371 return buf.toString(); 372 } 373 }