1 /* 2 * Copyright (C) 2008 The Guava Authors 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 static com.google.common.base.Preconditions.checkNotNull; 20 import static com.google.common.base.Predicates.alwaysTrue; 21 import static com.google.common.base.Predicates.equalTo; 22 import static com.google.common.base.Predicates.in; 23 import static com.google.common.base.Predicates.not; 24 import static com.google.common.collect.Maps.safeContainsKey; 25 import static com.google.common.collect.Maps.safeGet; 26 import static com.google.common.collect.NullnessCasts.uncheckedCastNullableTToT; 27 import static java.util.Objects.requireNonNull; 28 29 import com.google.common.annotations.GwtCompatible; 30 import com.google.common.base.Function; 31 import com.google.common.base.Predicate; 32 import com.google.common.base.Supplier; 33 import com.google.common.collect.Maps.IteratorBasedAbstractMap; 34 import com.google.common.collect.Maps.ViewCachingAbstractMap; 35 import com.google.common.collect.Sets.ImprovedAbstractSet; 36 import com.google.errorprone.annotations.CanIgnoreReturnValue; 37 import com.google.errorprone.annotations.concurrent.LazyInit; 38 import com.google.j2objc.annotations.WeakOuter; 39 import java.io.Serializable; 40 import java.util.Collection; 41 import java.util.Iterator; 42 import java.util.LinkedHashMap; 43 import java.util.Map; 44 import java.util.Map.Entry; 45 import java.util.Set; 46 import java.util.Spliterator; 47 import java.util.Spliterators; 48 import javax.annotation.CheckForNull; 49 50 /** 51 * {@link Table} implementation backed by a map that associates row keys with column key / value 52 * secondary maps. This class provides rapid access to records by the row key alone or by both keys, 53 * but not by just the column key. 54 * 55 * <p>The views returned by {@link #column}, {@link #columnKeySet()}, and {@link #columnMap()} have 56 * iterators that don't support {@code remove()}. Otherwise, all optional operations are supported. 57 * Null row keys, columns keys, and values are not supported. 58 * 59 * <p>Lookups by row key are often faster than lookups by column key, because the data is stored in 60 * a {@code Map<R, Map<C, V>>}. A method call like {@code column(columnKey).get(rowKey)} still runs 61 * quickly, since the row key is provided. However, {@code column(columnKey).size()} takes longer, 62 * since an iteration across all row keys occurs. 63 * 64 * <p>Note that this implementation is not synchronized. If multiple threads access this table 65 * concurrently and one of the threads modifies the table, it must be synchronized externally. 66 * 67 * @author Jared Levy 68 */ 69 @GwtCompatible 70 @ElementTypesAreNonnullByDefault 71 class StandardTable<R, C, V> extends AbstractTable<R, C, V> implements Serializable { 72 @GwtTransient final Map<R, Map<C, V>> backingMap; 73 @GwtTransient final Supplier<? extends Map<C, V>> factory; 74 StandardTable(Map<R, Map<C, V>> backingMap, Supplier<? extends Map<C, V>> factory)75 StandardTable(Map<R, Map<C, V>> backingMap, Supplier<? extends Map<C, V>> factory) { 76 this.backingMap = backingMap; 77 this.factory = factory; 78 } 79 80 // Accessors 81 82 @Override contains(@heckForNull Object rowKey, @CheckForNull Object columnKey)83 public boolean contains(@CheckForNull Object rowKey, @CheckForNull Object columnKey) { 84 return rowKey != null && columnKey != null && super.contains(rowKey, columnKey); 85 } 86 87 @Override containsColumn(@heckForNull Object columnKey)88 public boolean containsColumn(@CheckForNull Object columnKey) { 89 if (columnKey == null) { 90 return false; 91 } 92 for (Map<C, V> map : backingMap.values()) { 93 if (safeContainsKey(map, columnKey)) { 94 return true; 95 } 96 } 97 return false; 98 } 99 100 @Override containsRow(@heckForNull Object rowKey)101 public boolean containsRow(@CheckForNull Object rowKey) { 102 return rowKey != null && safeContainsKey(backingMap, rowKey); 103 } 104 105 @Override containsValue(@heckForNull Object value)106 public boolean containsValue(@CheckForNull Object value) { 107 return value != null && super.containsValue(value); 108 } 109 110 @Override 111 @CheckForNull get(@heckForNull Object rowKey, @CheckForNull Object columnKey)112 public V get(@CheckForNull Object rowKey, @CheckForNull Object columnKey) { 113 return (rowKey == null || columnKey == null) ? null : super.get(rowKey, columnKey); 114 } 115 116 @Override isEmpty()117 public boolean isEmpty() { 118 return backingMap.isEmpty(); 119 } 120 121 @Override size()122 public int size() { 123 int size = 0; 124 for (Map<C, V> map : backingMap.values()) { 125 size += map.size(); 126 } 127 return size; 128 } 129 130 // Mutators 131 132 @Override clear()133 public void clear() { 134 backingMap.clear(); 135 } 136 getOrCreate(R rowKey)137 private Map<C, V> getOrCreate(R rowKey) { 138 Map<C, V> map = backingMap.get(rowKey); 139 if (map == null) { 140 map = factory.get(); 141 backingMap.put(rowKey, map); 142 } 143 return map; 144 } 145 146 @CanIgnoreReturnValue 147 @Override 148 @CheckForNull put(R rowKey, C columnKey, V value)149 public V put(R rowKey, C columnKey, V value) { 150 checkNotNull(rowKey); 151 checkNotNull(columnKey); 152 checkNotNull(value); 153 return getOrCreate(rowKey).put(columnKey, value); 154 } 155 156 @CanIgnoreReturnValue 157 @Override 158 @CheckForNull remove(@heckForNull Object rowKey, @CheckForNull Object columnKey)159 public V remove(@CheckForNull Object rowKey, @CheckForNull Object columnKey) { 160 if ((rowKey == null) || (columnKey == null)) { 161 return null; 162 } 163 Map<C, V> map = safeGet(backingMap, rowKey); 164 if (map == null) { 165 return null; 166 } 167 V value = map.remove(columnKey); 168 if (map.isEmpty()) { 169 backingMap.remove(rowKey); 170 } 171 return value; 172 } 173 174 @CanIgnoreReturnValue removeColumn(@heckForNull Object column)175 private Map<R, V> removeColumn(@CheckForNull Object column) { 176 Map<R, V> output = new LinkedHashMap<>(); 177 Iterator<Entry<R, Map<C, V>>> iterator = backingMap.entrySet().iterator(); 178 while (iterator.hasNext()) { 179 Entry<R, Map<C, V>> entry = iterator.next(); 180 V value = entry.getValue().remove(column); 181 if (value != null) { 182 output.put(entry.getKey(), value); 183 if (entry.getValue().isEmpty()) { 184 iterator.remove(); 185 } 186 } 187 } 188 return output; 189 } 190 containsMapping( @heckForNull Object rowKey, @CheckForNull Object columnKey, @CheckForNull Object value)191 private boolean containsMapping( 192 @CheckForNull Object rowKey, @CheckForNull Object columnKey, @CheckForNull Object value) { 193 return value != null && value.equals(get(rowKey, columnKey)); 194 } 195 196 /** Remove a row key / column key / value mapping, if present. */ removeMapping( @heckForNull Object rowKey, @CheckForNull Object columnKey, @CheckForNull Object value)197 private boolean removeMapping( 198 @CheckForNull Object rowKey, @CheckForNull Object columnKey, @CheckForNull Object value) { 199 if (containsMapping(rowKey, columnKey, value)) { 200 remove(rowKey, columnKey); 201 return true; 202 } 203 return false; 204 } 205 206 // Views 207 208 /** 209 * Abstract set whose {@code isEmpty()} returns whether the table is empty and whose {@code 210 * clear()} clears all table mappings. 211 */ 212 @WeakOuter 213 private abstract class TableSet<T> extends ImprovedAbstractSet<T> { 214 @Override isEmpty()215 public boolean isEmpty() { 216 return backingMap.isEmpty(); 217 } 218 219 @Override clear()220 public void clear() { 221 backingMap.clear(); 222 } 223 } 224 225 /** 226 * {@inheritDoc} 227 * 228 * <p>The set's iterator traverses the mappings for the first row, the mappings for the second 229 * row, and so on. 230 * 231 * <p>Each cell is an immutable snapshot of a row key / column key / value mapping, taken at the 232 * time the cell is returned by a method call to the set or its iterator. 233 */ 234 @Override cellSet()235 public Set<Cell<R, C, V>> cellSet() { 236 return super.cellSet(); 237 } 238 239 @Override cellIterator()240 Iterator<Cell<R, C, V>> cellIterator() { 241 return new CellIterator(); 242 } 243 244 private class CellIterator implements Iterator<Cell<R, C, V>> { 245 final Iterator<Entry<R, Map<C, V>>> rowIterator = backingMap.entrySet().iterator(); 246 @CheckForNull Entry<R, Map<C, V>> rowEntry; 247 Iterator<Entry<C, V>> columnIterator = Iterators.emptyModifiableIterator(); 248 249 @Override hasNext()250 public boolean hasNext() { 251 return rowIterator.hasNext() || columnIterator.hasNext(); 252 } 253 254 @Override next()255 public Cell<R, C, V> next() { 256 if (!columnIterator.hasNext()) { 257 rowEntry = rowIterator.next(); 258 columnIterator = rowEntry.getValue().entrySet().iterator(); 259 } 260 /* 261 * requireNonNull is safe because: 262 * 263 * - columnIterator started off pointing to an empty iterator, so we must have entered the 264 * `if` body above at least once. Thus, if we got this far, that `if` body initialized 265 * rowEntry at least once. 266 * 267 * - The only case in which rowEntry is cleared (during remove() below) happens only if the 268 * caller removed every element from columnIterator. During that process, we would have had 269 * to iterate it to exhaustion. Then we can apply the logic above about an empty 270 * columnIterator. (This assumes no concurrent modification, but behavior under concurrent 271 * modification is undefined, anyway.) 272 */ 273 requireNonNull(rowEntry); 274 Entry<C, V> columnEntry = columnIterator.next(); 275 return Tables.immutableCell(rowEntry.getKey(), columnEntry.getKey(), columnEntry.getValue()); 276 } 277 278 @Override remove()279 public void remove() { 280 columnIterator.remove(); 281 /* 282 * requireNonNull is safe because: 283 * 284 * - columnIterator.remove() succeeded, so it must have returned a value, so it must have been 285 * initialized by next() -- which initializes rowEntry, too. 286 * 287 * - rowEntry isn't cleared except below. If it was cleared below, then either 288 * columnIterator.remove() would have failed above (if the user hasn't called next() since 289 * then) or rowEntry would have been initialized by next() (as discussed above). 290 */ 291 if (requireNonNull(rowEntry).getValue().isEmpty()) { 292 rowIterator.remove(); 293 rowEntry = null; 294 } 295 } 296 } 297 298 @Override cellSpliterator()299 Spliterator<Cell<R, C, V>> cellSpliterator() { 300 return CollectSpliterators.flatMap( 301 backingMap.entrySet().spliterator(), 302 (Entry<R, Map<C, V>> rowEntry) -> 303 CollectSpliterators.map( 304 rowEntry.getValue().entrySet().spliterator(), 305 (Entry<C, V> columnEntry) -> 306 Tables.immutableCell( 307 rowEntry.getKey(), columnEntry.getKey(), columnEntry.getValue())), 308 Spliterator.DISTINCT | Spliterator.SIZED, 309 size()); 310 } 311 312 @Override row(R rowKey)313 public Map<C, V> row(R rowKey) { 314 return new Row(rowKey); 315 } 316 317 class Row extends IteratorBasedAbstractMap<C, V> { 318 final R rowKey; 319 Row(R rowKey)320 Row(R rowKey) { 321 this.rowKey = checkNotNull(rowKey); 322 } 323 324 @CheckForNull Map<C, V> backingRowMap; 325 updateBackingRowMapField()326 final void updateBackingRowMapField() { 327 if (backingRowMap == null || (backingRowMap.isEmpty() && backingMap.containsKey(rowKey))) { 328 backingRowMap = computeBackingRowMap(); 329 } 330 } 331 332 @CheckForNull computeBackingRowMap()333 Map<C, V> computeBackingRowMap() { 334 return backingMap.get(rowKey); 335 } 336 337 // Call this every time we perform a removal. maintainEmptyInvariant()338 void maintainEmptyInvariant() { 339 updateBackingRowMapField(); 340 if (backingRowMap != null && backingRowMap.isEmpty()) { 341 backingMap.remove(rowKey); 342 backingRowMap = null; 343 } 344 } 345 346 @Override containsKey(@heckForNull Object key)347 public boolean containsKey(@CheckForNull Object key) { 348 updateBackingRowMapField(); 349 return (key != null && backingRowMap != null) && Maps.safeContainsKey(backingRowMap, key); 350 } 351 352 @Override 353 @CheckForNull get(@heckForNull Object key)354 public V get(@CheckForNull Object key) { 355 updateBackingRowMapField(); 356 return (key != null && backingRowMap != null) ? Maps.safeGet(backingRowMap, key) : null; 357 } 358 359 @Override 360 @CheckForNull put(C key, V value)361 public V put(C key, V value) { 362 checkNotNull(key); 363 checkNotNull(value); 364 if (backingRowMap != null && !backingRowMap.isEmpty()) { 365 return backingRowMap.put(key, value); 366 } 367 return StandardTable.this.put(rowKey, key, value); 368 } 369 370 @Override 371 @CheckForNull remove(@heckForNull Object key)372 public V remove(@CheckForNull Object key) { 373 updateBackingRowMapField(); 374 if (backingRowMap == null) { 375 return null; 376 } 377 V result = Maps.safeRemove(backingRowMap, key); 378 maintainEmptyInvariant(); 379 return result; 380 } 381 382 @Override clear()383 public void clear() { 384 updateBackingRowMapField(); 385 if (backingRowMap != null) { 386 backingRowMap.clear(); 387 } 388 maintainEmptyInvariant(); 389 } 390 391 @Override size()392 public int size() { 393 updateBackingRowMapField(); 394 return (backingRowMap == null) ? 0 : backingRowMap.size(); 395 } 396 397 @Override entryIterator()398 Iterator<Entry<C, V>> entryIterator() { 399 updateBackingRowMapField(); 400 if (backingRowMap == null) { 401 return Iterators.emptyModifiableIterator(); 402 } 403 final Iterator<Entry<C, V>> iterator = backingRowMap.entrySet().iterator(); 404 return new Iterator<Entry<C, V>>() { 405 @Override 406 public boolean hasNext() { 407 return iterator.hasNext(); 408 } 409 410 @Override 411 public Entry<C, V> next() { 412 return wrapEntry(iterator.next()); 413 } 414 415 @Override 416 public void remove() { 417 iterator.remove(); 418 maintainEmptyInvariant(); 419 } 420 }; 421 } 422 423 @Override entrySpliterator()424 Spliterator<Entry<C, V>> entrySpliterator() { 425 updateBackingRowMapField(); 426 if (backingRowMap == null) { 427 return Spliterators.emptySpliterator(); 428 } 429 return CollectSpliterators.map(backingRowMap.entrySet().spliterator(), this::wrapEntry); 430 } 431 wrapEntry(final Entry<C, V> entry)432 Entry<C, V> wrapEntry(final Entry<C, V> entry) { 433 return new ForwardingMapEntry<C, V>() { 434 @Override 435 protected Entry<C, V> delegate() { 436 return entry; 437 } 438 439 @Override 440 public V setValue(V value) { 441 return super.setValue(checkNotNull(value)); 442 } 443 444 @Override 445 public boolean equals(@CheckForNull Object object) { 446 // TODO(lowasser): identify why this affects GWT tests 447 return standardEquals(object); 448 } 449 }; 450 } 451 } 452 453 /** 454 * {@inheritDoc} 455 * 456 * <p>The returned map's views have iterators that don't support {@code remove()}. 457 */ 458 @Override 459 public Map<R, V> column(C columnKey) { 460 return new Column(columnKey); 461 } 462 463 private class Column extends ViewCachingAbstractMap<R, V> { 464 final C columnKey; 465 466 Column(C columnKey) { 467 this.columnKey = checkNotNull(columnKey); 468 } 469 470 @Override 471 @CheckForNull 472 public V put(R key, V value) { 473 return StandardTable.this.put(key, columnKey, value); 474 } 475 476 @Override 477 @CheckForNull 478 public V get(@CheckForNull Object key) { 479 return StandardTable.this.get(key, columnKey); 480 } 481 482 @Override 483 public boolean containsKey(@CheckForNull Object key) { 484 return StandardTable.this.contains(key, columnKey); 485 } 486 487 @Override 488 @CheckForNull 489 public V remove(@CheckForNull Object key) { 490 return StandardTable.this.remove(key, columnKey); 491 } 492 493 /** Removes all {@code Column} mappings whose row key and value satisfy the given predicate. */ 494 @CanIgnoreReturnValue 495 boolean removeFromColumnIf(Predicate<? super Entry<R, V>> predicate) { 496 boolean changed = false; 497 Iterator<Entry<R, Map<C, V>>> iterator = backingMap.entrySet().iterator(); 498 while (iterator.hasNext()) { 499 Entry<R, Map<C, V>> entry = iterator.next(); 500 Map<C, V> map = entry.getValue(); 501 V value = map.get(columnKey); 502 if (value != null && predicate.apply(Maps.immutableEntry(entry.getKey(), value))) { 503 map.remove(columnKey); 504 changed = true; 505 if (map.isEmpty()) { 506 iterator.remove(); 507 } 508 } 509 } 510 return changed; 511 } 512 513 @Override 514 Set<Entry<R, V>> createEntrySet() { 515 return new EntrySet(); 516 } 517 518 @WeakOuter 519 private class EntrySet extends ImprovedAbstractSet<Entry<R, V>> { 520 @Override 521 public Iterator<Entry<R, V>> iterator() { 522 return new EntrySetIterator(); 523 } 524 525 @Override 526 public int size() { 527 int size = 0; 528 for (Map<C, V> map : backingMap.values()) { 529 if (map.containsKey(columnKey)) { 530 size++; 531 } 532 } 533 return size; 534 } 535 536 @Override 537 public boolean isEmpty() { 538 return !containsColumn(columnKey); 539 } 540 541 @Override 542 public void clear() { 543 removeFromColumnIf(alwaysTrue()); 544 } 545 546 @Override 547 public boolean contains(@CheckForNull Object o) { 548 if (o instanceof Entry) { 549 Entry<?, ?> entry = (Entry<?, ?>) o; 550 return containsMapping(entry.getKey(), columnKey, entry.getValue()); 551 } 552 return false; 553 } 554 555 @Override 556 public boolean remove(@CheckForNull Object obj) { 557 if (obj instanceof Entry) { 558 Entry<?, ?> entry = (Entry<?, ?>) obj; 559 return removeMapping(entry.getKey(), columnKey, entry.getValue()); 560 } 561 return false; 562 } 563 564 @Override 565 public boolean retainAll(Collection<?> c) { 566 return removeFromColumnIf(not(in(c))); 567 } 568 } 569 570 private class EntrySetIterator extends AbstractIterator<Entry<R, V>> { 571 final Iterator<Entry<R, Map<C, V>>> iterator = backingMap.entrySet().iterator(); 572 573 @Override 574 @CheckForNull 575 protected Entry<R, V> computeNext() { 576 while (iterator.hasNext()) { 577 final Entry<R, Map<C, V>> entry = iterator.next(); 578 if (entry.getValue().containsKey(columnKey)) { 579 @WeakOuter 580 class EntryImpl extends AbstractMapEntry<R, V> { 581 @Override 582 public R getKey() { 583 return entry.getKey(); 584 } 585 586 @Override 587 public V getValue() { 588 return entry.getValue().get(columnKey); 589 } 590 591 @Override 592 public V setValue(V value) { 593 /* 594 * The cast is safe because of the containsKey check above. (Well, it's possible for 595 * the map to change between that call and this one. But if that happens, the 596 * behavior is undefined because of the concurrent mutation.) 597 * 598 * (Our prototype checker happens to be "smart" enough to understand this for the 599 * *get* call in getValue but not for the *put* call here.) 600 * 601 * (Arguably we should use requireNonNull rather than uncheckedCastNullableTToT: We 602 * know that V is a non-null type because that's the only kind of value type that 603 * StandardTable supports. Thus, requireNonNull is safe as long as the cell is still 604 * present. (And if it's not present, behavior is undefined.) However, that's a 605 * behavior change relative to the old code, so it didn't seem worth risking.) 606 */ 607 return uncheckedCastNullableTToT( 608 entry.getValue().put(columnKey, checkNotNull(value))); 609 } 610 } 611 return new EntryImpl(); 612 } 613 } 614 return endOfData(); 615 } 616 } 617 618 @Override 619 Set<R> createKeySet() { 620 return new KeySet(); 621 } 622 623 @WeakOuter 624 private class KeySet extends Maps.KeySet<R, V> { 625 KeySet() { 626 super(Column.this); 627 } 628 629 @Override 630 public boolean contains(@CheckForNull Object obj) { 631 return StandardTable.this.contains(obj, columnKey); 632 } 633 634 @Override 635 public boolean remove(@CheckForNull Object obj) { 636 return StandardTable.this.remove(obj, columnKey) != null; 637 } 638 639 @Override 640 public boolean retainAll(final Collection<?> c) { 641 return removeFromColumnIf(Maps.<R>keyPredicateOnEntries(not(in(c)))); 642 } 643 } 644 645 @Override 646 Collection<V> createValues() { 647 return new Values(); 648 } 649 650 @WeakOuter 651 private class Values extends Maps.Values<R, V> { 652 Values() { 653 super(Column.this); 654 } 655 656 @Override 657 public boolean remove(@CheckForNull Object obj) { 658 return obj != null && removeFromColumnIf(Maps.<V>valuePredicateOnEntries(equalTo(obj))); 659 } 660 661 @Override 662 public boolean removeAll(final Collection<?> c) { 663 return removeFromColumnIf(Maps.<V>valuePredicateOnEntries(in(c))); 664 } 665 666 @Override 667 public boolean retainAll(final Collection<?> c) { 668 return removeFromColumnIf(Maps.<V>valuePredicateOnEntries(not(in(c)))); 669 } 670 } 671 } 672 673 @Override 674 public Set<R> rowKeySet() { 675 return rowMap().keySet(); 676 } 677 678 @LazyInit @CheckForNull private transient Set<C> columnKeySet; 679 680 /** 681 * {@inheritDoc} 682 * 683 * <p>The returned set has an iterator that does not support {@code remove()}. 684 * 685 * <p>The set's iterator traverses the columns of the first row, the columns of the second row, 686 * etc., skipping any columns that have appeared previously. 687 */ 688 @Override 689 public Set<C> columnKeySet() { 690 Set<C> result = columnKeySet; 691 return (result == null) ? columnKeySet = new ColumnKeySet() : result; 692 } 693 694 @WeakOuter 695 private class ColumnKeySet extends TableSet<C> { 696 @Override 697 public Iterator<C> iterator() { 698 return createColumnKeyIterator(); 699 } 700 701 @Override 702 public int size() { 703 return Iterators.size(iterator()); 704 } 705 706 @Override 707 public boolean remove(@CheckForNull Object obj) { 708 if (obj == null) { 709 return false; 710 } 711 boolean changed = false; 712 Iterator<Map<C, V>> iterator = backingMap.values().iterator(); 713 while (iterator.hasNext()) { 714 Map<C, V> map = iterator.next(); 715 if (map.keySet().remove(obj)) { 716 changed = true; 717 if (map.isEmpty()) { 718 iterator.remove(); 719 } 720 } 721 } 722 return changed; 723 } 724 725 @Override 726 public boolean removeAll(Collection<?> c) { 727 checkNotNull(c); 728 boolean changed = false; 729 Iterator<Map<C, V>> iterator = backingMap.values().iterator(); 730 while (iterator.hasNext()) { 731 Map<C, V> map = iterator.next(); 732 // map.keySet().removeAll(c) can throw a NPE when map is a TreeMap with 733 // natural ordering and c contains a null. 734 if (Iterators.removeAll(map.keySet().iterator(), c)) { 735 changed = true; 736 if (map.isEmpty()) { 737 iterator.remove(); 738 } 739 } 740 } 741 return changed; 742 } 743 744 @Override 745 public boolean retainAll(Collection<?> c) { 746 checkNotNull(c); 747 boolean changed = false; 748 Iterator<Map<C, V>> iterator = backingMap.values().iterator(); 749 while (iterator.hasNext()) { 750 Map<C, V> map = iterator.next(); 751 if (map.keySet().retainAll(c)) { 752 changed = true; 753 if (map.isEmpty()) { 754 iterator.remove(); 755 } 756 } 757 } 758 return changed; 759 } 760 761 @Override 762 public boolean contains(@CheckForNull Object obj) { 763 return containsColumn(obj); 764 } 765 } 766 767 /** Creates an iterator that returns each column value with duplicates omitted. */ 768 Iterator<C> createColumnKeyIterator() { 769 return new ColumnKeyIterator(); 770 } 771 772 private class ColumnKeyIterator extends AbstractIterator<C> { 773 // Use the same map type to support TreeMaps with comparators that aren't 774 // consistent with equals(). 775 final Map<C, V> seen = factory.get(); 776 final Iterator<Map<C, V>> mapIterator = backingMap.values().iterator(); 777 Iterator<Entry<C, V>> entryIterator = Iterators.emptyIterator(); 778 779 @Override 780 @CheckForNull 781 protected C computeNext() { 782 while (true) { 783 if (entryIterator.hasNext()) { 784 Entry<C, V> entry = entryIterator.next(); 785 if (!seen.containsKey(entry.getKey())) { 786 seen.put(entry.getKey(), entry.getValue()); 787 return entry.getKey(); 788 } 789 } else if (mapIterator.hasNext()) { 790 entryIterator = mapIterator.next().entrySet().iterator(); 791 } else { 792 return endOfData(); 793 } 794 } 795 } 796 } 797 798 /** 799 * {@inheritDoc} 800 * 801 * <p>The collection's iterator traverses the values for the first row, the values for the second 802 * row, and so on. 803 */ 804 @Override 805 public Collection<V> values() { 806 return super.values(); 807 } 808 809 @LazyInit @CheckForNull private transient Map<R, Map<C, V>> rowMap; 810 811 @Override 812 public Map<R, Map<C, V>> rowMap() { 813 Map<R, Map<C, V>> result = rowMap; 814 return (result == null) ? rowMap = createRowMap() : result; 815 } 816 817 Map<R, Map<C, V>> createRowMap() { 818 return new RowMap(); 819 } 820 821 @WeakOuter 822 class RowMap extends ViewCachingAbstractMap<R, Map<C, V>> { 823 @Override 824 public boolean containsKey(@CheckForNull Object key) { 825 return containsRow(key); 826 } 827 828 // performing cast only when key is in backing map and has the correct type 829 @SuppressWarnings("unchecked") 830 @Override 831 @CheckForNull 832 public Map<C, V> get(@CheckForNull Object key) { 833 // requireNonNull is safe because of the containsRow check. 834 return containsRow(key) ? row((R) requireNonNull(key)) : null; 835 } 836 837 @Override 838 @CheckForNull 839 public Map<C, V> remove(@CheckForNull Object key) { 840 return (key == null) ? null : backingMap.remove(key); 841 } 842 843 @Override 844 protected Set<Entry<R, Map<C, V>>> createEntrySet() { 845 return new EntrySet(); 846 } 847 848 @WeakOuter 849 private final class EntrySet extends TableSet<Entry<R, Map<C, V>>> { 850 @Override 851 public Iterator<Entry<R, Map<C, V>>> iterator() { 852 return Maps.asMapEntryIterator( 853 backingMap.keySet(), 854 new Function<R, Map<C, V>>() { 855 @Override 856 public Map<C, V> apply(R rowKey) { 857 return row(rowKey); 858 } 859 }); 860 } 861 862 @Override 863 public int size() { 864 return backingMap.size(); 865 } 866 867 @Override 868 public boolean contains(@CheckForNull Object obj) { 869 if (obj instanceof Entry) { 870 Entry<?, ?> entry = (Entry<?, ?>) obj; 871 return entry.getKey() != null 872 && entry.getValue() instanceof Map 873 && Collections2.safeContains(backingMap.entrySet(), entry); 874 } 875 return false; 876 } 877 878 @Override 879 public boolean remove(@CheckForNull Object obj) { 880 if (obj instanceof Entry) { 881 Entry<?, ?> entry = (Entry<?, ?>) obj; 882 return entry.getKey() != null 883 && entry.getValue() instanceof Map 884 && backingMap.entrySet().remove(entry); 885 } 886 return false; 887 } 888 } 889 } 890 891 @LazyInit @CheckForNull private transient ColumnMap columnMap; 892 893 @Override 894 public Map<C, Map<R, V>> columnMap() { 895 ColumnMap result = columnMap; 896 return (result == null) ? columnMap = new ColumnMap() : result; 897 } 898 899 @WeakOuter 900 private class ColumnMap extends ViewCachingAbstractMap<C, Map<R, V>> { 901 // The cast to C occurs only when the key is in the map, implying that it 902 // has the correct type. 903 @SuppressWarnings("unchecked") 904 @Override 905 @CheckForNull 906 public Map<R, V> get(@CheckForNull Object key) { 907 // requireNonNull is safe because of the containsColumn check. 908 return containsColumn(key) ? column((C) requireNonNull(key)) : null; 909 } 910 911 @Override 912 public boolean containsKey(@CheckForNull Object key) { 913 return containsColumn(key); 914 } 915 916 @Override 917 @CheckForNull 918 public Map<R, V> remove(@CheckForNull Object key) { 919 return containsColumn(key) ? removeColumn(key) : null; 920 } 921 922 @Override 923 public Set<Entry<C, Map<R, V>>> createEntrySet() { 924 return new ColumnMapEntrySet(); 925 } 926 927 @Override 928 public Set<C> keySet() { 929 return columnKeySet(); 930 } 931 932 @Override 933 Collection<Map<R, V>> createValues() { 934 return new ColumnMapValues(); 935 } 936 937 @WeakOuter 938 private final class ColumnMapEntrySet extends TableSet<Entry<C, Map<R, V>>> { 939 @Override 940 public Iterator<Entry<C, Map<R, V>>> iterator() { 941 return Maps.asMapEntryIterator( 942 columnKeySet(), 943 new Function<C, Map<R, V>>() { 944 @Override 945 public Map<R, V> apply(C columnKey) { 946 return column(columnKey); 947 } 948 }); 949 } 950 951 @Override 952 public int size() { 953 return columnKeySet().size(); 954 } 955 956 @Override 957 public boolean contains(@CheckForNull Object obj) { 958 if (obj instanceof Entry) { 959 Entry<?, ?> entry = (Entry<?, ?>) obj; 960 if (containsColumn(entry.getKey())) { 961 // requireNonNull is safe because of the containsColumn check. 962 return requireNonNull(get(entry.getKey())).equals(entry.getValue()); 963 } 964 } 965 return false; 966 } 967 968 @Override 969 public boolean remove(@CheckForNull Object obj) { 970 /* 971 * `o instanceof Entry` is guaranteed by `contains`, but we check it here to satisfy our 972 * nullness checker. 973 */ 974 if (contains(obj) && obj instanceof Entry) { 975 Entry<?, ?> entry = (Entry<?, ?>) obj; 976 removeColumn(entry.getKey()); 977 return true; 978 } 979 return false; 980 } 981 982 @Override 983 public boolean removeAll(Collection<?> c) { 984 /* 985 * We can't inherit the normal implementation (which calls 986 * Sets.removeAllImpl(Set, *Collection*)) because, under some 987 * circumstances, it attempts to call columnKeySet().iterator().remove, 988 * which is unsupported. 989 */ 990 checkNotNull(c); 991 return Sets.removeAllImpl(this, c.iterator()); 992 } 993 994 @Override 995 public boolean retainAll(Collection<?> c) { 996 checkNotNull(c); 997 boolean changed = false; 998 for (C columnKey : Lists.newArrayList(columnKeySet().iterator())) { 999 if (!c.contains(Maps.immutableEntry(columnKey, column(columnKey)))) { 1000 removeColumn(columnKey); 1001 changed = true; 1002 } 1003 } 1004 return changed; 1005 } 1006 } 1007 1008 @WeakOuter 1009 private class ColumnMapValues extends Maps.Values<C, Map<R, V>> { 1010 ColumnMapValues() { 1011 super(ColumnMap.this); 1012 } 1013 1014 @Override 1015 public boolean remove(@CheckForNull Object obj) { 1016 for (Entry<C, Map<R, V>> entry : ColumnMap.this.entrySet()) { 1017 if (entry.getValue().equals(obj)) { 1018 removeColumn(entry.getKey()); 1019 return true; 1020 } 1021 } 1022 return false; 1023 } 1024 1025 @Override 1026 public boolean removeAll(Collection<?> c) { 1027 checkNotNull(c); 1028 boolean changed = false; 1029 for (C columnKey : Lists.newArrayList(columnKeySet().iterator())) { 1030 if (c.contains(column(columnKey))) { 1031 removeColumn(columnKey); 1032 changed = true; 1033 } 1034 } 1035 return changed; 1036 } 1037 1038 @Override 1039 public boolean retainAll(Collection<?> c) { 1040 checkNotNull(c); 1041 boolean changed = false; 1042 for (C columnKey : Lists.newArrayList(columnKeySet().iterator())) { 1043 if (!c.contains(column(columnKey))) { 1044 removeColumn(columnKey); 1045 changed = true; 1046 } 1047 } 1048 return changed; 1049 } 1050 } 1051 } 1052 1053 private static final long serialVersionUID = 0; 1054 } 1055