1 /* 2 * Copyright (C) 2007 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.common.collect; 18 19 import static com.google.common.base.Preconditions.checkArgument; 20 import static com.google.common.base.Preconditions.checkState; 21 import static com.google.common.collect.CollectPreconditions.checkRemove; 22 23 import com.google.common.annotations.GwtCompatible; 24 import com.google.common.base.Objects; 25 26 import java.io.Serializable; 27 import java.util.Collection; 28 import java.util.Iterator; 29 import java.util.Map; 30 import java.util.Set; 31 32 import javax.annotation.Nullable; 33 34 /** 35 * A general-purpose bimap implementation using any two backing {@code Map} 36 * instances. 37 * 38 * <p>Note that this class contains {@code equals()} calls that keep it from 39 * supporting {@code IdentityHashMap} backing maps. 40 * 41 * @author Kevin Bourrillion 42 * @author Mike Bostock 43 */ 44 @GwtCompatible(emulated = true) 45 abstract class AbstractBiMap<K, V> extends ForwardingMap<K, V> 46 implements BiMap<K, V>, Serializable { 47 48 private transient Map<K, V> delegate; 49 transient AbstractBiMap<V, K> inverse; 50 51 /** Package-private constructor for creating a map-backed bimap. */ 52 AbstractBiMap(Map<K, V> forward, Map<V, K> backward) { 53 setDelegates(forward, backward); 54 } 55 56 /** Private constructor for inverse bimap. */ 57 private AbstractBiMap(Map<K, V> backward, AbstractBiMap<V, K> forward) { 58 delegate = backward; 59 inverse = forward; 60 } 61 62 @Override protected Map<K, V> delegate() { 63 return delegate; 64 } 65 66 /** 67 * Returns its input, or throws an exception if this is not a valid key. 68 */ 69 K checkKey(@Nullable K key) { 70 return key; 71 } 72 73 /** 74 * Returns its input, or throws an exception if this is not a valid value. 75 */ 76 V checkValue(@Nullable V value) { 77 return value; 78 } 79 80 /** 81 * Specifies the delegate maps going in each direction. Called by the 82 * constructor and by subclasses during deserialization. 83 */ 84 void setDelegates(Map<K, V> forward, Map<V, K> backward) { 85 checkState(delegate == null); 86 checkState(inverse == null); 87 checkArgument(forward.isEmpty()); 88 checkArgument(backward.isEmpty()); 89 checkArgument(forward != backward); 90 delegate = forward; 91 inverse = new Inverse<V, K>(backward, this); 92 } 93 94 void setInverse(AbstractBiMap<V, K> inverse) { 95 this.inverse = inverse; 96 } 97 98 // Query Operations (optimizations) 99 100 @Override public boolean containsValue(@Nullable Object value) { 101 return inverse.containsKey(value); 102 } 103 104 // Modification Operations 105 106 @Override public V put(@Nullable K key, @Nullable V value) { 107 return putInBothMaps(key, value, false); 108 } 109 110 @Override 111 public V forcePut(@Nullable K key, @Nullable V value) { 112 return putInBothMaps(key, value, true); 113 } 114 115 private V putInBothMaps(@Nullable K key, @Nullable V value, boolean force) { 116 checkKey(key); 117 checkValue(value); 118 boolean containedKey = containsKey(key); 119 if (containedKey && Objects.equal(value, get(key))) { 120 return value; 121 } 122 if (force) { 123 inverse().remove(value); 124 } else { 125 checkArgument(!containsValue(value), "value already present: %s", value); 126 } 127 V oldValue = delegate.put(key, value); 128 updateInverseMap(key, containedKey, oldValue, value); 129 return oldValue; 130 } 131 132 private void updateInverseMap( 133 K key, boolean containedKey, V oldValue, V newValue) { 134 if (containedKey) { 135 removeFromInverseMap(oldValue); 136 } 137 inverse.delegate.put(newValue, key); 138 } 139 140 @Override public V remove(@Nullable Object key) { 141 return containsKey(key) ? removeFromBothMaps(key) : null; 142 } 143 144 private V removeFromBothMaps(Object key) { 145 V oldValue = delegate.remove(key); 146 removeFromInverseMap(oldValue); 147 return oldValue; 148 } 149 150 private void removeFromInverseMap(V oldValue) { 151 inverse.delegate.remove(oldValue); 152 } 153 154 // Bulk Operations 155 156 @Override public void putAll(Map<? extends K, ? extends V> map) { 157 for (Entry<? extends K, ? extends V> entry : map.entrySet()) { 158 put(entry.getKey(), entry.getValue()); 159 } 160 } 161 162 @Override public void clear() { 163 delegate.clear(); 164 inverse.delegate.clear(); 165 } 166 167 // Views 168 169 @Override 170 public BiMap<V, K> inverse() { 171 return inverse; 172 } 173 174 private transient Set<K> keySet; 175 176 @Override public Set<K> keySet() { 177 Set<K> result = keySet; 178 return (result == null) ? keySet = new KeySet() : result; 179 } 180 181 private class KeySet extends ForwardingSet<K> { 182 @Override protected Set<K> delegate() { 183 return delegate.keySet(); 184 } 185 186 @Override public void clear() { 187 AbstractBiMap.this.clear(); 188 } 189 190 @Override public boolean remove(Object key) { 191 if (!contains(key)) { 192 return false; 193 } 194 removeFromBothMaps(key); 195 return true; 196 } 197 198 @Override public boolean removeAll(Collection<?> keysToRemove) { 199 return standardRemoveAll(keysToRemove); 200 } 201 202 @Override public boolean retainAll(Collection<?> keysToRetain) { 203 return standardRetainAll(keysToRetain); 204 } 205 206 @Override public Iterator<K> iterator() { 207 return Maps.keyIterator(entrySet().iterator()); 208 } 209 } 210 211 private transient Set<V> valueSet; 212 213 @Override public Set<V> values() { 214 /* 215 * We can almost reuse the inverse's keySet, except we have to fix the 216 * iteration order so that it is consistent with the forward map. 217 */ 218 Set<V> result = valueSet; 219 return (result == null) ? valueSet = new ValueSet() : result; 220 } 221 222 private class ValueSet extends ForwardingSet<V> { 223 final Set<V> valuesDelegate = inverse.keySet(); 224 225 @Override protected Set<V> delegate() { 226 return valuesDelegate; 227 } 228 229 @Override public Iterator<V> iterator() { 230 return Maps.valueIterator(entrySet().iterator()); 231 } 232 233 @Override public Object[] toArray() { 234 return standardToArray(); 235 } 236 237 @Override public <T> T[] toArray(T[] array) { 238 return standardToArray(array); 239 } 240 241 @Override public String toString() { 242 return standardToString(); 243 } 244 } 245 246 private transient Set<Entry<K, V>> entrySet; 247 248 @Override public Set<Entry<K, V>> entrySet() { 249 Set<Entry<K, V>> result = entrySet; 250 return (result == null) ? entrySet = new EntrySet() : result; 251 } 252 253 private class EntrySet extends ForwardingSet<Entry<K, V>> { 254 final Set<Entry<K, V>> esDelegate = delegate.entrySet(); 255 256 @Override protected Set<Entry<K, V>> delegate() { 257 return esDelegate; 258 } 259 260 @Override public void clear() { 261 AbstractBiMap.this.clear(); 262 } 263 264 @Override public boolean remove(Object object) { 265 if (!esDelegate.contains(object)) { 266 return false; 267 } 268 269 // safe because esDelgate.contains(object). 270 Entry<?, ?> entry = (Entry<?, ?>) object; 271 inverse.delegate.remove(entry.getValue()); 272 /* 273 * Remove the mapping in inverse before removing from esDelegate because 274 * if entry is part of esDelegate, entry might be invalidated after the 275 * mapping is removed from esDelegate. 276 */ 277 esDelegate.remove(entry); 278 return true; 279 } 280 281 @Override public Iterator<Entry<K, V>> iterator() { 282 final Iterator<Entry<K, V>> iterator = esDelegate.iterator(); 283 return new Iterator<Entry<K, V>>() { 284 Entry<K, V> entry; 285 286 @Override public boolean hasNext() { 287 return iterator.hasNext(); 288 } 289 290 @Override public Entry<K, V> next() { 291 entry = iterator.next(); 292 final Entry<K, V> finalEntry = entry; 293 294 return new ForwardingMapEntry<K, V>() { 295 @Override protected Entry<K, V> delegate() { 296 return finalEntry; 297 } 298 299 @Override public V setValue(V value) { 300 // Preconditions keep the map and inverse consistent. 301 checkState(contains(this), "entry no longer in map"); 302 // similar to putInBothMaps, but set via entry 303 if (Objects.equal(value, getValue())) { 304 return value; 305 } 306 checkArgument(!containsValue(value), 307 "value already present: %s", value); 308 V oldValue = finalEntry.setValue(value); 309 checkState(Objects.equal(value, get(getKey())), 310 "entry no longer in map"); 311 updateInverseMap(getKey(), true, oldValue, value); 312 return oldValue; 313 } 314 }; 315 } 316 317 @Override public void remove() { 318 checkRemove(entry != null); 319 V value = entry.getValue(); 320 iterator.remove(); 321 removeFromInverseMap(value); 322 } 323 }; 324 } 325 326 // See java.util.Collections.CheckedEntrySet for details on attacks. 327 328 @Override public Object[] toArray() { 329 return standardToArray(); 330 } 331 @Override public <T> T[] toArray(T[] array) { 332 return standardToArray(array); 333 } 334 @Override public boolean contains(Object o) { 335 return Maps.containsEntryImpl(delegate(), o); 336 } 337 @Override public boolean containsAll(Collection<?> c) { 338 return standardContainsAll(c); 339 } 340 @Override public boolean removeAll(Collection<?> c) { 341 return standardRemoveAll(c); 342 } 343 @Override public boolean retainAll(Collection<?> c) { 344 return standardRetainAll(c); 345 } 346 } 347 348 /** The inverse of any other {@code AbstractBiMap} subclass. */ 349 private static class Inverse<K, V> extends AbstractBiMap<K, V> { 350 private Inverse(Map<K, V> backward, AbstractBiMap<V, K> forward) { 351 super(backward, forward); 352 } 353 354 /* 355 * Serialization stores the forward bimap, the inverse of this inverse. 356 * Deserialization calls inverse() on the forward bimap and returns that 357 * inverse. 358 * 359 * If a bimap and its inverse are serialized together, the deserialized 360 * instances have inverse() methods that return the other. 361 */ 362 363 @Override 364 K checkKey(K key) { 365 return inverse.checkValue(key); 366 } 367 368 @Override 369 V checkValue(V value) { 370 return inverse.checkKey(value); 371 } 372 } 373 } 374 375