1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
27 import com.google.common.annotations.GwtCompatible;
28 import com.google.common.base.Function;
29 import com.google.common.base.Predicate;
30 import com.google.common.base.Supplier;
31 import com.google.common.collect.Maps.ImprovedAbstractMap;
32 import com.google.common.collect.Sets.ImprovedAbstractSet;
33
34 import java.io.Serializable;
35 import java.util.Collection;
36 import java.util.Iterator;
37 import java.util.LinkedHashMap;
38 import java.util.Map;
39 import java.util.Map.Entry;
40 import java.util.Set;
41
42 import javax.annotation.Nullable;
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66 @GwtCompatible
67 class StandardTable<R, C, V> extends AbstractTable<R, C, V> implements Serializable {
68 @GwtTransient final Map<R, Map<C, V>> backingMap;
69 @GwtTransient final Supplier<? extends Map<C, V>> factory;
70
71 StandardTable(Map<R, Map<C, V>> backingMap,
72 Supplier<? extends Map<C, V>> factory) {
73 this.backingMap = backingMap;
74 this.factory = factory;
75 }
76
77
78
79 @Override public boolean contains(
80 @Nullable Object rowKey, @Nullable Object columnKey) {
81 return rowKey != null && columnKey != null && super.contains(rowKey, columnKey);
82 }
83
84 @Override public boolean containsColumn(@Nullable Object columnKey) {
85 if (columnKey == null) {
86 return false;
87 }
88 for (Map<C, V> map : backingMap.values()) {
89 if (safeContainsKey(map, columnKey)) {
90 return true;
91 }
92 }
93 return false;
94 }
95
96 @Override public boolean containsRow(@Nullable Object rowKey) {
97 return rowKey != null && safeContainsKey(backingMap, rowKey);
98 }
99
100 @Override public boolean containsValue(@Nullable Object value) {
101 return value != null && super.containsValue(value);
102 }
103
104 @Override public V get(@Nullable Object rowKey, @Nullable Object columnKey) {
105 return (rowKey == null || columnKey == null)
106 ? null
107 : super.get(rowKey, columnKey);
108 }
109
110 @Override public boolean isEmpty() {
111 return backingMap.isEmpty();
112 }
113
114 @Override public int size() {
115 int size = 0;
116 for (Map<C, V> map : backingMap.values()) {
117 size += map.size();
118 }
119 return size;
120 }
121
122
123
124 @Override public void clear() {
125 backingMap.clear();
126 }
127
128 private Map<C, V> getOrCreate(R rowKey) {
129 Map<C, V> map = backingMap.get(rowKey);
130 if (map == null) {
131 map = factory.get();
132 backingMap.put(rowKey, map);
133 }
134 return map;
135 }
136
137 @Override public V put(R rowKey, C columnKey, V value) {
138 checkNotNull(rowKey);
139 checkNotNull(columnKey);
140 checkNotNull(value);
141 return getOrCreate(rowKey).put(columnKey, value);
142 }
143
144 @Override public V remove(
145 @Nullable Object rowKey, @Nullable Object columnKey) {
146 if ((rowKey == null) || (columnKey == null)) {
147 return null;
148 }
149 Map<C, V> map = safeGet(backingMap, rowKey);
150 if (map == null) {
151 return null;
152 }
153 V value = map.remove(columnKey);
154 if (map.isEmpty()) {
155 backingMap.remove(rowKey);
156 }
157 return value;
158 }
159
160 private Map<R, V> removeColumn(Object column) {
161 Map<R, V> output = new LinkedHashMap<R, V>();
162 Iterator<Entry<R, Map<C, V>>> iterator
163 = backingMap.entrySet().iterator();
164 while (iterator.hasNext()) {
165 Entry<R, Map<C, V>> entry = iterator.next();
166 V value = entry.getValue().remove(column);
167 if (value != null) {
168 output.put(entry.getKey(), value);
169 if (entry.getValue().isEmpty()) {
170 iterator.remove();
171 }
172 }
173 }
174 return output;
175 }
176
177 private boolean containsMapping(
178 Object rowKey, Object columnKey, Object value) {
179 return value != null && value.equals(get(rowKey, columnKey));
180 }
181
182
183 private boolean removeMapping(Object rowKey, Object columnKey, Object value) {
184 if (containsMapping(rowKey, columnKey, value)) {
185 remove(rowKey, columnKey);
186 return true;
187 }
188 return false;
189 }
190
191
192
193
194
195
196
197 private abstract class TableSet<T> extends ImprovedAbstractSet<T> {
198 @Override public boolean isEmpty() {
199 return backingMap.isEmpty();
200 }
201
202 @Override public void clear() {
203 backingMap.clear();
204 }
205 }
206
207
208
209
210
211
212
213
214
215
216
217 @Override public Set<Cell<R, C, V>> cellSet() {
218 return super.cellSet();
219 }
220
221 @Override Iterator<Cell<R, C, V>> cellIterator() {
222 return new CellIterator();
223 }
224
225 private class CellIterator implements Iterator<Cell<R, C, V>> {
226 final Iterator<Entry<R, Map<C, V>>> rowIterator
227 = backingMap.entrySet().iterator();
228 Entry<R, Map<C, V>> rowEntry;
229 Iterator<Entry<C, V>> columnIterator
230 = Iterators.emptyModifiableIterator();
231
232 @Override public boolean hasNext() {
233 return rowIterator.hasNext() || columnIterator.hasNext();
234 }
235
236 @Override public Cell<R, C, V> next() {
237 if (!columnIterator.hasNext()) {
238 rowEntry = rowIterator.next();
239 columnIterator = rowEntry.getValue().entrySet().iterator();
240 }
241 Entry<C, V> columnEntry = columnIterator.next();
242 return Tables.immutableCell(
243 rowEntry.getKey(), columnEntry.getKey(), columnEntry.getValue());
244 }
245
246 @Override public void remove() {
247 columnIterator.remove();
248 if (rowEntry.getValue().isEmpty()) {
249 rowIterator.remove();
250 }
251 }
252 }
253
254 @Override public Map<C, V> row(R rowKey) {
255 return new Row(rowKey);
256 }
257
258 class Row extends ImprovedAbstractMap<C, V> {
259 final R rowKey;
260
261 Row(R rowKey) {
262 this.rowKey = checkNotNull(rowKey);
263 }
264
265 Map<C, V> backingRowMap;
266
267 Map<C, V> backingRowMap() {
268 return (backingRowMap == null
269 || (backingRowMap.isEmpty() && backingMap.containsKey(rowKey)))
270 ? backingRowMap = computeBackingRowMap()
271 : backingRowMap;
272 }
273
274 Map<C, V> computeBackingRowMap() {
275 return backingMap.get(rowKey);
276 }
277
278
279 void maintainEmptyInvariant() {
280 if (backingRowMap() != null && backingRowMap.isEmpty()) {
281 backingMap.remove(rowKey);
282 backingRowMap = null;
283 }
284 }
285
286 @Override
287 public boolean containsKey(Object key) {
288 Map<C, V> backingRowMap = backingRowMap();
289 return (key != null && backingRowMap != null)
290 && Maps.safeContainsKey(backingRowMap, key);
291 }
292
293 @Override
294 public V get(Object key) {
295 Map<C, V> backingRowMap = backingRowMap();
296 return (key != null && backingRowMap != null)
297 ? Maps.safeGet(backingRowMap, key)
298 : null;
299 }
300
301 @Override
302 public V put(C key, V value) {
303 checkNotNull(key);
304 checkNotNull(value);
305 if (backingRowMap != null && !backingRowMap.isEmpty()) {
306 return backingRowMap.put(key, value);
307 }
308 return StandardTable.this.put(rowKey, key, value);
309 }
310
311 @Override
312 public V remove(Object key) {
313 Map<C, V> backingRowMap = backingRowMap();
314 if (backingRowMap == null) {
315 return null;
316 }
317 V result = Maps.safeRemove(backingRowMap, key);
318 maintainEmptyInvariant();
319 return result;
320 }
321
322 @Override
323 public void clear() {
324 Map<C, V> backingRowMap = backingRowMap();
325 if (backingRowMap != null) {
326 backingRowMap.clear();
327 }
328 maintainEmptyInvariant();
329 }
330
331 @Override
332 protected Set<Entry<C, V>> createEntrySet() {
333 return new RowEntrySet();
334 }
335
336 private final class RowEntrySet extends Maps.EntrySet<C, V> {
337 @Override
338 Map<C, V> map() {
339 return Row.this;
340 }
341
342 @Override
343 public int size() {
344 Map<C, V> map = backingRowMap();
345 return (map == null) ? 0 : map.size();
346 }
347
348 @Override
349 public Iterator<Entry<C, V>> iterator() {
350 final Map<C, V> map = backingRowMap();
351 if (map == null) {
352 return Iterators.emptyModifiableIterator();
353 }
354 final Iterator<Entry<C, V>> iterator = map.entrySet().iterator();
355 return new Iterator<Entry<C, V>>() {
356 @Override public boolean hasNext() {
357 return iterator.hasNext();
358 }
359 @Override public Entry<C, V> next() {
360 final Entry<C, V> entry = iterator.next();
361 return new ForwardingMapEntry<C, V>() {
362 @Override protected Entry<C, V> delegate() {
363 return entry;
364 }
365 @Override public V setValue(V value) {
366 return super.setValue(checkNotNull(value));
367 }
368 @Override
369 public boolean equals(Object object) {
370
371 return standardEquals(object);
372 }
373 };
374 }
375
376 @Override
377 public void remove() {
378 iterator.remove();
379 maintainEmptyInvariant();
380 }
381 };
382 }
383 }
384 }
385
386
387
388
389
390
391
392 @Override public Map<R, V> column(C columnKey) {
393 return new Column(columnKey);
394 }
395
396 private class Column extends ImprovedAbstractMap<R, V> {
397 final C columnKey;
398
399 Column(C columnKey) {
400 this.columnKey = checkNotNull(columnKey);
401 }
402
403 @Override public V put(R key, V value) {
404 return StandardTable.this.put(key, columnKey, value);
405 }
406
407 @Override public V get(Object key) {
408 return StandardTable.this.get(key, columnKey);
409 }
410
411 @Override public boolean containsKey(Object key) {
412 return StandardTable.this.contains(key, columnKey);
413 }
414
415 @Override public V remove(Object key) {
416 return StandardTable.this.remove(key, columnKey);
417 }
418
419
420
421
422
423 boolean removeFromColumnIf(Predicate<? super Entry<R, V>> predicate) {
424 boolean changed = false;
425 Iterator<Entry<R, Map<C, V>>> iterator
426 = backingMap.entrySet().iterator();
427 while (iterator.hasNext()) {
428 Entry<R, Map<C, V>> entry = iterator.next();
429 Map<C, V> map = entry.getValue();
430 V value = map.get(columnKey);
431 if (value != null
432 && predicate.apply(Maps.immutableEntry(entry.getKey(), value))) {
433 map.remove(columnKey);
434 changed = true;
435 if (map.isEmpty()) {
436 iterator.remove();
437 }
438 }
439 }
440 return changed;
441 }
442
443 @Override Set<Entry<R, V>> createEntrySet() {
444 return new EntrySet();
445 }
446
447 private class EntrySet extends ImprovedAbstractSet<Entry<R, V>> {
448 @Override public Iterator<Entry<R, V>> iterator() {
449 return new EntrySetIterator();
450 }
451
452 @Override public int size() {
453 int size = 0;
454 for (Map<C, V> map : backingMap.values()) {
455 if (map.containsKey(columnKey)) {
456 size++;
457 }
458 }
459 return size;
460 }
461
462 @Override public boolean isEmpty() {
463 return !containsColumn(columnKey);
464 }
465
466 @Override public void clear() {
467 removeFromColumnIf(alwaysTrue());
468 }
469
470 @Override public boolean contains(Object o) {
471 if (o instanceof Entry) {
472 Entry<?, ?> entry = (Entry<?, ?>) o;
473 return containsMapping(entry.getKey(), columnKey, entry.getValue());
474 }
475 return false;
476 }
477
478 @Override public boolean remove(Object obj) {
479 if (obj instanceof Entry) {
480 Entry<?, ?> entry = (Entry<?, ?>) obj;
481 return removeMapping(entry.getKey(), columnKey, entry.getValue());
482 }
483 return false;
484 }
485
486 @Override public boolean retainAll(Collection<?> c) {
487 return removeFromColumnIf(not(in(c)));
488 }
489 }
490
491 private class EntrySetIterator extends AbstractIterator<Entry<R, V>> {
492 final Iterator<Entry<R, Map<C, V>>> iterator
493 = backingMap.entrySet().iterator();
494 @Override protected Entry<R, V> computeNext() {
495 while (iterator.hasNext()) {
496 final Entry<R, Map<C, V>> entry = iterator.next();
497 if (entry.getValue().containsKey(columnKey)) {
498 return new AbstractMapEntry<R, V>() {
499 @Override public R getKey() {
500 return entry.getKey();
501 }
502 @Override public V getValue() {
503 return entry.getValue().get(columnKey);
504 }
505 @Override public V setValue(V value) {
506 return entry.getValue().put(columnKey, checkNotNull(value));
507 }
508 };
509 }
510 }
511 return endOfData();
512 }
513 }
514
515 @Override Set<R> createKeySet() {
516 return new KeySet();
517 }
518
519 private class KeySet extends Maps.KeySet<R, V> {
520 KeySet() {
521 super(Column.this);
522 }
523
524 @Override public boolean contains(Object obj) {
525 return StandardTable.this.contains(obj, columnKey);
526 }
527
528 @Override public boolean remove(Object obj) {
529 return StandardTable.this.remove(obj, columnKey) != null;
530 }
531
532 @Override public boolean retainAll(final Collection<?> c) {
533 return removeFromColumnIf(Maps.<R>keyPredicateOnEntries(not(in(c))));
534 }
535 }
536
537 @Override
538 Collection<V> createValues() {
539 return new Values();
540 }
541
542 private class Values extends Maps.Values<R, V> {
543 Values() {
544 super(Column.this);
545 }
546
547 @Override public boolean remove(Object obj) {
548 return obj != null && removeFromColumnIf(Maps.<V>valuePredicateOnEntries(equalTo(obj)));
549 }
550
551 @Override public boolean removeAll(final Collection<?> c) {
552 return removeFromColumnIf(Maps.<V>valuePredicateOnEntries(in(c)));
553 }
554
555 @Override public boolean retainAll(final Collection<?> c) {
556 return removeFromColumnIf(Maps.<V>valuePredicateOnEntries(not(in(c))));
557 }
558 }
559 }
560
561 @Override public Set<R> rowKeySet() {
562 return rowMap().keySet();
563 }
564
565 private transient Set<C> columnKeySet;
566
567
568
569
570
571
572
573
574
575
576 @Override
577 public Set<C> columnKeySet() {
578 Set<C> result = columnKeySet;
579 return (result == null) ? columnKeySet = new ColumnKeySet() : result;
580 }
581
582 private class ColumnKeySet extends TableSet<C> {
583 @Override public Iterator<C> iterator() {
584 return createColumnKeyIterator();
585 }
586
587 @Override public int size() {
588 return Iterators.size(iterator());
589 }
590
591 @Override public boolean remove(Object obj) {
592 if (obj == null) {
593 return false;
594 }
595 boolean changed = false;
596 Iterator<Map<C, V>> iterator = backingMap.values().iterator();
597 while (iterator.hasNext()) {
598 Map<C, V> map = iterator.next();
599 if (map.keySet().remove(obj)) {
600 changed = true;
601 if (map.isEmpty()) {
602 iterator.remove();
603 }
604 }
605 }
606 return changed;
607 }
608
609 @Override public boolean removeAll(Collection<?> c) {
610 checkNotNull(c);
611 boolean changed = false;
612 Iterator<Map<C, V>> iterator = backingMap.values().iterator();
613 while (iterator.hasNext()) {
614 Map<C, V> map = iterator.next();
615
616
617 if (Iterators.removeAll(map.keySet().iterator(), c)) {
618 changed = true;
619 if (map.isEmpty()) {
620 iterator.remove();
621 }
622 }
623 }
624 return changed;
625 }
626
627 @Override public boolean retainAll(Collection<?> c) {
628 checkNotNull(c);
629 boolean changed = false;
630 Iterator<Map<C, V>> iterator = backingMap.values().iterator();
631 while (iterator.hasNext()) {
632 Map<C, V> map = iterator.next();
633 if (map.keySet().retainAll(c)) {
634 changed = true;
635 if (map.isEmpty()) {
636 iterator.remove();
637 }
638 }
639 }
640 return changed;
641 }
642
643 @Override public boolean contains(Object obj) {
644 return containsColumn(obj);
645 }
646 }
647
648
649
650
651
652 Iterator<C> createColumnKeyIterator() {
653 return new ColumnKeyIterator();
654 }
655
656 private class ColumnKeyIterator extends AbstractIterator<C> {
657
658
659 final Map<C, V> seen = factory.get();
660 final Iterator<Map<C, V>> mapIterator = backingMap.values().iterator();
661 Iterator<Entry<C, V>> entryIterator = Iterators.emptyIterator();
662
663 @Override protected C computeNext() {
664 while (true) {
665 if (entryIterator.hasNext()) {
666 Entry<C, V> entry = entryIterator.next();
667 if (!seen.containsKey(entry.getKey())) {
668 seen.put(entry.getKey(), entry.getValue());
669 return entry.getKey();
670 }
671 } else if (mapIterator.hasNext()) {
672 entryIterator = mapIterator.next().entrySet().iterator();
673 } else {
674 return endOfData();
675 }
676 }
677 }
678 }
679
680
681
682
683
684
685
686 @Override public Collection<V> values() {
687 return super.values();
688 }
689
690 private transient Map<R, Map<C, V>> rowMap;
691
692 @Override public Map<R, Map<C, V>> rowMap() {
693 Map<R, Map<C, V>> result = rowMap;
694 return (result == null) ? rowMap = createRowMap() : result;
695 }
696
697 Map<R, Map<C, V>> createRowMap() {
698 return new RowMap();
699 }
700
701 class RowMap extends ImprovedAbstractMap<R, Map<C, V>> {
702 @Override public boolean containsKey(Object key) {
703 return containsRow(key);
704 }
705
706
707 @SuppressWarnings("unchecked")
708 @Override public Map<C, V> get(Object key) {
709 return containsRow(key) ? row((R) key) : null;
710 }
711
712 @Override public Map<C, V> remove(Object key) {
713 return (key == null) ? null : backingMap.remove(key);
714 }
715
716 @Override protected Set<Entry<R, Map<C, V>>> createEntrySet() {
717 return new EntrySet();
718 }
719
720 class EntrySet extends TableSet<Entry<R, Map<C, V>>> {
721 @Override public Iterator<Entry<R, Map<C, V>>> iterator() {
722 return Maps.asMapEntryIterator(backingMap.keySet(), new Function<R, Map<C, V>>() {
723 @Override
724 public Map<C, V> apply(R rowKey) {
725 return row(rowKey);
726 }
727 });
728 }
729
730 @Override public int size() {
731 return backingMap.size();
732 }
733
734 @Override public boolean contains(Object obj) {
735 if (obj instanceof Entry) {
736 Entry<?, ?> entry = (Entry<?, ?>) obj;
737 return entry.getKey() != null
738 && entry.getValue() instanceof Map
739 && Collections2.safeContains(backingMap.entrySet(), entry);
740 }
741 return false;
742 }
743
744 @Override public boolean remove(Object obj) {
745 if (obj instanceof Entry) {
746 Entry<?, ?> entry = (Entry<?, ?>) obj;
747 return entry.getKey() != null
748 && entry.getValue() instanceof Map
749 && backingMap.entrySet().remove(entry);
750 }
751 return false;
752 }
753 }
754 }
755
756 private transient ColumnMap columnMap;
757
758 @Override public Map<C, Map<R, V>> columnMap() {
759 ColumnMap result = columnMap;
760 return (result == null) ? columnMap = new ColumnMap() : result;
761 }
762
763 private class ColumnMap extends ImprovedAbstractMap<C, Map<R, V>> {
764
765
766 @SuppressWarnings("unchecked")
767 @Override public Map<R, V> get(Object key) {
768 return containsColumn(key) ? column((C) key) : null;
769 }
770
771 @Override public boolean containsKey(Object key) {
772 return containsColumn(key);
773 }
774
775 @Override public Map<R, V> remove(Object key) {
776 return containsColumn(key) ? removeColumn(key) : null;
777 }
778
779 @Override public Set<Entry<C, Map<R, V>>> createEntrySet() {
780 return new ColumnMapEntrySet();
781 }
782
783 @Override public Set<C> keySet() {
784 return columnKeySet();
785 }
786
787 @Override Collection<Map<R, V>> createValues() {
788 return new ColumnMapValues();
789 }
790
791 class ColumnMapEntrySet extends TableSet<Entry<C, Map<R, V>>> {
792 @Override public Iterator<Entry<C, Map<R, V>>> iterator() {
793 return Maps.asMapEntryIterator(columnKeySet(), new Function<C, Map<R, V>>() {
794 @Override
795 public Map<R, V> apply(C columnKey) {
796 return column(columnKey);
797 }
798 });
799 }
800
801 @Override public int size() {
802 return columnKeySet().size();
803 }
804
805 @Override public boolean contains(Object obj) {
806 if (obj instanceof Entry) {
807 Entry<?, ?> entry = (Entry<?, ?>) obj;
808 if (containsColumn(entry.getKey())) {
809
810
811 @SuppressWarnings("unchecked")
812 C columnKey = (C) entry.getKey();
813 return get(columnKey).equals(entry.getValue());
814 }
815 }
816 return false;
817 }
818
819 @Override public boolean remove(Object obj) {
820 if (contains(obj)) {
821 Entry<?, ?> entry = (Entry<?, ?>) obj;
822 removeColumn(entry.getKey());
823 return true;
824 }
825 return false;
826 }
827
828 @Override public boolean removeAll(Collection<?> c) {
829
830
831
832
833
834
835 checkNotNull(c);
836 return Sets.removeAllImpl(this, c.iterator());
837 }
838
839 @Override public boolean retainAll(Collection<?> c) {
840 checkNotNull(c);
841 boolean changed = false;
842 for (C columnKey : Lists.newArrayList(columnKeySet().iterator())) {
843 if (!c.contains(Maps.immutableEntry(columnKey, column(columnKey)))) {
844 removeColumn(columnKey);
845 changed = true;
846 }
847 }
848 return changed;
849 }
850 }
851
852 private class ColumnMapValues extends Maps.Values<C, Map<R, V>> {
853 ColumnMapValues() {
854 super(ColumnMap.this);
855 }
856
857 @Override public boolean remove(Object obj) {
858 for (Entry<C, Map<R, V>> entry : ColumnMap.this.entrySet()) {
859 if (entry.getValue().equals(obj)) {
860 removeColumn(entry.getKey());
861 return true;
862 }
863 }
864 return false;
865 }
866
867 @Override public boolean removeAll(Collection<?> c) {
868 checkNotNull(c);
869 boolean changed = false;
870 for (C columnKey : Lists.newArrayList(columnKeySet().iterator())) {
871 if (c.contains(column(columnKey))) {
872 removeColumn(columnKey);
873 changed = true;
874 }
875 }
876 return changed;
877 }
878
879 @Override public boolean retainAll(Collection<?> c) {
880 checkNotNull(c);
881 boolean changed = false;
882 for (C columnKey : Lists.newArrayList(columnKeySet().iterator())) {
883 if (!c.contains(column(columnKey))) {
884 removeColumn(columnKey);
885 changed = true;
886 }
887 }
888 return changed;
889 }
890 }
891 }
892
893 private static final long serialVersionUID = 0;
894 }