src/share/classes/java/util/IdentityHashMap.java

Print this page
rev 4788 : Fix bunch of generics warnings


 310         return (i + 2 < len ? i + 2 : 0);
 311     }
 312 
 313     /**
 314      * Returns the value to which the specified key is mapped,
 315      * or {@code null} if this map contains no mapping for the key.
 316      *
 317      * <p>More formally, if this map contains a mapping from a key
 318      * {@code k} to a value {@code v} such that {@code (key == k)},
 319      * then this method returns {@code v}; otherwise it returns
 320      * {@code null}.  (There can be at most one such mapping.)
 321      *
 322      * <p>A return value of {@code null} does not <i>necessarily</i>
 323      * indicate that the map contains no mapping for the key; it's also
 324      * possible that the map explicitly maps the key to {@code null}.
 325      * The {@link #containsKey containsKey} operation may be used to
 326      * distinguish these two cases.
 327      *
 328      * @see #put(Object, Object)
 329      */

 330     public V get(Object key) {
 331         Object k = maskNull(key);
 332         Object[] tab = table;
 333         int len = tab.length;
 334         int i = hash(k, len);
 335         while (true) {
 336             Object item = tab[i];
 337             if (item == k)
 338                 return (V) tab[i + 1];
 339             if (item == null)
 340                 return null;
 341             i = nextKeyIndex(i, len);
 342         }
 343     }
 344 
 345     /**
 346      * Tests whether the specified object reference is a key in this identity
 347      * hash map.
 348      *
 349      * @param   key   possible key


 414      *
 415      * @param key the key with which the specified value is to be associated
 416      * @param value the value to be associated with the specified key
 417      * @return the previous value associated with <tt>key</tt>, or
 418      *         <tt>null</tt> if there was no mapping for <tt>key</tt>.
 419      *         (A <tt>null</tt> return can also indicate that the map
 420      *         previously associated <tt>null</tt> with <tt>key</tt>.)
 421      * @see     Object#equals(Object)
 422      * @see     #get(Object)
 423      * @see     #containsKey(Object)
 424      */
 425     public V put(K key, V value) {
 426         Object k = maskNull(key);
 427         Object[] tab = table;
 428         int len = tab.length;
 429         int i = hash(k, len);
 430 
 431         Object item;
 432         while ( (item = tab[i]) != null) {
 433             if (item == k) {

 434                 V oldValue = (V) tab[i + 1];
 435                 tab[i + 1] = value;
 436                 return oldValue;
 437             }
 438             i = nextKeyIndex(i, len);
 439         }
 440 
 441         modCount++;
 442         tab[i] = k;
 443         tab[i + 1] = value;
 444         if (++size >= threshold)
 445             resize(len); // len == 2 * current capacity.
 446         return null;
 447     }
 448 
 449     /**
 450      * Resize the table to hold given capacity.
 451      *
 452      * @param newCapacity the new capacity, must be a power of two.
 453      */


 507     /**
 508      * Removes the mapping for this key from this map if present.
 509      *
 510      * @param key key whose mapping is to be removed from the map
 511      * @return the previous value associated with <tt>key</tt>, or
 512      *         <tt>null</tt> if there was no mapping for <tt>key</tt>.
 513      *         (A <tt>null</tt> return can also indicate that the map
 514      *         previously associated <tt>null</tt> with <tt>key</tt>.)
 515      */
 516     public V remove(Object key) {
 517         Object k = maskNull(key);
 518         Object[] tab = table;
 519         int len = tab.length;
 520         int i = hash(k, len);
 521 
 522         while (true) {
 523             Object item = tab[i];
 524             if (item == k) {
 525                 modCount++;
 526                 size--;

 527                 V oldValue = (V) tab[i + 1];
 528                 tab[i + 1] = null;
 529                 tab[i] = null;
 530                 closeDeletion(i);
 531                 return oldValue;
 532             }
 533             if (item == null)
 534                 return null;
 535             i = nextKeyIndex(i, len);
 536         }
 537 
 538     }
 539 
 540     /**
 541      * Removes the specified key-value mapping from the map if it is present.
 542      *
 543      * @param   key   possible key
 544      * @param   value possible value
 545      * @return  <code>true</code> if and only if the specified key-value
 546      *          mapping was in the map


 621      * Compares the specified object with this map for equality.  Returns
 622      * <tt>true</tt> if the given object is also a map and the two maps
 623      * represent identical object-reference mappings.  More formally, this
 624      * map is equal to another map <tt>m</tt> if and only if
 625      * <tt>this.entrySet().equals(m.entrySet())</tt>.
 626      *
 627      * <p><b>Owing to the reference-equality-based semantics of this map it is
 628      * possible that the symmetry and transitivity requirements of the
 629      * <tt>Object.equals</tt> contract may be violated if this map is compared
 630      * to a normal map.  However, the <tt>Object.equals</tt> contract is
 631      * guaranteed to hold among <tt>IdentityHashMap</tt> instances.</b>
 632      *
 633      * @param  o object to be compared for equality with this map
 634      * @return <tt>true</tt> if the specified object is equal to this map
 635      * @see Object#equals(Object)
 636      */
 637     public boolean equals(Object o) {
 638         if (o == this) {
 639             return true;
 640         } else if (o instanceof IdentityHashMap) {
 641             IdentityHashMap m = (IdentityHashMap) o;
 642             if (m.size() != size)
 643                 return false;
 644 
 645             Object[] tab = m.table;
 646             for (int i = 0; i < tab.length; i+=2) {
 647                 Object k = tab[i];
 648                 if (k != null && !containsMapping(k, tab[i + 1]))
 649                     return false;
 650             }
 651             return true;
 652         } else if (o instanceof Map) {
 653             Map m = (Map)o;
 654             return entrySet().equals(m.entrySet());
 655         } else {
 656             return false;  // o is not a Map
 657         }
 658     }
 659 
 660     /**
 661      * Returns the hash code value for this map.  The hash code of a map is
 662      * defined to be the sum of the hash codes of each entry in the map's
 663      * <tt>entrySet()</tt> view.  This ensures that <tt>m1.equals(m2)</tt>
 664      * implies that <tt>m1.hashCode()==m2.hashCode()</tt> for any two
 665      * <tt>IdentityHashMap</tt> instances <tt>m1</tt> and <tt>m2</tt>, as
 666      * required by the general contract of {@link Object#hashCode}.
 667      *
 668      * <p><b>Owing to the reference-equality-based semantics of the
 669      * <tt>Map.Entry</tt> instances in the set returned by this map's
 670      * <tt>entrySet</tt> method, it is possible that the contractual
 671      * requirement of <tt>Object.hashCode</tt> mentioned in the previous
 672      * paragraph will be violated if one of the two objects being compared is
 673      * an <tt>IdentityHashMap</tt> instance and the other is a normal map.</b>


 681         Object[] tab = table;
 682         for (int i = 0; i < tab.length; i +=2) {
 683             Object key = tab[i];
 684             if (key != null) {
 685                 Object k = unmaskNull(key);
 686                 result += System.identityHashCode(k) ^
 687                           System.identityHashCode(tab[i + 1]);
 688             }
 689         }
 690         return result;
 691     }
 692 
 693     /**
 694      * Returns a shallow copy of this identity hash map: the keys and values
 695      * themselves are not cloned.
 696      *
 697      * @return a shallow copy of this map
 698      */
 699     public Object clone() {
 700         try {
 701             IdentityHashMap<K,V> m = (IdentityHashMap<K,V>) super.clone();
 702             m.entrySet = null;
 703             m.table = table.clone();
 704             return m;
 705         } catch (CloneNotSupportedException e) {
 706             throw new InternalError(e);
 707         }
 708     }
 709 
 710     private abstract class IdentityHashMapIterator<T> implements Iterator<T> {
 711         int index = (size != 0 ? 0 : table.length); // current slot.
 712         int expectedModCount = modCount; // to support fast-fail
 713         int lastReturnedIndex = -1;      // to allow remove()
 714         boolean indexValid; // To avoid unnecessary next computation
 715         Object[] traversalTable = table; // reference to main table or copy
 716 
 717         public boolean hasNext() {
 718             Object[] tab = traversalTable;
 719             for (int i = index; i < tab.length; i+=2) {
 720                 Object key = tab[i];
 721                 if (key != null) {


 751             // back up index to revisit new contents after deletion
 752             index = deletedSlot;
 753             indexValid = false;
 754 
 755             // Removal code proceeds as in closeDeletion except that
 756             // it must catch the rare case where an element already
 757             // seen is swapped into a vacant slot that will be later
 758             // traversed by this iterator. We cannot allow future
 759             // next() calls to return it again.  The likelihood of
 760             // this occurring under 2/3 load factor is very slim, but
 761             // when it does happen, we must make a copy of the rest of
 762             // the table to use for the rest of the traversal. Since
 763             // this can only happen when we are near the end of the table,
 764             // even in these rare cases, this is not very expensive in
 765             // time or space.
 766 
 767             Object[] tab = traversalTable;
 768             int len = tab.length;
 769 
 770             int d = deletedSlot;
 771             K key = (K) tab[d];
 772             tab[d] = null;        // vacate the slot
 773             tab[d + 1] = null;
 774 
 775             // If traversing a copy, remove in real table.
 776             // We can skip gap-closure on copy.
 777             if (tab != IdentityHashMap.this.table) {
 778                 IdentityHashMap.this.remove(key);
 779                 expectedModCount = modCount;
 780                 return;
 781             }
 782 
 783             size--;
 784 
 785             Object item;
 786             for (int i = nextKeyIndex(d, len); (item = tab[i]) != null;
 787                  i = nextKeyIndex(i, len)) {
 788                 int r = hash(item, len);
 789                 // See closeDeletion for explanation of this conditional
 790                 if ((i < r && (r <= d || d <= i)) ||
 791                     (r <= d && d <= i)) {


 801                         traversalTable == IdentityHashMap.this.table) {
 802                         int remaining = len - deletedSlot;
 803                         Object[] newTable = new Object[remaining];
 804                         System.arraycopy(tab, deletedSlot,
 805                                          newTable, 0, remaining);
 806                         traversalTable = newTable;
 807                         index = 0;
 808                     }
 809 
 810                     tab[d] = item;
 811                     tab[d + 1] = tab[i + 1];
 812                     tab[i] = null;
 813                     tab[i + 1] = null;
 814                     d = i;
 815                 }
 816             }
 817         }
 818     }
 819 
 820     private class KeyIterator extends IdentityHashMapIterator<K> {

 821         public K next() {
 822             return (K) unmaskNull(traversalTable[nextIndex()]);
 823         }
 824     }
 825 
 826     private class ValueIterator extends IdentityHashMapIterator<V> {

 827         public V next() {
 828             return (V) traversalTable[nextIndex() + 1];
 829         }
 830     }
 831 
 832     private class EntryIterator
 833         extends IdentityHashMapIterator<Map.Entry<K,V>>
 834     {
 835         private Entry lastReturnedEntry = null;
 836 
 837         public Map.Entry<K,V> next() {
 838             lastReturnedEntry = new Entry(nextIndex());
 839             return lastReturnedEntry;
 840         }
 841 
 842         public void remove() {
 843             lastReturnedIndex =
 844                 ((null == lastReturnedEntry) ? -1 : lastReturnedEntry.index);
 845             super.remove();
 846             lastReturnedEntry.index = lastReturnedIndex;
 847             lastReturnedEntry = null;
 848         }
 849 
 850         private class Entry implements Map.Entry<K,V> {
 851             private int index;
 852 
 853             private Entry(int index) {
 854                 this.index = index;
 855             }
 856 

 857             public K getKey() {
 858                 checkIndexForEntryUse();
 859                 return (K) unmaskNull(traversalTable[index]);
 860             }
 861 

 862             public V getValue() {
 863                 checkIndexForEntryUse();
 864                 return (V) traversalTable[index+1];
 865             }
 866 

 867             public V setValue(V value) {
 868                 checkIndexForEntryUse();
 869                 V oldValue = (V) traversalTable[index+1];
 870                 traversalTable[index+1] = value;
 871                 // if shadowing, force into main table
 872                 if (traversalTable != IdentityHashMap.this.table)
 873                     put((K) traversalTable[index], value);
 874                 return oldValue;
 875             }
 876 
 877             public boolean equals(Object o) {
 878                 if (index < 0)
 879                     return super.equals(o);
 880 
 881                 if (!(o instanceof Map.Entry))
 882                     return false;
 883                 Map.Entry e = (Map.Entry)o;
 884                 return (e.getKey() == unmaskNull(traversalTable[index]) &&
 885                        e.getValue() == traversalTable[index+1]);
 886             }
 887 
 888             public int hashCode() {
 889                 if (lastReturnedIndex < 0)
 890                     return super.hashCode();
 891 
 892                 return (System.identityHashCode(unmaskNull(traversalTable[index])) ^
 893                        System.identityHashCode(traversalTable[index+1]));
 894             }
 895 
 896             public String toString() {
 897                 if (index < 0)
 898                     return super.toString();
 899 
 900                 return (unmaskNull(traversalTable[index]) + "="
 901                         + traversalTable[index+1]);
 902             }
 903 


1092      * hold among identity-based map entries, and among sets of such entries.
1093      * </b>
1094      *
1095      * @return a set view of the identity-mappings contained in this map
1096      */
1097     public Set<Map.Entry<K,V>> entrySet() {
1098         Set<Map.Entry<K,V>> es = entrySet;
1099         if (es != null)
1100             return es;
1101         else
1102             return entrySet = new EntrySet();
1103     }
1104 
1105     private class EntrySet extends AbstractSet<Map.Entry<K,V>> {
1106         public Iterator<Map.Entry<K,V>> iterator() {
1107             return new EntryIterator();
1108         }
1109         public boolean contains(Object o) {
1110             if (!(o instanceof Map.Entry))
1111                 return false;
1112             Map.Entry entry = (Map.Entry)o;
1113             return containsMapping(entry.getKey(), entry.getValue());
1114         }
1115         public boolean remove(Object o) {
1116             if (!(o instanceof Map.Entry))
1117                 return false;
1118             Map.Entry entry = (Map.Entry)o;
1119             return removeMapping(entry.getKey(), entry.getValue());
1120         }
1121         public int size() {
1122             return size;
1123         }
1124         public void clear() {
1125             IdentityHashMap.this.clear();
1126         }
1127         /*
1128          * Must revert from AbstractSet's impl to AbstractCollection's, as
1129          * the former contains an optimization that results in incorrect
1130          * behavior when c is a smaller "normal" (non-identity-based) Set.
1131          */
1132         public boolean removeAll(Collection<?> c) {
1133             boolean modified = false;
1134             for (Iterator<Map.Entry<K,V>> i = iterator(); i.hasNext(); ) {
1135                 if (c.contains(i.next())) {
1136                     i.remove();
1137                     modified = true;
1138                 }


1196         }
1197     }
1198 
1199     /**
1200      * Reconstitute the <tt>IdentityHashMap</tt> instance from a stream (i.e.,
1201      * deserialize it).
1202      */
1203     private void readObject(java.io.ObjectInputStream s)
1204         throws java.io.IOException, ClassNotFoundException  {
1205         // Read in any hidden stuff
1206         s.defaultReadObject();
1207 
1208         // Read in size (number of Mappings)
1209         int size = s.readInt();
1210 
1211         // Allow for 33% growth (i.e., capacity is >= 2* size()).
1212         init(capacity((size*4)/3));
1213 
1214         // Read the keys and values, and put the mappings in the table
1215         for (int i=0; i<size; i++) {

1216             K key = (K) s.readObject();

1217             V value = (V) s.readObject();
1218             putForCreate(key, value);
1219         }
1220     }
1221 
1222     /**
1223      * The put method for readObject.  It does not resize the table,
1224      * update modCount, etc.
1225      */
1226     private void putForCreate(K key, V value)
1227         throws IOException
1228     {
1229         K k = (K)maskNull(key);
1230         Object[] tab = table;
1231         int len = tab.length;
1232         int i = hash(k, len);
1233 
1234         Object item;
1235         while ( (item = tab[i]) != null) {
1236             if (item == k)
1237                 throw new java.io.StreamCorruptedException();
1238             i = nextKeyIndex(i, len);
1239         }
1240         tab[i] = k;
1241         tab[i + 1] = value;
1242     }
1243 }


 310         return (i + 2 < len ? i + 2 : 0);
 311     }
 312 
 313     /**
 314      * Returns the value to which the specified key is mapped,
 315      * or {@code null} if this map contains no mapping for the key.
 316      *
 317      * <p>More formally, if this map contains a mapping from a key
 318      * {@code k} to a value {@code v} such that {@code (key == k)},
 319      * then this method returns {@code v}; otherwise it returns
 320      * {@code null}.  (There can be at most one such mapping.)
 321      *
 322      * <p>A return value of {@code null} does not <i>necessarily</i>
 323      * indicate that the map contains no mapping for the key; it's also
 324      * possible that the map explicitly maps the key to {@code null}.
 325      * The {@link #containsKey containsKey} operation may be used to
 326      * distinguish these two cases.
 327      *
 328      * @see #put(Object, Object)
 329      */
 330     @SuppressWarnings("unchecked")
 331     public V get(Object key) {
 332         Object k = maskNull(key);
 333         Object[] tab = table;
 334         int len = tab.length;
 335         int i = hash(k, len);
 336         while (true) {
 337             Object item = tab[i];
 338             if (item == k)
 339                 return (V) tab[i + 1];
 340             if (item == null)
 341                 return null;
 342             i = nextKeyIndex(i, len);
 343         }
 344     }
 345 
 346     /**
 347      * Tests whether the specified object reference is a key in this identity
 348      * hash map.
 349      *
 350      * @param   key   possible key


 415      *
 416      * @param key the key with which the specified value is to be associated
 417      * @param value the value to be associated with the specified key
 418      * @return the previous value associated with <tt>key</tt>, or
 419      *         <tt>null</tt> if there was no mapping for <tt>key</tt>.
 420      *         (A <tt>null</tt> return can also indicate that the map
 421      *         previously associated <tt>null</tt> with <tt>key</tt>.)
 422      * @see     Object#equals(Object)
 423      * @see     #get(Object)
 424      * @see     #containsKey(Object)
 425      */
 426     public V put(K key, V value) {
 427         Object k = maskNull(key);
 428         Object[] tab = table;
 429         int len = tab.length;
 430         int i = hash(k, len);
 431 
 432         Object item;
 433         while ( (item = tab[i]) != null) {
 434             if (item == k) {
 435                 @SuppressWarnings("unchecked")
 436                     V oldValue = (V) tab[i + 1];
 437                 tab[i + 1] = value;
 438                 return oldValue;
 439             }
 440             i = nextKeyIndex(i, len);
 441         }
 442 
 443         modCount++;
 444         tab[i] = k;
 445         tab[i + 1] = value;
 446         if (++size >= threshold)
 447             resize(len); // len == 2 * current capacity.
 448         return null;
 449     }
 450 
 451     /**
 452      * Resize the table to hold given capacity.
 453      *
 454      * @param newCapacity the new capacity, must be a power of two.
 455      */


 509     /**
 510      * Removes the mapping for this key from this map if present.
 511      *
 512      * @param key key whose mapping is to be removed from the map
 513      * @return the previous value associated with <tt>key</tt>, or
 514      *         <tt>null</tt> if there was no mapping for <tt>key</tt>.
 515      *         (A <tt>null</tt> return can also indicate that the map
 516      *         previously associated <tt>null</tt> with <tt>key</tt>.)
 517      */
 518     public V remove(Object key) {
 519         Object k = maskNull(key);
 520         Object[] tab = table;
 521         int len = tab.length;
 522         int i = hash(k, len);
 523 
 524         while (true) {
 525             Object item = tab[i];
 526             if (item == k) {
 527                 modCount++;
 528                 size--;
 529                 @SuppressWarnings("unchecked")
 530                     V oldValue = (V) tab[i + 1];
 531                 tab[i + 1] = null;
 532                 tab[i] = null;
 533                 closeDeletion(i);
 534                 return oldValue;
 535             }
 536             if (item == null)
 537                 return null;
 538             i = nextKeyIndex(i, len);
 539         }
 540 
 541     }
 542 
 543     /**
 544      * Removes the specified key-value mapping from the map if it is present.
 545      *
 546      * @param   key   possible key
 547      * @param   value possible value
 548      * @return  <code>true</code> if and only if the specified key-value
 549      *          mapping was in the map


 624      * Compares the specified object with this map for equality.  Returns
 625      * <tt>true</tt> if the given object is also a map and the two maps
 626      * represent identical object-reference mappings.  More formally, this
 627      * map is equal to another map <tt>m</tt> if and only if
 628      * <tt>this.entrySet().equals(m.entrySet())</tt>.
 629      *
 630      * <p><b>Owing to the reference-equality-based semantics of this map it is
 631      * possible that the symmetry and transitivity requirements of the
 632      * <tt>Object.equals</tt> contract may be violated if this map is compared
 633      * to a normal map.  However, the <tt>Object.equals</tt> contract is
 634      * guaranteed to hold among <tt>IdentityHashMap</tt> instances.</b>
 635      *
 636      * @param  o object to be compared for equality with this map
 637      * @return <tt>true</tt> if the specified object is equal to this map
 638      * @see Object#equals(Object)
 639      */
 640     public boolean equals(Object o) {
 641         if (o == this) {
 642             return true;
 643         } else if (o instanceof IdentityHashMap) {
 644             IdentityHashMap<?,?> m = (IdentityHashMap<?,?>) o;
 645             if (m.size() != size)
 646                 return false;
 647 
 648             Object[] tab = m.table;
 649             for (int i = 0; i < tab.length; i+=2) {
 650                 Object k = tab[i];
 651                 if (k != null && !containsMapping(k, tab[i + 1]))
 652                     return false;
 653             }
 654             return true;
 655         } else if (o instanceof Map) {
 656             Map<?,?> m = (Map<?,?>)o;
 657             return entrySet().equals(m.entrySet());
 658         } else {
 659             return false;  // o is not a Map
 660         }
 661     }
 662 
 663     /**
 664      * Returns the hash code value for this map.  The hash code of a map is
 665      * defined to be the sum of the hash codes of each entry in the map's
 666      * <tt>entrySet()</tt> view.  This ensures that <tt>m1.equals(m2)</tt>
 667      * implies that <tt>m1.hashCode()==m2.hashCode()</tt> for any two
 668      * <tt>IdentityHashMap</tt> instances <tt>m1</tt> and <tt>m2</tt>, as
 669      * required by the general contract of {@link Object#hashCode}.
 670      *
 671      * <p><b>Owing to the reference-equality-based semantics of the
 672      * <tt>Map.Entry</tt> instances in the set returned by this map's
 673      * <tt>entrySet</tt> method, it is possible that the contractual
 674      * requirement of <tt>Object.hashCode</tt> mentioned in the previous
 675      * paragraph will be violated if one of the two objects being compared is
 676      * an <tt>IdentityHashMap</tt> instance and the other is a normal map.</b>


 684         Object[] tab = table;
 685         for (int i = 0; i < tab.length; i +=2) {
 686             Object key = tab[i];
 687             if (key != null) {
 688                 Object k = unmaskNull(key);
 689                 result += System.identityHashCode(k) ^
 690                           System.identityHashCode(tab[i + 1]);
 691             }
 692         }
 693         return result;
 694     }
 695 
 696     /**
 697      * Returns a shallow copy of this identity hash map: the keys and values
 698      * themselves are not cloned.
 699      *
 700      * @return a shallow copy of this map
 701      */
 702     public Object clone() {
 703         try {
 704             IdentityHashMap<?,?> m = (IdentityHashMap<?,?>) super.clone();
 705             m.entrySet = null;
 706             m.table = table.clone();
 707             return m;
 708         } catch (CloneNotSupportedException e) {
 709             throw new InternalError(e);
 710         }
 711     }
 712 
 713     private abstract class IdentityHashMapIterator<T> implements Iterator<T> {
 714         int index = (size != 0 ? 0 : table.length); // current slot.
 715         int expectedModCount = modCount; // to support fast-fail
 716         int lastReturnedIndex = -1;      // to allow remove()
 717         boolean indexValid; // To avoid unnecessary next computation
 718         Object[] traversalTable = table; // reference to main table or copy
 719 
 720         public boolean hasNext() {
 721             Object[] tab = traversalTable;
 722             for (int i = index; i < tab.length; i+=2) {
 723                 Object key = tab[i];
 724                 if (key != null) {


 754             // back up index to revisit new contents after deletion
 755             index = deletedSlot;
 756             indexValid = false;
 757 
 758             // Removal code proceeds as in closeDeletion except that
 759             // it must catch the rare case where an element already
 760             // seen is swapped into a vacant slot that will be later
 761             // traversed by this iterator. We cannot allow future
 762             // next() calls to return it again.  The likelihood of
 763             // this occurring under 2/3 load factor is very slim, but
 764             // when it does happen, we must make a copy of the rest of
 765             // the table to use for the rest of the traversal. Since
 766             // this can only happen when we are near the end of the table,
 767             // even in these rare cases, this is not very expensive in
 768             // time or space.
 769 
 770             Object[] tab = traversalTable;
 771             int len = tab.length;
 772 
 773             int d = deletedSlot;
 774             Object key = tab[d];
 775             tab[d] = null;        // vacate the slot
 776             tab[d + 1] = null;
 777 
 778             // If traversing a copy, remove in real table.
 779             // We can skip gap-closure on copy.
 780             if (tab != IdentityHashMap.this.table) {
 781                 IdentityHashMap.this.remove(key);
 782                 expectedModCount = modCount;
 783                 return;
 784             }
 785 
 786             size--;
 787 
 788             Object item;
 789             for (int i = nextKeyIndex(d, len); (item = tab[i]) != null;
 790                  i = nextKeyIndex(i, len)) {
 791                 int r = hash(item, len);
 792                 // See closeDeletion for explanation of this conditional
 793                 if ((i < r && (r <= d || d <= i)) ||
 794                     (r <= d && d <= i)) {


 804                         traversalTable == IdentityHashMap.this.table) {
 805                         int remaining = len - deletedSlot;
 806                         Object[] newTable = new Object[remaining];
 807                         System.arraycopy(tab, deletedSlot,
 808                                          newTable, 0, remaining);
 809                         traversalTable = newTable;
 810                         index = 0;
 811                     }
 812 
 813                     tab[d] = item;
 814                     tab[d + 1] = tab[i + 1];
 815                     tab[i] = null;
 816                     tab[i + 1] = null;
 817                     d = i;
 818                 }
 819             }
 820         }
 821     }
 822 
 823     private class KeyIterator extends IdentityHashMapIterator<K> {
 824         @SuppressWarnings("unchecked")
 825         public K next() {
 826             return (K) unmaskNull(traversalTable[nextIndex()]);
 827         }
 828     }
 829 
 830     private class ValueIterator extends IdentityHashMapIterator<V> {
 831         @SuppressWarnings("unchecked")
 832         public V next() {
 833             return (V) traversalTable[nextIndex() + 1];
 834         }
 835     }
 836 
 837     private class EntryIterator
 838         extends IdentityHashMapIterator<Map.Entry<K,V>>
 839     {
 840         private Entry lastReturnedEntry = null;
 841 
 842         public Map.Entry<K,V> next() {
 843             lastReturnedEntry = new Entry(nextIndex());
 844             return lastReturnedEntry;
 845         }
 846 
 847         public void remove() {
 848             lastReturnedIndex =
 849                 ((null == lastReturnedEntry) ? -1 : lastReturnedEntry.index);
 850             super.remove();
 851             lastReturnedEntry.index = lastReturnedIndex;
 852             lastReturnedEntry = null;
 853         }
 854 
 855         private class Entry implements Map.Entry<K,V> {
 856             private int index;
 857 
 858             private Entry(int index) {
 859                 this.index = index;
 860             }
 861 
 862             @SuppressWarnings("unchecked")
 863             public K getKey() {
 864                 checkIndexForEntryUse();
 865                 return (K) unmaskNull(traversalTable[index]);
 866             }
 867 
 868             @SuppressWarnings("unchecked")
 869             public V getValue() {
 870                 checkIndexForEntryUse();
 871                 return (V) traversalTable[index+1];
 872             }
 873 
 874             @SuppressWarnings("unchecked")
 875             public V setValue(V value) {
 876                 checkIndexForEntryUse();
 877                 V oldValue = (V) traversalTable[index+1];
 878                 traversalTable[index+1] = value;
 879                 // if shadowing, force into main table
 880                 if (traversalTable != IdentityHashMap.this.table)
 881                     put((K) traversalTable[index], value);
 882                 return oldValue;
 883             }
 884 
 885             public boolean equals(Object o) {
 886                 if (index < 0)
 887                     return super.equals(o);
 888 
 889                 if (!(o instanceof Map.Entry))
 890                     return false;
 891                 Map.Entry<?,?> e = (Map.Entry<?,?>)o;
 892                 return (e.getKey() == unmaskNull(traversalTable[index]) &&
 893                        e.getValue() == traversalTable[index+1]);
 894             }
 895 
 896             public int hashCode() {
 897                 if (lastReturnedIndex < 0)
 898                     return super.hashCode();
 899 
 900                 return (System.identityHashCode(unmaskNull(traversalTable[index])) ^
 901                        System.identityHashCode(traversalTable[index+1]));
 902             }
 903 
 904             public String toString() {
 905                 if (index < 0)
 906                     return super.toString();
 907 
 908                 return (unmaskNull(traversalTable[index]) + "="
 909                         + traversalTable[index+1]);
 910             }
 911 


1100      * hold among identity-based map entries, and among sets of such entries.
1101      * </b>
1102      *
1103      * @return a set view of the identity-mappings contained in this map
1104      */
1105     public Set<Map.Entry<K,V>> entrySet() {
1106         Set<Map.Entry<K,V>> es = entrySet;
1107         if (es != null)
1108             return es;
1109         else
1110             return entrySet = new EntrySet();
1111     }
1112 
1113     private class EntrySet extends AbstractSet<Map.Entry<K,V>> {
1114         public Iterator<Map.Entry<K,V>> iterator() {
1115             return new EntryIterator();
1116         }
1117         public boolean contains(Object o) {
1118             if (!(o instanceof Map.Entry))
1119                 return false;
1120             Map.Entry<?,?> entry = (Map.Entry<?,?>)o;
1121             return containsMapping(entry.getKey(), entry.getValue());
1122         }
1123         public boolean remove(Object o) {
1124             if (!(o instanceof Map.Entry))
1125                 return false;
1126             Map.Entry<?,?> entry = (Map.Entry<?,?>)o;
1127             return removeMapping(entry.getKey(), entry.getValue());
1128         }
1129         public int size() {
1130             return size;
1131         }
1132         public void clear() {
1133             IdentityHashMap.this.clear();
1134         }
1135         /*
1136          * Must revert from AbstractSet's impl to AbstractCollection's, as
1137          * the former contains an optimization that results in incorrect
1138          * behavior when c is a smaller "normal" (non-identity-based) Set.
1139          */
1140         public boolean removeAll(Collection<?> c) {
1141             boolean modified = false;
1142             for (Iterator<Map.Entry<K,V>> i = iterator(); i.hasNext(); ) {
1143                 if (c.contains(i.next())) {
1144                     i.remove();
1145                     modified = true;
1146                 }


1204         }
1205     }
1206 
1207     /**
1208      * Reconstitute the <tt>IdentityHashMap</tt> instance from a stream (i.e.,
1209      * deserialize it).
1210      */
1211     private void readObject(java.io.ObjectInputStream s)
1212         throws java.io.IOException, ClassNotFoundException  {
1213         // Read in any hidden stuff
1214         s.defaultReadObject();
1215 
1216         // Read in size (number of Mappings)
1217         int size = s.readInt();
1218 
1219         // Allow for 33% growth (i.e., capacity is >= 2* size()).
1220         init(capacity((size*4)/3));
1221 
1222         // Read the keys and values, and put the mappings in the table
1223         for (int i=0; i<size; i++) {
1224             @SuppressWarnings("unchecked")
1225                 K key = (K) s.readObject();
1226             @SuppressWarnings("unchecked")
1227                 V value = (V) s.readObject();
1228             putForCreate(key, value);
1229         }
1230     }
1231 
1232     /**
1233      * The put method for readObject.  It does not resize the table,
1234      * update modCount, etc.
1235      */
1236     private void putForCreate(K key, V value)
1237         throws IOException
1238     {
1239         Object k = maskNull(key);
1240         Object[] tab = table;
1241         int len = tab.length;
1242         int i = hash(k, len);
1243 
1244         Object item;
1245         while ( (item = tab[i]) != null) {
1246             if (item == k)
1247                 throw new java.io.StreamCorruptedException();
1248             i = nextKeyIndex(i, len);
1249         }
1250         tab[i] = k;
1251         tab[i + 1] = value;
1252     }
1253 }