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