1 /* 2 * Copyright (C) 2007 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.common.collect; 18 19 import com.google.common.annotations.GwtCompatible; 20 import com.google.common.base.Objects; 21 import com.google.common.base.Preconditions; 22 import static com.google.common.base.Preconditions.checkArgument; 23 import static com.google.common.base.Preconditions.checkState; 24 import static com.google.common.collect.Multisets.setCountImpl; 25 26 import java.io.IOException; 27 import java.io.ObjectInputStream; 28 import java.io.ObjectOutputStream; 29 import java.io.Serializable; 30 import java.util.AbstractCollection; 31 import java.util.AbstractMap; 32 import java.util.AbstractSequentialList; 33 import java.util.AbstractSet; 34 import java.util.Collection; 35 import static java.util.Collections.unmodifiableList; 36 import java.util.HashSet; 37 import java.util.Iterator; 38 import java.util.List; 39 import java.util.ListIterator; 40 import java.util.Map; 41 import java.util.Map.Entry; 42 import java.util.NoSuchElementException; 43 import java.util.Set; 44 45 import javax.annotation.Nullable; 46 47 /** 48 * An implementation of {@code ListMultimap} that supports deterministic 49 * iteration order for both keys and values. The iteration order is preserved 50 * across non-distinct key values. For example, for the following multimap 51 * definition: <pre> {@code 52 * 53 * Multimap<K, V> multimap = LinkedListMultimap.create(); 54 * multimap.put(key1, foo); 55 * multimap.put(key2, bar); 56 * multimap.put(key1, baz);}</pre> 57 * 58 * ... the iteration order for {@link #keys()} is {@code [key1, key2, key1]}, 59 * and similarly for {@link #entries()}. Unlike {@link LinkedHashMultimap}, the 60 * iteration order is kept consistent between keys, entries and values. For 61 * example, calling: <pre> {@code 62 * 63 * map.remove(key1, foo);}</pre> 64 * 65 * changes the entries iteration order to {@code [key2=bar, key1=baz]} and the 66 * key iteration order to {@code [key2, key1]}. The {@link #entries()} iterator 67 * returns mutable map entries, and {@link #replaceValues} attempts to preserve 68 * iteration order as much as possible. 69 * 70 * <p>The collections returned by {@link #keySet} and {@link #asMap} iterate 71 * through the keys in the order they were first added to the multimap. 72 * Similarly, {@link #get}, {@link #removeAll}, and {@link #replaceValues} 73 * return collections that iterate through the values in the order they were 74 * added. The collections generated by {@link #entries}, {@link #keys}, and 75 * {@link #values} iterate across the key-value mappings in the order they were 76 * added to the multimap. 77 * 78 * <p>Keys and values may be null. All optional multimap methods are supported, 79 * and all returned views are modifiable. 80 * 81 * <p>The methods {@link #get}, {@link #keySet}, {@link #keys}, {@link #values}, 82 * {@link #entries}, and {@link #asMap} return collections that are views of the 83 * multimap. If the multimap is modified while an iteration over any of those 84 * collections is in progress, except through the iterator's own {@code remove} 85 * operation, the results of the iteration are undefined. 86 * 87 * <p>This class is not threadsafe when any concurrent operations update the 88 * multimap. Concurrent read operations will work correctly. To allow concurrent 89 * update operations, wrap your multimap with a call to {@link 90 * Multimaps#synchronizedListMultimap}. 91 * 92 * @author Mike Bostock 93 * @since 2010.01.04 <b>stable</b> (imported from Google Collections Library) 94 */ 95 @GwtCompatible(serializable = true) 96 public final class LinkedListMultimap<K, V> 97 implements ListMultimap<K, V>, Serializable { 98 /* 99 * Order is maintained using a linked list containing all key-value pairs. In 100 * addition, a series of disjoint linked lists of "siblings", each containing 101 * the values for a specific key, is used to implement {@link 102 * ValueForKeyIterator} in constant time. 103 */ 104 105 private static final class Node<K, V> { 106 final K key; 107 V value; 108 Node<K, V> next; // the next node (with any key) 109 Node<K, V> previous; // the previous node (with any key) 110 Node<K, V> nextSibling; // the next node with the same key 111 Node<K, V> previousSibling; // the previous node with the same key 112 113 Node(@Nullable K key, @Nullable V value) { 114 this.key = key; 115 this.value = value; 116 } 117 118 @Override public String toString() { 119 return key + "=" + value; 120 } 121 } 122 123 private transient Node<K, V> head; // the head for all keys 124 private transient Node<K, V> tail; // the tail for all keys 125 private transient Multiset<K> keyCount; // the number of values for each key 126 private transient Map<K, Node<K, V>> keyToKeyHead; // the head for a given key 127 private transient Map<K, Node<K, V>> keyToKeyTail; // the tail for a given key 128 129 /** 130 * Creates a new, empty {@code LinkedListMultimap} with the default initial 131 * capacity. 132 */ 133 public static <K, V> LinkedListMultimap<K, V> create() { 134 return new LinkedListMultimap<K, V>(); 135 } 136 137 /** 138 * Constructs an empty {@code LinkedListMultimap} with enough capacity to hold 139 * the specified number of keys without rehashing. 140 * 141 * @param expectedKeys the expected number of distinct keys 142 * @throws IllegalArgumentException if {@code expectedKeys} is negative 143 */ 144 public static <K, V> LinkedListMultimap<K, V> create(int expectedKeys) { 145 return new LinkedListMultimap<K, V>(expectedKeys); 146 } 147 148 /** 149 * Constructs a {@code LinkedListMultimap} with the same mappings as the 150 * specified {@code Multimap}. The new multimap has the same 151 * {@link Multimap#entries()} iteration order as the input multimap. 152 * 153 * @param multimap the multimap whose contents are copied to this multimap 154 */ 155 public static <K, V> LinkedListMultimap<K, V> create( 156 Multimap<? extends K, ? extends V> multimap) { 157 return new LinkedListMultimap<K, V>(multimap); 158 } 159 160 private LinkedListMultimap() { 161 keyCount = LinkedHashMultiset.create(); 162 keyToKeyHead = Maps.newHashMap(); 163 keyToKeyTail = Maps.newHashMap(); 164 } 165 166 private LinkedListMultimap(int expectedKeys) { 167 keyCount = LinkedHashMultiset.create(expectedKeys); 168 keyToKeyHead = Maps.newHashMapWithExpectedSize(expectedKeys); 169 keyToKeyTail = Maps.newHashMapWithExpectedSize(expectedKeys); 170 } 171 172 private LinkedListMultimap(Multimap<? extends K, ? extends V> multimap) { 173 this(multimap.keySet().size()); 174 putAll(multimap); 175 } 176 177 /** 178 * Adds a new node for the specified key-value pair before the specified 179 * {@code nextSibling} element, or at the end of the list if {@code 180 * nextSibling} is null. Note: if {@code nextSibling} is specified, it MUST be 181 * for an node for the same {@code key}! 182 */ 183 private Node<K, V> addNode( 184 @Nullable K key, @Nullable V value, @Nullable Node<K, V> nextSibling) { 185 Node<K, V> node = new Node<K, V>(key, value); 186 if (head == null) { // empty list 187 head = tail = node; 188 keyToKeyHead.put(key, node); 189 keyToKeyTail.put(key, node); 190 } else if (nextSibling == null) { // non-empty list, add to tail 191 tail.next = node; 192 node.previous = tail; 193 Node<K, V> keyTail = keyToKeyTail.get(key); 194 if (keyTail == null) { // first for this key 195 keyToKeyHead.put(key, node); 196 } else { 197 keyTail.nextSibling = node; 198 node.previousSibling = keyTail; 199 } 200 keyToKeyTail.put(key, node); 201 tail = node; 202 } else { // non-empty list, insert before nextSibling 203 node.previous = nextSibling.previous; 204 node.previousSibling = nextSibling.previousSibling; 205 node.next = nextSibling; 206 node.nextSibling = nextSibling; 207 if (nextSibling.previousSibling == null) { // nextSibling was key head 208 keyToKeyHead.put(key, node); 209 } else { 210 nextSibling.previousSibling.nextSibling = node; 211 } 212 if (nextSibling.previous == null) { // nextSibling was head 213 head = node; 214 } else { 215 nextSibling.previous.next = node; 216 } 217 nextSibling.previous = node; 218 nextSibling.previousSibling = node; 219 } 220 keyCount.add(key); 221 return node; 222 } 223 224 /** 225 * Removes the specified node from the linked list. This method is only 226 * intended to be used from the {@code Iterator} classes. See also {@link 227 * LinkedListMultimap#removeAllNodes(Object)}. 228 */ 229 private void removeNode(Node<K, V> node) { 230 if (node.previous != null) { 231 node.previous.next = node.next; 232 } else { // node was head 233 head = node.next; 234 } 235 if (node.next != null) { 236 node.next.previous = node.previous; 237 } else { // node was tail 238 tail = node.previous; 239 } 240 if (node.previousSibling != null) { 241 node.previousSibling.nextSibling = node.nextSibling; 242 } else if (node.nextSibling != null) { // node was key head 243 keyToKeyHead.put(node.key, node.nextSibling); 244 } else { 245 keyToKeyHead.remove(node.key); // don't leak a key-null entry 246 } 247 if (node.nextSibling != null) { 248 node.nextSibling.previousSibling = node.previousSibling; 249 } else if (node.previousSibling != null) { // node was key tail 250 keyToKeyTail.put(node.key, node.previousSibling); 251 } else { 252 keyToKeyTail.remove(node.key); // don't leak a key-null entry 253 } 254 keyCount.remove(node.key); 255 } 256 257 /** Removes all nodes for the specified key. */ 258 private void removeAllNodes(@Nullable Object key) { 259 for (Iterator<V> i = new ValueForKeyIterator(key); i.hasNext();) { 260 i.next(); 261 i.remove(); 262 } 263 } 264 265 /** Helper method for verifying that an iterator element is present. */ 266 private static void checkElement(@Nullable Object node) { 267 if (node == null) { 268 throw new NoSuchElementException(); 269 } 270 } 271 272 /** An {@code Iterator} over all nodes. */ 273 private class NodeIterator implements Iterator<Node<K, V>> { 274 Node<K, V> next = head; 275 Node<K, V> current; 276 277 public boolean hasNext() { 278 return next != null; 279 } 280 public Node<K, V> next() { 281 checkElement(next); 282 current = next; 283 next = next.next; 284 return current; 285 } 286 public void remove() { 287 checkState(current != null); 288 removeNode(current); 289 current = null; 290 } 291 } 292 293 /** An {@code Iterator} over distinct keys in key head order. */ 294 private class DistinctKeyIterator implements Iterator<K> { 295 final Set<K> seenKeys = new HashSet<K>(Maps.capacity(keySet().size())); 296 Node<K, V> next = head; 297 Node<K, V> current; 298 299 public boolean hasNext() { 300 return next != null; 301 } 302 public K next() { 303 checkElement(next); 304 current = next; 305 seenKeys.add(current.key); 306 do { // skip ahead to next unseen key 307 next = next.next; 308 } while ((next != null) && !seenKeys.add(next.key)); 309 return current.key; 310 } 311 public void remove() { 312 checkState(current != null); 313 removeAllNodes(current.key); 314 current = null; 315 } 316 } 317 318 /** A {@code ListIterator} over values for a specified key. */ 319 private class ValueForKeyIterator implements ListIterator<V> { 320 final Object key; 321 int nextIndex; 322 Node<K, V> next; 323 Node<K, V> current; 324 Node<K, V> previous; 325 326 /** Constructs a new iterator over all values for the specified key. */ 327 ValueForKeyIterator(@Nullable Object key) { 328 this.key = key; 329 next = keyToKeyHead.get(key); 330 } 331 332 /** 333 * Constructs a new iterator over all values for the specified key starting 334 * at the specified index. This constructor is optimized so that it starts 335 * at either the head or the tail, depending on which is closer to the 336 * specified index. This allows adds to the tail to be done in constant 337 * time. 338 * 339 * @throws IndexOutOfBoundsException if index is invalid 340 */ 341 public ValueForKeyIterator(@Nullable Object key, int index) { 342 int size = keyCount.count(key); 343 Preconditions.checkPositionIndex(index, size); 344 if (index >= (size / 2)) { 345 previous = keyToKeyTail.get(key); 346 nextIndex = size; 347 while (index++ < size) { 348 previous(); 349 } 350 } else { 351 next = keyToKeyHead.get(key); 352 while (index-- > 0) { 353 next(); 354 } 355 } 356 this.key = key; 357 current = null; 358 } 359 360 public boolean hasNext() { 361 return next != null; 362 } 363 364 public V next() { 365 checkElement(next); 366 previous = current = next; 367 next = next.nextSibling; 368 nextIndex++; 369 return current.value; 370 } 371 372 public boolean hasPrevious() { 373 return previous != null; 374 } 375 376 public V previous() { 377 checkElement(previous); 378 next = current = previous; 379 previous = previous.previousSibling; 380 nextIndex--; 381 return current.value; 382 } 383 384 public int nextIndex() { 385 return nextIndex; 386 } 387 388 public int previousIndex() { 389 return nextIndex - 1; 390 } 391 392 public void remove() { 393 checkState(current != null); 394 if (current != next) { // removing next element 395 previous = current.previousSibling; 396 nextIndex--; 397 } else { 398 next = current.nextSibling; 399 } 400 removeNode(current); 401 current = null; 402 } 403 404 public void set(V value) { 405 checkState(current != null); 406 current.value = value; 407 } 408 409 @SuppressWarnings("unchecked") 410 public void add(V value) { 411 previous = addNode((K) key, value, next); 412 nextIndex++; 413 current = null; 414 } 415 } 416 417 // Query Operations 418 419 public int size() { 420 return keyCount.size(); 421 } 422 423 public boolean isEmpty() { 424 return head == null; 425 } 426 427 public boolean containsKey(@Nullable Object key) { 428 return keyToKeyHead.containsKey(key); 429 } 430 431 public boolean containsValue(@Nullable Object value) { 432 for (Iterator<Node<K, V>> i = new NodeIterator(); i.hasNext();) { 433 if (Objects.equal(i.next().value, value)) { 434 return true; 435 } 436 } 437 return false; 438 } 439 440 public boolean containsEntry(@Nullable Object key, @Nullable Object value) { 441 for (Iterator<V> i = new ValueForKeyIterator(key); i.hasNext();) { 442 if (Objects.equal(i.next(), value)) { 443 return true; 444 } 445 } 446 return false; 447 } 448 449 // Modification Operations 450 451 /** 452 * Stores a key-value pair in the multimap. 453 * 454 * @param key key to store in the multimap 455 * @param value value to store in the multimap 456 * @return {@code true} always 457 */ 458 public boolean put(@Nullable K key, @Nullable V value) { 459 addNode(key, value, null); 460 return true; 461 } 462 463 public boolean remove(@Nullable Object key, @Nullable Object value) { 464 Iterator<V> values = new ValueForKeyIterator(key); 465 while (values.hasNext()) { 466 if (Objects.equal(values.next(), value)) { 467 values.remove(); 468 return true; 469 } 470 } 471 return false; 472 } 473 474 // Bulk Operations 475 476 public boolean putAll(@Nullable K key, Iterable<? extends V> values) { 477 boolean changed = false; 478 for (V value : values) { 479 changed |= put(key, value); 480 } 481 return changed; 482 } 483 484 public boolean putAll(Multimap<? extends K, ? extends V> multimap) { 485 boolean changed = false; 486 for (Entry<? extends K, ? extends V> entry : multimap.entries()) { 487 changed |= put(entry.getKey(), entry.getValue()); 488 } 489 return changed; 490 } 491 492 /** 493 * {@inheritDoc} 494 * 495 * <p>If any entries for the specified {@code key} already exist in the 496 * multimap, their values are changed in-place without affecting the iteration 497 * order. 498 * 499 * <p>The returned list is immutable and implements 500 * {@link java.util.RandomAccess}. 501 */ 502 public List<V> replaceValues(@Nullable K key, Iterable<? extends V> values) { 503 List<V> oldValues = getCopy(key); 504 ListIterator<V> keyValues = new ValueForKeyIterator(key); 505 Iterator<? extends V> newValues = values.iterator(); 506 507 // Replace existing values, if any. 508 while (keyValues.hasNext() && newValues.hasNext()) { 509 keyValues.next(); 510 keyValues.set(newValues.next()); 511 } 512 513 // Remove remaining old values, if any. 514 while (keyValues.hasNext()) { 515 keyValues.next(); 516 keyValues.remove(); 517 } 518 519 // Add remaining new values, if any. 520 while (newValues.hasNext()) { 521 keyValues.add(newValues.next()); 522 } 523 524 return oldValues; 525 } 526 527 private List<V> getCopy(@Nullable Object key) { 528 return unmodifiableList(Lists.newArrayList(new ValueForKeyIterator(key))); 529 } 530 531 /** 532 * {@inheritDoc} 533 * 534 * <p>The returned list is immutable and implements 535 * {@link java.util.RandomAccess}. 536 */ 537 public List<V> removeAll(@Nullable Object key) { 538 List<V> oldValues = getCopy(key); 539 removeAllNodes(key); 540 return oldValues; 541 } 542 543 public void clear() { 544 head = null; 545 tail = null; 546 keyCount.clear(); 547 keyToKeyHead.clear(); 548 keyToKeyTail.clear(); 549 } 550 551 // Views 552 553 /** 554 * {@inheritDoc} 555 * 556 * <p>If the multimap is modified while an iteration over the list is in 557 * progress (except through the iterator's own {@code add}, {@code set} or 558 * {@code remove} operations) the results of the iteration are undefined. 559 * 560 * <p>The returned list is not serializable and does not have random access. 561 */ 562 public List<V> get(final @Nullable K key) { 563 return new AbstractSequentialList<V>() { 564 @Override public int size() { 565 return keyCount.count(key); 566 } 567 @Override public ListIterator<V> listIterator(int index) { 568 return new ValueForKeyIterator(key, index); 569 } 570 @Override public boolean removeAll(Collection<?> c) { 571 return Iterators.removeAll(iterator(), c); 572 } 573 @Override public boolean retainAll(Collection<?> c) { 574 return Iterators.retainAll(iterator(), c); 575 } 576 }; 577 } 578 579 private transient Set<K> keySet; 580 581 public Set<K> keySet() { 582 Set<K> result = keySet; 583 if (result == null) { 584 keySet = result = new AbstractSet<K>() { 585 @Override public int size() { 586 return keyCount.elementSet().size(); 587 } 588 @Override public Iterator<K> iterator() { 589 return new DistinctKeyIterator(); 590 } 591 @Override public boolean contains(Object key) { // for performance 592 return keyCount.contains(key); 593 } 594 }; 595 } 596 return result; 597 } 598 599 private transient Multiset<K> keys; 600 601 public Multiset<K> keys() { 602 Multiset<K> result = keys; 603 if (result == null) { 604 keys = result = new MultisetView(); 605 } 606 return result; 607 } 608 609 private class MultisetView extends AbstractCollection<K> 610 implements Multiset<K> { 611 612 @Override public int size() { 613 return keyCount.size(); 614 } 615 616 @Override public Iterator<K> iterator() { 617 final Iterator<Node<K, V>> nodes = new NodeIterator(); 618 return new Iterator<K>() { 619 public boolean hasNext() { 620 return nodes.hasNext(); 621 } 622 public K next() { 623 return nodes.next().key; 624 } 625 public void remove() { 626 nodes.remove(); 627 } 628 }; 629 } 630 631 public int count(@Nullable Object key) { 632 return keyCount.count(key); 633 } 634 635 public int add(@Nullable K key, int occurrences) { 636 throw new UnsupportedOperationException(); 637 } 638 639 public int remove(@Nullable Object key, int occurrences) { 640 checkArgument(occurrences >= 0); 641 int oldCount = count(key); 642 Iterator<V> values = new ValueForKeyIterator(key); 643 while ((occurrences-- > 0) && values.hasNext()) { 644 values.next(); 645 values.remove(); 646 } 647 return oldCount; 648 } 649 650 public int setCount(K element, int count) { 651 return setCountImpl(this, element, count); 652 } 653 654 public boolean setCount(K element, int oldCount, int newCount) { 655 return setCountImpl(this, element, oldCount, newCount); 656 } 657 658 @Override public boolean removeAll(Collection<?> c) { 659 return Iterators.removeAll(iterator(), c); 660 } 661 662 @Override public boolean retainAll(Collection<?> c) { 663 return Iterators.retainAll(iterator(), c); 664 } 665 666 public Set<K> elementSet() { 667 return keySet(); 668 } 669 670 public Set<Entry<K>> entrySet() { 671 // TODO: lazy init? 672 return new AbstractSet<Entry<K>>() { 673 @Override public int size() { 674 return keyCount.elementSet().size(); 675 } 676 677 @Override public Iterator<Entry<K>> iterator() { 678 final Iterator<K> keyIterator = new DistinctKeyIterator(); 679 return new Iterator<Entry<K>>() { 680 public boolean hasNext() { 681 return keyIterator.hasNext(); 682 } 683 public Entry<K> next() { 684 final K key = keyIterator.next(); 685 return new Multisets.AbstractEntry<K>() { 686 public K getElement() { 687 return key; 688 } 689 public int getCount() { 690 return keyCount.count(key); 691 } 692 }; 693 } 694 public void remove() { 695 keyIterator.remove(); 696 } 697 }; 698 } 699 }; 700 } 701 702 @Override public boolean equals(@Nullable Object object) { 703 return keyCount.equals(object); 704 } 705 706 @Override public int hashCode() { 707 return keyCount.hashCode(); 708 } 709 710 @Override public String toString() { 711 return keyCount.toString(); // XXX observe order? 712 } 713 } 714 715 private transient Collection<V> valuesCollection; 716 717 /** 718 * {@inheritDoc} 719 * 720 * <p>The iterator generated by the returned collection traverses the values 721 * in the order they were added to the multimap. 722 */ 723 public Collection<V> values() { 724 Collection<V> result = valuesCollection; 725 if (result == null) { 726 valuesCollection = result = new AbstractCollection<V>() { 727 @Override public int size() { 728 return keyCount.size(); 729 } 730 @Override public Iterator<V> iterator() { 731 final Iterator<Node<K, V>> nodes = new NodeIterator(); 732 return new Iterator<V>() { 733 public boolean hasNext() { 734 return nodes.hasNext(); 735 } 736 public V next() { 737 return nodes.next().value; 738 } 739 public void remove() { 740 nodes.remove(); 741 } 742 }; 743 } 744 }; 745 } 746 return result; 747 } 748 749 private transient Collection<Entry<K, V>> entries; 750 751 /** 752 * {@inheritDoc} 753 * 754 * <p>The iterator generated by the returned collection traverses the entries 755 * in the order they were added to the multimap. 756 * 757 * <p>An entry's {@link Entry#getKey} method always returns the same key, 758 * regardless of what happens subsequently. As long as the corresponding 759 * key-value mapping is not removed from the multimap, {@link Entry#getValue} 760 * returns the value from the multimap, which may change over time, and {@link 761 * Entry#setValue} modifies that value. Removing the mapping from the 762 * multimap does not alter the value returned by {@code getValue()}, though a 763 * subsequent {@code setValue()} call won't update the multimap but will lead 764 * to a revised value being returned by {@code getValue()}. 765 */ 766 public Collection<Entry<K, V>> entries() { 767 Collection<Entry<K, V>> result = entries; 768 if (result == null) { 769 entries = result = new AbstractCollection<Entry<K, V>>() { 770 @Override public int size() { 771 return keyCount.size(); 772 } 773 774 @Override public Iterator<Entry<K, V>> iterator() { 775 final Iterator<Node<K, V>> nodes = new NodeIterator(); 776 return new Iterator<Entry<K, V>>() { 777 public boolean hasNext() { 778 return nodes.hasNext(); 779 } 780 781 public Entry<K, V> next() { 782 final Node<K, V> node = nodes.next(); 783 return new AbstractMapEntry<K, V>() { 784 @Override public K getKey() { 785 return node.key; 786 } 787 @Override public V getValue() { 788 return node.value; 789 } 790 @Override public V setValue(V value) { 791 V oldValue = node.value; 792 node.value = value; 793 return oldValue; 794 } 795 }; 796 } 797 798 public void remove() { 799 nodes.remove(); 800 } 801 }; 802 } 803 }; 804 } 805 return result; 806 } 807 808 private class AsMapEntries extends AbstractSet<Entry<K, Collection<V>>> { 809 810 // TODO: Override contains() and remove() for better performance. 811 812 @Override public int size() { 813 return keyCount.elementSet().size(); 814 } 815 816 @Override public Iterator<Entry<K, Collection<V>>> iterator() { 817 final Iterator<K> keyIterator = new DistinctKeyIterator(); 818 return new Iterator<Entry<K, Collection<V>>>() { 819 public boolean hasNext() { 820 return keyIterator.hasNext(); 821 } 822 823 public Entry<K, Collection<V>> next() { 824 final K key = keyIterator.next(); 825 return new AbstractMapEntry<K, Collection<V>>() { 826 @Override public K getKey() { 827 return key; 828 } 829 830 @Override public Collection<V> getValue() { 831 return LinkedListMultimap.this.get(key); 832 } 833 }; 834 } 835 836 public void remove() { 837 keyIterator.remove(); 838 } 839 }; 840 } 841 } 842 843 private transient Map<K, Collection<V>> map; 844 845 public Map<K, Collection<V>> asMap() { 846 Map<K, Collection<V>> result = map; 847 if (result == null) { 848 map = result = new AbstractMap<K, Collection<V>>() { 849 Set<Entry<K, Collection<V>>> entrySet; 850 851 @Override public Set<Entry<K, Collection<V>>> entrySet() { 852 Set<Entry<K, Collection<V>>> result = entrySet; 853 if (result == null) { 854 entrySet = result = new AsMapEntries(); 855 } 856 return result; 857 } 858 859 // The following methods are included for performance. 860 861 @Override public boolean containsKey(@Nullable Object key) { 862 return LinkedListMultimap.this.containsKey(key); 863 } 864 865 @SuppressWarnings("unchecked") 866 @Override public Collection<V> get(@Nullable Object key) { 867 Collection<V> collection = LinkedListMultimap.this.get((K) key); 868 return collection.isEmpty() ? null : collection; 869 } 870 871 @Override public Collection<V> remove(@Nullable Object key) { 872 Collection<V> collection = removeAll(key); 873 return collection.isEmpty() ? null : collection; 874 } 875 }; 876 } 877 878 return result; 879 } 880 881 // Comparison and hashing 882 883 /** 884 * Compares the specified object to this multimap for equality. 885 * 886 * <p>Two {@code ListMultimap} instances are equal if, for each key, they 887 * contain the same values in the same order. If the value orderings disagree, 888 * the multimaps will not be considered equal. 889 */ 890 @Override public boolean equals(@Nullable Object other) { 891 if (other == this) { 892 return true; 893 } 894 if (other instanceof Multimap) { 895 Multimap<?, ?> that = (Multimap<?, ?>) other; 896 return this.asMap().equals(that.asMap()); 897 } 898 return false; 899 } 900 901 /** 902 * Returns the hash code for this multimap. 903 * 904 * <p>The hash code of a multimap is defined as the hash code of the map view, 905 * as returned by {@link Multimap#asMap}. 906 */ 907 @Override public int hashCode() { 908 return asMap().hashCode(); 909 } 910 911 /** 912 * Returns a string representation of the multimap, generated by calling 913 * {@code toString} on the map returned by {@link Multimap#asMap}. 914 * 915 * @return a string representation of the multimap 916 */ 917 @Override public String toString() { 918 return asMap().toString(); 919 } 920 921 /** 922 * @serialData the number of distinct keys, and then for each distinct key: 923 * the first key, the number of values for that key, and the key's values, 924 * followed by successive keys and values from the entries() ordering 925 */ 926 private void writeObject(ObjectOutputStream stream) throws IOException { 927 stream.defaultWriteObject(); 928 stream.writeInt(size()); 929 for (Entry<K, V> entry : entries()) { 930 stream.writeObject(entry.getKey()); 931 stream.writeObject(entry.getValue()); 932 } 933 } 934 935 private void readObject(ObjectInputStream stream) 936 throws IOException, ClassNotFoundException { 937 stream.defaultReadObject(); 938 keyCount = LinkedHashMultiset.create(); 939 keyToKeyHead = Maps.newHashMap(); 940 keyToKeyTail = Maps.newHashMap(); 941 int size = stream.readInt(); 942 for (int i = 0; i < size; i++) { 943 @SuppressWarnings("unchecked") // reading data stored by writeObject 944 K key = (K) stream.readObject(); 945 @SuppressWarnings("unchecked") // reading data stored by writeObject 946 V value = (V) stream.readObject(); 947 put(key, value); 948 } 949 } 950 951 private static final long serialVersionUID = 0; 952 } 953