1 /* 2 * Copyright (c) 2015, 2018, 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 package sun.awt; 27 28 import java.lang.ref.Reference; 29 import java.lang.ref.ReferenceQueue; 30 import java.lang.ref.WeakReference; 31 import java.util.*; 32 33 // A weak key reference hash map that uses System.identityHashCode() and "==" 34 // instead of hashCode() and equals(Object) 35 class WeakIdentityHashMap<K, V> implements Map<K, V> { 36 private final Map<WeakKey<K>, V> map; 37 private final transient ReferenceQueue<K> queue = new ReferenceQueue<K>(); 38 39 /** 40 * Constructs a new, empty identity hash map with a default initial 41 * size (16). 42 */ WeakIdentityHashMap()43 public WeakIdentityHashMap() { 44 map = new HashMap<>(16); 45 } 46 47 /** 48 * Constructs a new, empty identity map with the specified initial size. 49 */ WeakIdentityHashMap(int initialSize)50 public WeakIdentityHashMap(int initialSize) { 51 map = new HashMap<>(initialSize); 52 } 53 getMap()54 private Map<WeakKey<K>, V> getMap() { 55 for(Reference<? extends K> ref; (ref = this.queue.poll()) != null;) { 56 map.remove(ref); 57 } 58 return map; 59 } 60 61 @Override size()62 public int size() { 63 return getMap().size(); 64 } 65 66 @Override isEmpty()67 public boolean isEmpty() { 68 return getMap().isEmpty(); 69 } 70 71 @Override containsKey(Object key)72 public boolean containsKey(Object key) { 73 return getMap().containsKey(new WeakKey<>(key, null)); 74 } 75 76 @Override containsValue(Object value)77 public boolean containsValue(Object value) { 78 return getMap().containsValue(value); 79 } 80 81 @Override get(Object key)82 public V get(Object key) { 83 return getMap().get(new WeakKey<>(key, null)); 84 } 85 86 @Override put(K key, V value)87 public V put(K key, V value) { 88 return getMap().put(new WeakKey<K>(key, queue), value); 89 } 90 91 @Override remove(Object key)92 public V remove(Object key) { 93 return getMap().remove(new WeakKey<>(key, null)); 94 } 95 96 @Override putAll(Map<? extends K, ? extends V> m)97 public void putAll(Map<? extends K, ? extends V> m) { 98 for (Entry<? extends K, ? extends V> entry : m.entrySet()) { 99 put(entry.getKey(), entry.getValue()); 100 } 101 } 102 103 @Override clear()104 public void clear() { 105 getMap().clear(); 106 } 107 108 @Override keySet()109 public Set<K> keySet() { 110 return new AbstractSet<K>() { 111 @Override 112 public Iterator<K> iterator() { 113 return new Iterator<K>() { 114 private K next; 115 Iterator<WeakKey<K>> iterator = getMap().keySet().iterator(); 116 117 @Override 118 public boolean hasNext() { 119 while (iterator.hasNext()) { 120 if ((next = iterator.next().get()) != null) { 121 return true; 122 } 123 } 124 return false; 125 } 126 127 @Override 128 public K next() { 129 if(next == null && !hasNext()) { 130 throw new NoSuchElementException(); 131 } 132 K ret = next; 133 next = null; 134 return ret; 135 } 136 }; 137 } 138 139 @Override 140 public int size() { 141 return getMap().keySet().size(); 142 } 143 }; 144 } 145 146 @Override 147 public Collection<V> values() { 148 return getMap().values(); 149 } 150 151 @Override 152 public Set<Entry<K, V>> entrySet() { 153 return new AbstractSet<Entry<K, V>>() { 154 @Override 155 public Iterator<Entry<K, V>> iterator() { 156 final Iterator<Entry<WeakKey<K>, V>> iterator = getMap().entrySet().iterator(); 157 return new Iterator<Entry<K, V>>() { 158 @Override 159 public boolean hasNext() { 160 return iterator.hasNext(); 161 } 162 163 @Override 164 public Entry<K, V> next() { 165 return new Entry<K, V>() { 166 Entry<WeakKey<K>, V> entry = iterator.next(); 167 168 @Override 169 public K getKey() { 170 return entry.getKey().get(); 171 } 172 173 @Override 174 public V getValue() { 175 return entry.getValue(); 176 } 177 178 @Override 179 public V setValue(V value) { 180 return null; 181 } 182 }; 183 } 184 }; 185 } 186 187 @Override 188 public int size() { 189 return getMap().entrySet().size(); 190 } 191 }; 192 } 193 194 private static class WeakKey<K> extends WeakReference<K> { 195 private final int hash; 196 197 WeakKey(K key, ReferenceQueue <K> q) { 198 super(key, q); 199 hash = System.identityHashCode(key); 200 } 201 202 @Override 203 public boolean equals(Object o) { 204 if(this == o) { 205 return true; 206 } else if( o instanceof WeakKey ) { 207 return get() == ((WeakKey)o).get(); 208 } else { 209 return false; 210 } 211 } 212 213 @Override 214 public int hashCode() { 215 return hash; 216 } 217 } 218 219 220 } 221