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

Print this page
rev 3765 : 6312706: Map entrySet iterators should return different entries on each call to next()
Reviewed-by: mduigou
Contributed-by: Neil Richards <neil.richards@ngmr.net>
   1 /*
   2  * Copyright (c) 2000, 2008, 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


 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     /**
 833      * Since we don't use Entry objects, we use the Iterator
 834      * itself as an entry.
 835      */
 836     private class EntryIterator
 837         extends IdentityHashMapIterator<Map.Entry<K,V>>
 838         implements Map.Entry<K,V>
 839     {


 840         public Map.Entry<K,V> next() {
 841             nextIndex();
 842             return this;
 843         }
 844 
 845         public K getKey() {
 846             // Provide a better exception than out of bounds index
 847             if (lastReturnedIndex < 0)
 848                 throw new IllegalStateException("Entry was removed");






 849 
 850             return (K) unmaskNull(traversalTable[lastReturnedIndex]);

 851         }
 852 
 853         public V getValue() {
 854             // Provide a better exception than out of bounds index
 855             if (lastReturnedIndex < 0)
 856                 throw new IllegalStateException("Entry was removed");
 857 
 858             return (V) traversalTable[lastReturnedIndex+1];


 859         }
 860 
 861         public V setValue(V value) {
 862             // It would be mean-spirited to proceed here if remove() called
 863             if (lastReturnedIndex < 0)
 864                 throw new IllegalStateException("Entry was removed");
 865             V oldValue = (V) traversalTable[lastReturnedIndex+1];
 866             traversalTable[lastReturnedIndex+1] = value;
 867             // if shadowing, force into main table
 868             if (traversalTable != IdentityHashMap.this.table)
 869                 put((K) traversalTable[lastReturnedIndex], value);
 870             return oldValue;
 871         }
 872 
 873         public boolean equals(Object o) {
 874             if (lastReturnedIndex < 0)
 875                 return super.equals(o);
 876 
 877             if (!(o instanceof Map.Entry))
 878                 return false;
 879             Map.Entry e = (Map.Entry)o;
 880             return e.getKey()   == getKey() &&
 881                    e.getValue() == getValue();
 882         }
 883 
 884         public int hashCode() {
 885             if (lastReturnedIndex < 0)
 886                 return super.hashCode();
 887 
 888             return System.identityHashCode(getKey()) ^
 889                    System.identityHashCode(getValue());
 890         }
 891 
 892         public String toString() {
 893             if (lastReturnedIndex < 0)
 894                 return super.toString();
 895 
 896             return getKey() + "=" + getValue();







 897         }
 898     }
 899 
 900     // Views
 901 
 902     /**
 903      * This field is initialized to contain an instance of the entry set
 904      * view the first time this view is requested.  The view is stateless,
 905      * so there's no reason to create more than one.
 906      */
 907     private transient Set<Map.Entry<K,V>> entrySet = null;
 908 
 909     /**
 910      * Returns an identity-based set view of the keys contained in this map.
 911      * The set is backed by the map, so changes to the map are reflected in
 912      * the set, and vice-versa.  If the map is modified while an iteration
 913      * over the set is in progress, the results of the iteration are
 914      * undefined.  The set supports element removal, which removes the
 915      * corresponding mapping from the map, via the <tt>Iterator.remove</tt>,
 916      * <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt>, and


   1 /*
   2  * Copyright (c) 2000, 2011, 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


 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 
 904             private void checkIndexForEntryUse() {
 905                 if (index < 0)
 906                     throw new IllegalStateException("Entry was removed");
 907             }
 908         }
 909     }
 910 
 911     // Views
 912 
 913     /**
 914      * This field is initialized to contain an instance of the entry set
 915      * view the first time this view is requested.  The view is stateless,
 916      * so there's no reason to create more than one.
 917      */
 918     private transient Set<Map.Entry<K,V>> entrySet = null;
 919 
 920     /**
 921      * Returns an identity-based set view of the keys contained in this map.
 922      * The set is backed by the map, so changes to the map are reflected in
 923      * the set, and vice-versa.  If the map is modified while an iteration
 924      * over the set is in progress, the results of the iteration are
 925      * undefined.  The set supports element removal, which removes the
 926      * corresponding mapping from the map, via the <tt>Iterator.remove</tt>,
 927      * <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt>, and