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