1 /* 2 * Copyright (C) 2007 Google Inc. 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 com.google.common.annotations.GwtCompatible; 20 import com.google.common.base.Objects; 21 import static com.google.common.base.Preconditions.checkArgument; 22 import static com.google.common.base.Preconditions.checkState; 23 24 import java.io.IOException; 25 import java.io.ObjectInputStream; 26 import java.io.ObjectOutputStream; 27 import java.io.Serializable; 28 import java.util.Collection; 29 import java.util.Iterator; 30 import java.util.Map; 31 import java.util.Set; 32 33 import javax.annotation.Nullable; 34 35 /** 36 * A general-purpose bimap implementation using any two backing {@code Map} 37 * instances. 38 * 39 * <p>Note that this class contains {@code equals()} calls that keep it from 40 * supporting {@code IdentityHashMap} backing maps. 41 * 42 * @author Kevin Bourrillion 43 * @author Mike Bostock 44 */ 45 @GwtCompatible 46 abstract class AbstractBiMap<K, V> extends ForwardingMap<K, V> 47 implements BiMap<K, V>, Serializable { 48 49 private transient Map<K, V> delegate; 50 private transient AbstractBiMap<V, K> inverse; 51 52 /** Package-private constructor for creating a map-backed bimap. */ 53 AbstractBiMap(Map<K, V> forward, Map<V, K> backward) { 54 setDelegates(forward, backward); 55 } 56 57 /** Private constructor for inverse bimap. */ 58 private AbstractBiMap(Map<K, V> backward, AbstractBiMap<V, K> forward) { 59 delegate = backward; 60 inverse = forward; 61 } 62 63 @Override protected Map<K, V> delegate() { 64 return delegate; 65 } 66 67 /** 68 * Specifies the delegate maps going in each direction. Called by the 69 * constructor and by subclasses during deserialization. 70 */ 71 void setDelegates(Map<K, V> forward, Map<V, K> backward) { 72 checkState(delegate == null); 73 checkState(inverse == null); 74 checkArgument(forward.isEmpty()); 75 checkArgument(backward.isEmpty()); 76 checkArgument(forward != backward); 77 delegate = forward; 78 inverse = new Inverse<V, K>(backward, this); 79 } 80 81 void setInverse(AbstractBiMap<V, K> inverse) { 82 this.inverse = inverse; 83 } 84 85 // Query Operations (optimizations) 86 87 @Override public boolean containsValue(Object value) { 88 return inverse.containsKey(value); 89 } 90 91 // Modification Operations 92 93 @Override public V put(K key, V value) { 94 return putInBothMaps(key, value, false); 95 } 96 97 public V forcePut(K key, V value) { 98 return putInBothMaps(key, value, true); 99 } 100 101 private V putInBothMaps(@Nullable K key, @Nullable V value, boolean force) { 102 boolean containedKey = containsKey(key); 103 if (containedKey && Objects.equal(value, get(key))) { 104 return value; 105 } 106 if (force) { 107 inverse().remove(value); 108 } else { 109 checkArgument(!containsValue(value), "value already present: %s", value); 110 } 111 V oldValue = delegate.put(key, value); 112 updateInverseMap(key, containedKey, oldValue, value); 113 return oldValue; 114 } 115 116 private void updateInverseMap( 117 K key, boolean containedKey, V oldValue, V newValue) { 118 if (containedKey) { 119 removeFromInverseMap(oldValue); 120 } 121 inverse.delegate.put(newValue, key); 122 } 123 124 @Override public V remove(Object key) { 125 return containsKey(key) ? removeFromBothMaps(key) : null; 126 } 127 128 private V removeFromBothMaps(Object key) { 129 V oldValue = delegate.remove(key); 130 removeFromInverseMap(oldValue); 131 return oldValue; 132 } 133 134 private void removeFromInverseMap(V oldValue) { 135 inverse.delegate.remove(oldValue); 136 } 137 138 // Bulk Operations 139 140 @Override public void putAll(Map<? extends K, ? extends V> map) { 141 for (Entry<? extends K, ? extends V> entry : map.entrySet()) { 142 put(entry.getKey(), entry.getValue()); 143 } 144 } 145 146 @Override public void clear() { 147 delegate.clear(); 148 inverse.delegate.clear(); 149 } 150 151 // Views 152 153 public BiMap<V, K> inverse() { 154 return inverse; 155 } 156 157 private transient Set<K> keySet; 158 159 @Override public Set<K> keySet() { 160 Set<K> result = keySet; 161 return (result == null) ? keySet = new KeySet() : result; 162 } 163 164 private class KeySet extends ForwardingSet<K> { 165 @Override protected Set<K> delegate() { 166 return delegate.keySet(); 167 } 168 169 @Override public void clear() { 170 AbstractBiMap.this.clear(); 171 } 172 173 @Override public boolean remove(Object key) { 174 if (!contains(key)) { 175 return false; 176 } 177 removeFromBothMaps(key); 178 return true; 179 } 180 181 @Override public boolean removeAll(Collection<?> keysToRemove) { 182 return Iterators.removeAll(iterator(), keysToRemove); 183 } 184 185 @Override public boolean retainAll(Collection<?> keysToRetain) { 186 return Iterators.retainAll(iterator(), keysToRetain); 187 } 188 189 @Override public Iterator<K> iterator() { 190 final Iterator<Entry<K, V>> iterator = delegate.entrySet().iterator(); 191 return new Iterator<K>() { 192 Entry<K, V> entry; 193 194 public boolean hasNext() { 195 return iterator.hasNext(); 196 } 197 public K next() { 198 entry = iterator.next(); 199 return entry.getKey(); 200 } 201 public void remove() { 202 checkState(entry != null); 203 V value = entry.getValue(); 204 iterator.remove(); 205 removeFromInverseMap(value); 206 } 207 }; 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 final Iterator<V> iterator = delegate.values().iterator(); 231 return new Iterator<V>() { 232 V valueToRemove; 233 234 /*@Override*/ public boolean hasNext() { 235 return iterator.hasNext(); 236 } 237 238 /*@Override*/ public V next() { 239 return valueToRemove = iterator.next(); 240 } 241 242 /*@Override*/ public void remove() { 243 iterator.remove(); 244 removeFromInverseMap(valueToRemove); 245 } 246 }; 247 } 248 249 @Override public Object[] toArray() { 250 return ObjectArrays.toArrayImpl(this); 251 } 252 253 @Override public <T> T[] toArray(T[] array) { 254 return ObjectArrays.toArrayImpl(this, array); 255 } 256 257 @Override public String toString() { 258 return Iterators.toString(iterator()); 259 } 260 } 261 262 private transient Set<Entry<K, V>> entrySet; 263 264 @Override public Set<Entry<K, V>> entrySet() { 265 Set<Entry<K, V>> result = entrySet; 266 return (result == null) ? entrySet = new EntrySet() : result; 267 } 268 269 private class EntrySet extends ForwardingSet<Entry<K, V>> { 270 final Set<Entry<K, V>> esDelegate = delegate.entrySet(); 271 272 @Override protected Set<Entry<K, V>> delegate() { 273 return esDelegate; 274 } 275 276 @Override public void clear() { 277 AbstractBiMap.this.clear(); 278 } 279 280 @Override public boolean remove(Object object) { 281 if (!esDelegate.remove(object)) { 282 return false; 283 } 284 Entry<?, ?> entry = (Entry<?, ?>) object; 285 inverse.delegate.remove(entry.getValue()); 286 return true; 287 } 288 289 @Override public Iterator<Entry<K, V>> iterator() { 290 final Iterator<Entry<K, V>> iterator = esDelegate.iterator(); 291 return new Iterator<Entry<K, V>>() { 292 Entry<K, V> entry; 293 294 /*@Override*/ public boolean hasNext() { 295 return iterator.hasNext(); 296 } 297 298 /*@Override*/ public Entry<K, V> next() { 299 entry = iterator.next(); 300 final Entry<K, V> finalEntry = entry; 301 302 return new ForwardingMapEntry<K, V>() { 303 @Override protected Entry<K, V> delegate() { 304 return finalEntry; 305 } 306 307 @Override public V setValue(V value) { 308 // Preconditions keep the map and inverse consistent. 309 checkState(contains(this), "entry no longer in map"); 310 // similar to putInBothMaps, but set via entry 311 if (Objects.equal(value, getValue())) { 312 return value; 313 } 314 checkArgument(!containsValue(value), 315 "value already present: %s", value); 316 V oldValue = finalEntry.setValue(value); 317 checkState(Objects.equal(value, get(getKey())), 318 "entry no longer in map"); 319 updateInverseMap(getKey(), true, oldValue, value); 320 return oldValue; 321 } 322 }; 323 } 324 325 /*@Override*/ public void remove() { 326 checkState(entry != null); 327 V value = entry.getValue(); 328 iterator.remove(); 329 removeFromInverseMap(value); 330 } 331 }; 332 } 333 334 // See java.util.Collections.CheckedEntrySet for details on attacks. 335 336 @Override public Object[] toArray() { 337 return ObjectArrays.toArrayImpl(this); 338 } 339 @Override public <T> T[] toArray(T[] array) { 340 return ObjectArrays.toArrayImpl(this, array); 341 } 342 @Override public boolean contains(Object o) { 343 return Maps.containsEntryImpl(delegate(), o); 344 } 345 @Override public boolean containsAll(Collection<?> c) { 346 return Collections2.containsAll(this, c); 347 } 348 @Override public boolean removeAll(Collection<?> c) { 349 return Iterators.removeAll(iterator(), c); 350 } 351 @Override public boolean retainAll(Collection<?> c) { 352 return Iterators.retainAll(iterator(), c); 353 } 354 } 355 356 /** The inverse of any other {@code AbstractBiMap} subclass. */ 357 private static class Inverse<K, V> extends AbstractBiMap<K, V> { 358 private Inverse(Map<K, V> backward, AbstractBiMap<V, K> forward) { 359 super(backward, forward); 360 } 361 362 /* 363 * Serialization stores the forward bimap, the inverse of this inverse. 364 * Deserialization calls inverse() on the forward bimap and returns that 365 * inverse. 366 * 367 * If a bimap and its inverse are serialized together, the deserialized 368 * instances have inverse() methods that return the other. 369 */ 370 371 /** 372 * @serialData the forward bimap 373 */ 374 private void writeObject(ObjectOutputStream stream) throws IOException { 375 stream.defaultWriteObject(); 376 stream.writeObject(inverse()); 377 } 378 379 @SuppressWarnings("unchecked") // reading data stored by writeObject 380 private void readObject(ObjectInputStream stream) 381 throws IOException, ClassNotFoundException { 382 stream.defaultReadObject(); 383 setInverse((AbstractBiMap<V, K>) stream.readObject()); 384 } 385 386 Object readResolve() { 387 return inverse().inverse(); 388 } 389 390 private static final long serialVersionUID = 0; 391 } 392 393 private static final long serialVersionUID = 0; 394 } 395