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