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