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