001/* 002 * Copyright (C) 2007 The Guava Authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 005 * in compliance with the License. You may obtain a copy of the License at 006 * 007 * http://www.apache.org/licenses/LICENSE-2.0 008 * 009 * Unless required by applicable law or agreed to in writing, software distributed under the License 010 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 011 * or implied. See the License for the specific language governing permissions and limitations under 012 * the License. 013 */ 014 015package com.google.common.collect; 016 017import static com.google.common.base.Preconditions.checkArgument; 018import static com.google.common.collect.CollectPreconditions.checkRemove; 019 020import com.google.common.annotations.GwtCompatible; 021import com.google.common.annotations.GwtIncompatible; 022import com.google.common.base.Objects; 023 024import java.io.IOException; 025import java.io.ObjectInputStream; 026import java.io.ObjectOutputStream; 027import java.io.Serializable; 028import java.util.AbstractMap; 029import java.util.Arrays; 030import java.util.ConcurrentModificationException; 031import java.util.Iterator; 032import java.util.Map; 033import java.util.NoSuchElementException; 034import java.util.Set; 035 036import javax.annotation.Nullable; 037 038/** 039 * A {@link BiMap} backed by two hash tables. This implementation allows null keys and values. A 040 * {@code HashBiMap} and its inverse are both serializable. 041 * 042 * <p>See the Guava User Guide article on <a href= 043 * "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#BiMap"> {@code BiMap} 044 * </a>. 045 * 046 * @author Louis Wasserman 047 * @author Mike Bostock 048 * @since 2.0 (imported from Google Collections Library) 049 */ 050@GwtCompatible(emulated = true) 051public final class HashBiMap<K, V> extends AbstractMap<K, V> implements BiMap<K, V>, Serializable { 052 053 /** 054 * Returns a new, empty {@code HashBiMap} with the default initial capacity (16). 055 */ 056 public static <K, V> HashBiMap<K, V> create() { 057 return create(16); 058 } 059 060 /** 061 * Constructs a new, empty bimap with the specified expected size. 062 * 063 * @param expectedSize the expected number of entries 064 * @throws IllegalArgumentException if the specified expected size is negative 065 */ 066 public static <K, V> HashBiMap<K, V> create(int expectedSize) { 067 return new HashBiMap<K, V>(expectedSize); 068 } 069 070 /** 071 * Constructs a new bimap containing initial values from {@code map}. The bimap is created with an 072 * initial capacity sufficient to hold the mappings in the specified map. 073 */ 074 public static <K, V> HashBiMap<K, V> create(Map<? extends K, ? extends V> map) { 075 HashBiMap<K, V> bimap = create(map.size()); 076 bimap.putAll(map); 077 return bimap; 078 } 079 080 private static final class BiEntry<K, V> extends ImmutableEntry<K, V> { 081 final int keyHash; 082 final int valueHash; 083 084 @Nullable 085 BiEntry<K, V> nextInKToVBucket; 086 087 @Nullable 088 BiEntry<K, V> nextInVToKBucket; 089 090 BiEntry(K key, int keyHash, V value, int valueHash) { 091 super(key, value); 092 this.keyHash = keyHash; 093 this.valueHash = valueHash; 094 } 095 } 096 097 private static final double LOAD_FACTOR = 1.0; 098 099 private transient BiEntry<K, V>[] hashTableKToV; 100 private transient BiEntry<K, V>[] hashTableVToK; 101 private transient int size; 102 private transient int mask; 103 private transient int modCount; 104 105 private HashBiMap(int expectedSize) { 106 init(expectedSize); 107 } 108 109 private void init(int expectedSize) { 110 checkArgument(expectedSize >= 0, "expectedSize must be >= 0 but was %s", expectedSize); 111 int tableSize = Hashing.closedTableSize(expectedSize, LOAD_FACTOR); 112 this.hashTableKToV = createTable(tableSize); 113 this.hashTableVToK = createTable(tableSize); 114 this.mask = tableSize - 1; 115 this.modCount = 0; 116 this.size = 0; 117 } 118 119 /** 120 * Finds and removes {@code entry} from the bucket linked lists in both the 121 * key-to-value direction and the value-to-key direction. 122 */ 123 private void delete(BiEntry<K, V> entry) { 124 int keyBucket = entry.keyHash & mask; 125 BiEntry<K, V> prevBucketEntry = null; 126 for (BiEntry<K, V> bucketEntry = hashTableKToV[keyBucket]; true; 127 bucketEntry = bucketEntry.nextInKToVBucket) { 128 if (bucketEntry == entry) { 129 if (prevBucketEntry == null) { 130 hashTableKToV[keyBucket] = entry.nextInKToVBucket; 131 } else { 132 prevBucketEntry.nextInKToVBucket = entry.nextInKToVBucket; 133 } 134 break; 135 } 136 prevBucketEntry = bucketEntry; 137 } 138 139 int valueBucket = entry.valueHash & mask; 140 prevBucketEntry = null; 141 for (BiEntry<K, V> bucketEntry = hashTableVToK[valueBucket];; 142 bucketEntry = bucketEntry.nextInVToKBucket) { 143 if (bucketEntry == entry) { 144 if (prevBucketEntry == null) { 145 hashTableVToK[valueBucket] = entry.nextInVToKBucket; 146 } else { 147 prevBucketEntry.nextInVToKBucket = entry.nextInVToKBucket; 148 } 149 break; 150 } 151 prevBucketEntry = bucketEntry; 152 } 153 154 size--; 155 modCount++; 156 } 157 158 private void insert(BiEntry<K, V> entry) { 159 int keyBucket = entry.keyHash & mask; 160 entry.nextInKToVBucket = hashTableKToV[keyBucket]; 161 hashTableKToV[keyBucket] = entry; 162 163 int valueBucket = entry.valueHash & mask; 164 entry.nextInVToKBucket = hashTableVToK[valueBucket]; 165 hashTableVToK[valueBucket] = entry; 166 167 size++; 168 modCount++; 169 } 170 171 private static int hash(@Nullable Object o) { 172 return Hashing.smear((o == null) ? 0 : o.hashCode()); 173 } 174 175 private BiEntry<K, V> seekByKey(@Nullable Object key, int keyHash) { 176 for (BiEntry<K, V> entry = hashTableKToV[keyHash & mask]; entry != null; 177 entry = entry.nextInKToVBucket) { 178 if (keyHash == entry.keyHash && Objects.equal(key, entry.key)) { 179 return entry; 180 } 181 } 182 return null; 183 } 184 185 private BiEntry<K, V> seekByValue(@Nullable Object value, int valueHash) { 186 for (BiEntry<K, V> entry = hashTableVToK[valueHash & mask]; entry != null; 187 entry = entry.nextInVToKBucket) { 188 if (valueHash == entry.valueHash && Objects.equal(value, entry.value)) { 189 return entry; 190 } 191 } 192 return null; 193 } 194 195 @Override 196 public boolean containsKey(@Nullable Object key) { 197 return seekByKey(key, hash(key)) != null; 198 } 199 200 @Override 201 public boolean containsValue(@Nullable Object value) { 202 return seekByValue(value, hash(value)) != null; 203 } 204 205 @Nullable 206 @Override 207 public V get(@Nullable Object key) { 208 BiEntry<K, V> entry = seekByKey(key, hash(key)); 209 return (entry == null) ? null : entry.value; 210 } 211 212 @Override 213 public V put(@Nullable K key, @Nullable V value) { 214 return put(key, value, false); 215 } 216 217 @Override 218 public V forcePut(@Nullable K key, @Nullable V value) { 219 return put(key, value, true); 220 } 221 222 private V put(@Nullable K key, @Nullable V value, boolean force) { 223 int keyHash = hash(key); 224 int valueHash = hash(value); 225 226 BiEntry<K, V> oldEntryForKey = seekByKey(key, keyHash); 227 if (oldEntryForKey != null && valueHash == oldEntryForKey.valueHash 228 && Objects.equal(value, oldEntryForKey.value)) { 229 return value; 230 } 231 232 BiEntry<K, V> oldEntryForValue = seekByValue(value, valueHash); 233 if (oldEntryForValue != null) { 234 if (force) { 235 delete(oldEntryForValue); 236 } else { 237 throw new IllegalArgumentException("value already present: " + value); 238 } 239 } 240 241 if (oldEntryForKey != null) { 242 delete(oldEntryForKey); 243 } 244 BiEntry<K, V> newEntry = new BiEntry<K, V>(key, keyHash, value, valueHash); 245 insert(newEntry); 246 rehashIfNecessary(); 247 return (oldEntryForKey == null) ? null : oldEntryForKey.value; 248 } 249 250 @Nullable 251 private K putInverse(@Nullable V value, @Nullable K key, boolean force) { 252 int valueHash = hash(value); 253 int keyHash = hash(key); 254 255 BiEntry<K, V> oldEntryForValue = seekByValue(value, valueHash); 256 if (oldEntryForValue != null && keyHash == oldEntryForValue.keyHash 257 && Objects.equal(key, oldEntryForValue.key)) { 258 return key; 259 } 260 261 BiEntry<K, V> oldEntryForKey = seekByKey(key, keyHash); 262 if (oldEntryForKey != null) { 263 if (force) { 264 delete(oldEntryForKey); 265 } else { 266 throw new IllegalArgumentException("value already present: " + key); 267 } 268 } 269 270 if (oldEntryForValue != null) { 271 delete(oldEntryForValue); 272 } 273 BiEntry<K, V> newEntry = new BiEntry<K, V>(key, keyHash, value, valueHash); 274 insert(newEntry); 275 rehashIfNecessary(); 276 return (oldEntryForValue == null) ? null : oldEntryForValue.key; 277 } 278 279 private void rehashIfNecessary() { 280 BiEntry<K, V>[] oldKToV = hashTableKToV; 281 if (Hashing.needsResizing(size, oldKToV.length, LOAD_FACTOR)) { 282 int newTableSize = oldKToV.length * 2; 283 284 this.hashTableKToV = createTable(newTableSize); 285 this.hashTableVToK = createTable(newTableSize); 286 this.mask = newTableSize - 1; 287 this.size = 0; 288 289 for (int bucket = 0; bucket < oldKToV.length; bucket++) { 290 BiEntry<K, V> entry = oldKToV[bucket]; 291 while (entry != null) { 292 BiEntry<K, V> nextEntry = entry.nextInKToVBucket; 293 insert(entry); 294 entry = nextEntry; 295 } 296 } 297 this.modCount++; 298 } 299 } 300 301 @SuppressWarnings("unchecked") 302 private BiEntry<K, V>[] createTable(int length) { 303 return new BiEntry[length]; 304 } 305 306 @Override 307 public V remove(@Nullable Object key) { 308 BiEntry<K, V> entry = seekByKey(key, hash(key)); 309 if (entry == null) { 310 return null; 311 } else { 312 delete(entry); 313 return entry.value; 314 } 315 } 316 317 @Override 318 public void clear() { 319 size = 0; 320 Arrays.fill(hashTableKToV, null); 321 Arrays.fill(hashTableVToK, null); 322 modCount++; 323 } 324 325 @Override 326 public int size() { 327 return size; 328 } 329 330 abstract class Itr<T> implements Iterator<T> { 331 int nextBucket = 0; 332 BiEntry<K, V> next = null; 333 BiEntry<K, V> toRemove = null; 334 int expectedModCount = modCount; 335 336 private void checkForConcurrentModification() { 337 if (modCount != expectedModCount) { 338 throw new ConcurrentModificationException(); 339 } 340 } 341 342 @Override 343 public boolean hasNext() { 344 checkForConcurrentModification(); 345 if (next != null) { 346 return true; 347 } 348 while (nextBucket < hashTableKToV.length) { 349 if (hashTableKToV[nextBucket] != null) { 350 next = hashTableKToV[nextBucket++]; 351 return true; 352 } 353 nextBucket++; 354 } 355 return false; 356 } 357 358 @Override 359 public T next() { 360 checkForConcurrentModification(); 361 if (!hasNext()) { 362 throw new NoSuchElementException(); 363 } 364 365 BiEntry<K, V> entry = next; 366 next = entry.nextInKToVBucket; 367 toRemove = entry; 368 return output(entry); 369 } 370 371 @Override 372 public void remove() { 373 checkForConcurrentModification(); 374 checkRemove(toRemove != null); 375 delete(toRemove); 376 expectedModCount = modCount; 377 toRemove = null; 378 } 379 380 abstract T output(BiEntry<K, V> entry); 381 } 382 383 @Override 384 public Set<K> keySet() { 385 return new KeySet(); 386 } 387 388 private final class KeySet extends Maps.KeySet<K, V> { 389 KeySet() { 390 super(HashBiMap.this); 391 } 392 393 @Override 394 public Iterator<K> iterator() { 395 return new Itr<K>() { 396 @Override 397 K output(BiEntry<K, V> entry) { 398 return entry.key; 399 } 400 }; 401 } 402 403 @Override 404 public boolean remove(@Nullable Object o) { 405 BiEntry<K, V> entry = seekByKey(o, hash(o)); 406 if (entry == null) { 407 return false; 408 } else { 409 delete(entry); 410 return true; 411 } 412 } 413 } 414 415 @Override 416 public Set<V> values() { 417 return inverse().keySet(); 418 } 419 420 @Override 421 public Set<Entry<K, V>> entrySet() { 422 return new EntrySet(); 423 } 424 425 private final class EntrySet extends Maps.EntrySet<K, V> { 426 @Override 427 Map<K, V> map() { 428 return HashBiMap.this; 429 } 430 431 @Override 432 public Iterator<Entry<K, V>> iterator() { 433 return new Itr<Entry<K, V>>() { 434 @Override 435 Entry<K, V> output(BiEntry<K, V> entry) { 436 return new MapEntry(entry); 437 } 438 439 class MapEntry extends AbstractMapEntry<K, V> { 440 BiEntry<K, V> delegate; 441 442 MapEntry(BiEntry<K, V> entry) { 443 this.delegate = entry; 444 } 445 446 @Override public K getKey() { 447 return delegate.key; 448 } 449 450 @Override public V getValue() { 451 return delegate.value; 452 } 453 454 @Override public V setValue(V value) { 455 V oldValue = delegate.value; 456 int valueHash = hash(value); 457 if (valueHash == delegate.valueHash && Objects.equal(value, oldValue)) { 458 return value; 459 } 460 checkArgument( 461 seekByValue(value, valueHash) == null, "value already present: %s", value); 462 delete(delegate); 463 BiEntry<K, V> newEntry = 464 new BiEntry<K, V>(delegate.key, delegate.keyHash, value, valueHash); 465 insert(newEntry); 466 expectedModCount = modCount; 467 if (toRemove == delegate) { 468 toRemove = newEntry; 469 } 470 delegate = newEntry; 471 return oldValue; 472 } 473 } 474 }; 475 } 476 } 477 478 private transient BiMap<V, K> inverse; 479 480 @Override 481 public BiMap<V, K> inverse() { 482 return (inverse == null) ? inverse = new Inverse() : inverse; 483 } 484 485 private final class Inverse extends AbstractMap<V, K> implements BiMap<V, K>, Serializable { 486 BiMap<K, V> forward() { 487 return HashBiMap.this; 488 } 489 490 @Override 491 public int size() { 492 return size; 493 } 494 495 @Override 496 public void clear() { 497 forward().clear(); 498 } 499 500 @Override 501 public boolean containsKey(@Nullable Object value) { 502 return forward().containsValue(value); 503 } 504 505 @Override 506 public K get(@Nullable Object value) { 507 BiEntry<K, V> entry = seekByValue(value, hash(value)); 508 return (entry == null) ? null : entry.key; 509 } 510 511 @Override 512 public K put(@Nullable V value, @Nullable K key) { 513 return putInverse(value, key, false); 514 } 515 516 @Override 517 public K forcePut(@Nullable V value, @Nullable K key) { 518 return putInverse(value, key, true); 519 } 520 521 @Override 522 public K remove(@Nullable Object value) { 523 BiEntry<K, V> entry = seekByValue(value, hash(value)); 524 if (entry == null) { 525 return null; 526 } else { 527 delete(entry); 528 return entry.key; 529 } 530 } 531 532 @Override 533 public BiMap<K, V> inverse() { 534 return forward(); 535 } 536 537 @Override 538 public Set<V> keySet() { 539 return new InverseKeySet(); 540 } 541 542 private final class InverseKeySet extends Maps.KeySet<V, K> { 543 InverseKeySet() { 544 super(Inverse.this); 545 } 546 547 @Override 548 public boolean remove(@Nullable Object o) { 549 BiEntry<K, V> entry = seekByValue(o, hash(o)); 550 if (entry == null) { 551 return false; 552 } else { 553 delete(entry); 554 return true; 555 } 556 } 557 558 @Override 559 public Iterator<V> iterator() { 560 return new Itr<V>() { 561 @Override V output(BiEntry<K, V> entry) { 562 return entry.value; 563 } 564 }; 565 } 566 } 567 568 @Override 569 public Set<K> values() { 570 return forward().keySet(); 571 } 572 573 @Override 574 public Set<Entry<V, K>> entrySet() { 575 return new Maps.EntrySet<V, K>() { 576 577 @Override 578 Map<V, K> map() { 579 return Inverse.this; 580 } 581 582 @Override 583 public Iterator<Entry<V, K>> iterator() { 584 return new Itr<Entry<V, K>>() { 585 @Override 586 Entry<V, K> output(BiEntry<K, V> entry) { 587 return new InverseEntry(entry); 588 } 589 590 class InverseEntry extends AbstractMapEntry<V, K> { 591 BiEntry<K, V> delegate; 592 593 InverseEntry(BiEntry<K, V> entry) { 594 this.delegate = entry; 595 } 596 597 @Override 598 public V getKey() { 599 return delegate.value; 600 } 601 602 @Override 603 public K getValue() { 604 return delegate.key; 605 } 606 607 @Override 608 public K setValue(K key) { 609 K oldKey = delegate.key; 610 int keyHash = hash(key); 611 if (keyHash == delegate.keyHash && Objects.equal(key, oldKey)) { 612 return key; 613 } 614 checkArgument(seekByKey(key, keyHash) == null, "value already present: %s", key); 615 delete(delegate); 616 BiEntry<K, V> newEntry = 617 new BiEntry<K, V>(key, keyHash, delegate.value, delegate.valueHash); 618 insert(newEntry); 619 expectedModCount = modCount; 620 // This is safe because entries can only get bumped up to earlier in the iteration, 621 // so they can't get revisited. 622 return oldKey; 623 } 624 } 625 }; 626 } 627 }; 628 } 629 630 Object writeReplace() { 631 return new InverseSerializedForm<K, V>(HashBiMap.this); 632 } 633 } 634 635 private static final class InverseSerializedForm<K, V> implements Serializable { 636 private final HashBiMap<K, V> bimap; 637 638 InverseSerializedForm(HashBiMap<K, V> bimap) { 639 this.bimap = bimap; 640 } 641 642 Object readResolve() { 643 return bimap.inverse(); 644 } 645 } 646 647 /** 648 * @serialData the number of entries, first key, first value, second key, second value, and so on. 649 */ 650 @GwtIncompatible("java.io.ObjectOutputStream") 651 private void writeObject(ObjectOutputStream stream) throws IOException { 652 stream.defaultWriteObject(); 653 Serialization.writeMap(this, stream); 654 } 655 656 @GwtIncompatible("java.io.ObjectInputStream") 657 private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { 658 stream.defaultReadObject(); 659 int size = Serialization.readCount(stream); 660 init(size); 661 Serialization.populateMap(this, stream, size); 662 } 663 664 @GwtIncompatible("Not needed in emulated source") 665 private static final long serialVersionUID = 0; 666}