1 /* 2 * Copyright (c) 2016, 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 package java.lang.reflect; 26 27 import java.lang.ref.Reference; 28 import java.lang.ref.ReferenceQueue; 29 import java.lang.ref.WeakReference; 30 import java.util.Collection; 31 import java.util.Objects; 32 import java.util.concurrent.ConcurrentHashMap; 33 import java.util.function.BiFunction; 34 35 /** 36 * A WeakHashMap-like data structure that uses a pair of weakly-reachable keys 37 * with identity equality semantics to associate a strongly-reachable value. 38 * Unlike WeakHashMap, this data structure is thread-safe. 39 * 40 * @param <T> the type of 1st keys 41 * @param <U> the type of 2nd keys 42 * @param <V> the type of values 43 * 44 * @author Peter Levart 45 */ 46 final class WeakPairMap<T, U, V> { 47 48 private final ConcurrentHashMap<Pair<T, U>, V> map = new ConcurrentHashMap<>(); 49 private final ReferenceQueue<Object> queue = new ReferenceQueue<>(); 50 51 public boolean constainsKeyPair(T t, U u) { 52 expungeStaleAssociations(); 53 return map.containsKey(Pair.lookup(t, u)); 54 } 55 56 public V get(T t, U u) { 57 expungeStaleAssociations(); 58 return map.get(Pair.lookup(t, u)); 59 } 60 61 public V put(T t, U u, V v) { 62 expungeStaleAssociations(); 63 return map.put(Pair.weak(t, u, queue), v); 64 } 65 66 public V putIfAbsent(T t, U u, V v) { 67 expungeStaleAssociations(); 68 return map.putIfAbsent(Pair.weak(t, u, queue), v); 69 } 70 71 public V computeIfAbsent(T t, U u, 72 BiFunction<? super T, ? super U, ? extends V> 73 mappingFunction) { 74 expungeStaleAssociations(); 75 try { 76 return map.computeIfAbsent( 77 Pair.weak(t, u, queue), 78 pair -> mappingFunction.apply(pair.first(), pair.second())); 79 } finally { 80 Reference.reachabilityFence(t); 81 Reference.reachabilityFence(u); 82 } 83 } 84 85 public Collection<V> values() { 86 expungeStaleAssociations(); 87 return map.values(); 88 } 89 90 private void expungeStaleAssociations() { 91 Pair.Weak<?, ?> key; 92 while ((key = (Pair.Weak<?, ?>) queue.poll()) != null) { 93 // any peer can get cleared and enqueued, but 94 // only primary peers are keys in the map 95 map.remove(key.primaryPeer()); 96 } 97 } 98 99 private interface Pair<T, U> { 100 101 static <T, U> Pair<T, U> lookup(T t, U u) { 102 return new Lookup<>(t, u); 103 } 104 105 static <T, U> Pair<T, U> weak(T t, U u, ReferenceQueue<Object> queue) { 106 return new Weak.Primary<>(t, u, queue); 107 } 108 109 T first(); 110 111 U second(); 112 113 static boolean equals(Pair<?, ?> p1, Pair<?, ?> p2) { 114 if (p1 == p2) { 115 return true; 116 } 117 Object p1First = p1.first(); 118 Object p1Second = p1.second(); 119 return p1First != null && p1Second != null && 120 p1First == p2.first() && p1Second == p2.second(); 121 } 122 123 static int hashCode(Object first, Object second) { 124 return System.identityHashCode(first) ^ 125 System.identityHashCode(second); 126 } 127 128 abstract class Weak<T, U> extends WeakReference<T> implements Pair<T, U> { 129 130 Weak(T t, ReferenceQueue<Object> queue) { 131 super(Objects.requireNonNull(t), queue); 132 } 133 134 abstract Primary<?, ?> primaryPeer(); 135 136 abstract Weak<U, T> peer(); 137 138 @Override 139 public T first() { 140 return get(); 141 } 142 143 @Override 144 public U second() { 145 return peer().get(); 146 } 147 148 @Override 149 public boolean equals(Object obj) { 150 return obj instanceof Pair && 151 Pair.equals(this, (Pair<?, ?>) obj); 152 } 153 154 static final class Primary<T, U> extends Weak<T, U> { 155 156 final int hash; 157 final Secondary<U, T> secondary; 158 159 Primary(T t, U u, ReferenceQueue<Object> queue) { 160 super(t, queue); 161 hash = Pair.hashCode(t, u); 162 secondary = new Secondary<>(u, queue, this); 163 } 164 165 @Override 166 Primary<?, ?> primaryPeer() { 167 return this; 168 } 169 170 @Override 171 Weak<U, T> peer() { 172 return secondary; 173 } 174 175 @Override 176 public int hashCode() { 177 return hash; 178 } 179 } 180 181 static final class Secondary<T, U> extends Weak<T, U> { 182 183 final Primary<U, T> primary; 184 185 Secondary(T t, ReferenceQueue<Object> queue, Primary<U, T> primary) { 186 super(t, queue); 187 this.primary = primary; 188 } 189 190 @Override 191 Primary<?, ?> primaryPeer() { 192 return primary; 193 } 194 195 @Override 196 Weak<U, T> peer() { 197 return primary; 198 } 199 200 @Override 201 public int hashCode() { 202 return primary.hash; 203 } 204 } 205 } 206 207 final class Lookup<T, U> implements Pair<T, U> { 208 private final T t; 209 private final U u; 210 211 Lookup(T t, U u) { 212 this.t = Objects.requireNonNull(t); 213 this.u = Objects.requireNonNull(u); 214 } 215 216 @Override 217 public T first() { 218 return t; 219 } 220 221 @Override 222 public U second() { 223 return u; 224 } 225 226 @Override 227 public int hashCode() { 228 return Pair.hashCode(t, u); 229 } 230 231 @Override 232 public boolean equals(Object obj) { 233 return obj instanceof Pair && 234 Pair.equals(this, (Pair<?, ?>) obj); 235 } 236 } 237 } 238 }