• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.checkArgument;
20 import static com.google.common.base.Preconditions.checkNotNull;
21 import static com.google.common.collect.NullnessCasts.uncheckedCastNullableTToT;
22 
23 import com.google.common.annotations.GwtCompatible;
24 import com.google.common.base.Function;
25 import com.google.common.base.Objects;
26 import com.google.common.base.Supplier;
27 import com.google.common.collect.Table.Cell;
28 import java.io.Serializable;
29 import java.util.Collection;
30 import java.util.Collections;
31 import java.util.Iterator;
32 import java.util.Map;
33 import java.util.Set;
34 import java.util.SortedMap;
35 import java.util.SortedSet;
36 import java.util.function.BinaryOperator;
37 import java.util.stream.Collector;
38 import javax.annotation.CheckForNull;
39 import org.checkerframework.checker.nullness.qual.Nullable;
40 
41 /**
42  * Provides static methods that involve a {@code Table}.
43  *
44  * <p>See the Guava User Guide article on <a href=
45  * "https://github.com/google/guava/wiki/CollectionUtilitiesExplained#tables">{@code Tables}</a>.
46  *
47  * @author Jared Levy
48  * @author Louis Wasserman
49  * @since 7.0
50  */
51 @GwtCompatible
52 @ElementTypesAreNonnullByDefault
53 public final class Tables {
Tables()54   private Tables() {}
55 
56   /**
57    * Returns a {@link Collector} that accumulates elements into a {@code Table} created using the
58    * specified supplier, whose cells are generated by applying the provided mapping functions to the
59    * input elements. Cells are inserted into the generated {@code Table} in encounter order.
60    *
61    * <p>If multiple input elements map to the same row and column, an {@code IllegalStateException}
62    * is thrown when the collection operation is performed.
63    *
64    * <p>To collect to an {@link ImmutableTable}, use {@link ImmutableTable#toImmutableTable}.
65    */
66   @SuppressWarnings({"AndroidJdkLibsChecker", "Java7ApiChecker"})
67   @IgnoreJRERequirement // Users will use this only if they're already using streams.
68   static <
69           T extends @Nullable Object,
70           R extends @Nullable Object,
71           C extends @Nullable Object,
72           V extends @Nullable Object,
73           I extends Table<R, C, V>>
toTable( java.util.function.Function<? super T, ? extends R> rowFunction, java.util.function.Function<? super T, ? extends C> columnFunction, java.util.function.Function<? super T, ? extends V> valueFunction, java.util.function.Supplier<I> tableSupplier)74       Collector<T, ?, I> toTable(
75           java.util.function.Function<? super T, ? extends R> rowFunction,
76           java.util.function.Function<? super T, ? extends C> columnFunction,
77           java.util.function.Function<? super T, ? extends V> valueFunction,
78           java.util.function.Supplier<I> tableSupplier) {
79     return TableCollectors.<T, R, C, V, I>toTable(
80         rowFunction, columnFunction, valueFunction, tableSupplier);
81   }
82 
83   /**
84    * Returns a {@link Collector} that accumulates elements into a {@code Table} created using the
85    * specified supplier, whose cells are generated by applying the provided mapping functions to the
86    * input elements. Cells are inserted into the generated {@code Table} in encounter order.
87    *
88    * <p>If multiple input elements map to the same row and column, the specified merging function is
89    * used to combine the values. Like {@link
90    * java.util.stream.Collectors#toMap(java.util.function.Function, java.util.function.Function,
91    * BinaryOperator, java.util.function.Supplier)}, this Collector throws a {@code
92    * NullPointerException} on null values returned from {@code valueFunction}, and treats nulls
93    * returned from {@code mergeFunction} as removals of that row/column pair.
94    */
95   @SuppressWarnings({"AndroidJdkLibsChecker", "Java7ApiChecker"})
96   @IgnoreJRERequirement // Users will use this only if they're already using streams.
97   static <
98           T extends @Nullable Object,
99           R extends @Nullable Object,
100           C extends @Nullable Object,
101           V extends @Nullable Object,
102           I extends Table<R, C, V>>
toTable( java.util.function.Function<? super T, ? extends R> rowFunction, java.util.function.Function<? super T, ? extends C> columnFunction, java.util.function.Function<? super T, ? extends V> valueFunction, BinaryOperator<V> mergeFunction, java.util.function.Supplier<I> tableSupplier)103       Collector<T, ?, I> toTable(
104           java.util.function.Function<? super T, ? extends R> rowFunction,
105           java.util.function.Function<? super T, ? extends C> columnFunction,
106           java.util.function.Function<? super T, ? extends V> valueFunction,
107           BinaryOperator<V> mergeFunction,
108           java.util.function.Supplier<I> tableSupplier) {
109     return TableCollectors.<T, R, C, V, I>toTable(
110         rowFunction, columnFunction, valueFunction, mergeFunction, tableSupplier);
111   }
112 
113   /**
114    * Returns an immutable cell with the specified row key, column key, and value.
115    *
116    * <p>The returned cell is serializable.
117    *
118    * @param rowKey the row key to be associated with the returned cell
119    * @param columnKey the column key to be associated with the returned cell
120    * @param value the value to be associated with the returned cell
121    */
122   public static <R extends @Nullable Object, C extends @Nullable Object, V extends @Nullable Object>
immutableCell( @arametricNullness R rowKey, @ParametricNullness C columnKey, @ParametricNullness V value)123       Cell<R, C, V> immutableCell(
124           @ParametricNullness R rowKey,
125           @ParametricNullness C columnKey,
126           @ParametricNullness V value) {
127     return new ImmutableCell<>(rowKey, columnKey, value);
128   }
129 
130   static final class ImmutableCell<
131           R extends @Nullable Object, C extends @Nullable Object, V extends @Nullable Object>
132       extends AbstractCell<R, C, V> implements Serializable {
133     @ParametricNullness private final R rowKey;
134     @ParametricNullness private final C columnKey;
135     @ParametricNullness private final V value;
136 
ImmutableCell( @arametricNullness R rowKey, @ParametricNullness C columnKey, @ParametricNullness V value)137     ImmutableCell(
138         @ParametricNullness R rowKey,
139         @ParametricNullness C columnKey,
140         @ParametricNullness V value) {
141       this.rowKey = rowKey;
142       this.columnKey = columnKey;
143       this.value = value;
144     }
145 
146     @Override
147     @ParametricNullness
getRowKey()148     public R getRowKey() {
149       return rowKey;
150     }
151 
152     @Override
153     @ParametricNullness
getColumnKey()154     public C getColumnKey() {
155       return columnKey;
156     }
157 
158     @Override
159     @ParametricNullness
getValue()160     public V getValue() {
161       return value;
162     }
163 
164     private static final long serialVersionUID = 0;
165   }
166 
167   abstract static class AbstractCell<
168           R extends @Nullable Object, C extends @Nullable Object, V extends @Nullable Object>
169       implements Cell<R, C, V> {
170     // needed for serialization
AbstractCell()171     AbstractCell() {}
172 
173     @Override
equals(@heckForNull Object obj)174     public boolean equals(@CheckForNull Object obj) {
175       if (obj == this) {
176         return true;
177       }
178       if (obj instanceof Cell) {
179         Cell<?, ?, ?> other = (Cell<?, ?, ?>) obj;
180         return Objects.equal(getRowKey(), other.getRowKey())
181             && Objects.equal(getColumnKey(), other.getColumnKey())
182             && Objects.equal(getValue(), other.getValue());
183       }
184       return false;
185     }
186 
187     @Override
hashCode()188     public int hashCode() {
189       return Objects.hashCode(getRowKey(), getColumnKey(), getValue());
190     }
191 
192     @Override
toString()193     public String toString() {
194       return "(" + getRowKey() + "," + getColumnKey() + ")=" + getValue();
195     }
196   }
197 
198   /**
199    * Creates a transposed view of a given table that flips its row and column keys. In other words,
200    * calling {@code get(columnKey, rowKey)} on the generated table always returns the same value as
201    * calling {@code get(rowKey, columnKey)} on the original table. Updating the original table
202    * changes the contents of the transposed table and vice versa.
203    *
204    * <p>The returned table supports update operations as long as the input table supports the
205    * analogous operation with swapped rows and columns. For example, in a {@link HashBasedTable}
206    * instance, {@code rowKeySet().iterator()} supports {@code remove()} but {@code
207    * columnKeySet().iterator()} doesn't. With a transposed {@link HashBasedTable}, it's the other
208    * way around.
209    */
210   public static <R extends @Nullable Object, C extends @Nullable Object, V extends @Nullable Object>
transpose(Table<R, C, V> table)211       Table<C, R, V> transpose(Table<R, C, V> table) {
212     return (table instanceof TransposeTable)
213         ? ((TransposeTable<R, C, V>) table).original
214         : new TransposeTable<C, R, V>(table);
215   }
216 
217   private static class TransposeTable<
218           C extends @Nullable Object, R extends @Nullable Object, V extends @Nullable Object>
219       extends AbstractTable<C, R, V> {
220     final Table<R, C, V> original;
221 
TransposeTable(Table<R, C, V> original)222     TransposeTable(Table<R, C, V> original) {
223       this.original = checkNotNull(original);
224     }
225 
226     @Override
clear()227     public void clear() {
228       original.clear();
229     }
230 
231     @Override
column(@arametricNullness R columnKey)232     public Map<C, V> column(@ParametricNullness R columnKey) {
233       return original.row(columnKey);
234     }
235 
236     @Override
columnKeySet()237     public Set<R> columnKeySet() {
238       return original.rowKeySet();
239     }
240 
241     @Override
columnMap()242     public Map<R, Map<C, V>> columnMap() {
243       return original.rowMap();
244     }
245 
246     @Override
contains(@heckForNull Object rowKey, @CheckForNull Object columnKey)247     public boolean contains(@CheckForNull Object rowKey, @CheckForNull Object columnKey) {
248       return original.contains(columnKey, rowKey);
249     }
250 
251     @Override
containsColumn(@heckForNull Object columnKey)252     public boolean containsColumn(@CheckForNull Object columnKey) {
253       return original.containsRow(columnKey);
254     }
255 
256     @Override
containsRow(@heckForNull Object rowKey)257     public boolean containsRow(@CheckForNull Object rowKey) {
258       return original.containsColumn(rowKey);
259     }
260 
261     @Override
containsValue(@heckForNull Object value)262     public boolean containsValue(@CheckForNull Object value) {
263       return original.containsValue(value);
264     }
265 
266     @Override
267     @CheckForNull
get(@heckForNull Object rowKey, @CheckForNull Object columnKey)268     public V get(@CheckForNull Object rowKey, @CheckForNull Object columnKey) {
269       return original.get(columnKey, rowKey);
270     }
271 
272     @Override
273     @CheckForNull
put( @arametricNullness C rowKey, @ParametricNullness R columnKey, @ParametricNullness V value)274     public V put(
275         @ParametricNullness C rowKey,
276         @ParametricNullness R columnKey,
277         @ParametricNullness V value) {
278       return original.put(columnKey, rowKey, value);
279     }
280 
281     @Override
putAll(Table<? extends C, ? extends R, ? extends V> table)282     public void putAll(Table<? extends C, ? extends R, ? extends V> table) {
283       original.putAll(transpose(table));
284     }
285 
286     @Override
287     @CheckForNull
remove(@heckForNull Object rowKey, @CheckForNull Object columnKey)288     public V remove(@CheckForNull Object rowKey, @CheckForNull Object columnKey) {
289       return original.remove(columnKey, rowKey);
290     }
291 
292     @Override
row(@arametricNullness C rowKey)293     public Map<R, V> row(@ParametricNullness C rowKey) {
294       return original.column(rowKey);
295     }
296 
297     @Override
rowKeySet()298     public Set<C> rowKeySet() {
299       return original.columnKeySet();
300     }
301 
302     @Override
rowMap()303     public Map<C, Map<R, V>> rowMap() {
304       return original.columnMap();
305     }
306 
307     @Override
size()308     public int size() {
309       return original.size();
310     }
311 
312     @Override
values()313     public Collection<V> values() {
314       return original.values();
315     }
316 
317     // Will cast TRANSPOSE_CELL to a type that always succeeds
318     private static final Function TRANSPOSE_CELL =
319         new Function<Cell<?, ?, ?>, Cell<?, ?, ?>>() {
320           @Override
321           public Cell<?, ?, ?> apply(Cell<?, ?, ?> cell) {
322             return immutableCell(cell.getColumnKey(), cell.getRowKey(), cell.getValue());
323           }
324         };
325 
326     @SuppressWarnings("unchecked")
327     @Override
cellIterator()328     Iterator<Cell<C, R, V>> cellIterator() {
329       return Iterators.transform(
330           original.cellSet().iterator(), (Function<Cell<R, C, V>, Cell<C, R, V>>) TRANSPOSE_CELL);
331     }
332   }
333 
334   /**
335    * Creates a table that uses the specified backing map and factory. It can generate a table based
336    * on arbitrary {@link Map} classes.
337    *
338    * <p>The {@code factory}-generated and {@code backingMap} classes determine the table iteration
339    * order. However, the table's {@code row()} method returns instances of a different class than
340    * {@code factory.get()} does.
341    *
342    * <p>Call this method only when the simpler factory methods in classes like {@link
343    * HashBasedTable} and {@link TreeBasedTable} won't suffice.
344    *
345    * <p>The views returned by the {@code Table} methods {@link Table#column}, {@link
346    * Table#columnKeySet}, and {@link Table#columnMap} have iterators that don't support {@code
347    * remove()}. Otherwise, all optional operations are supported. Null row keys, columns keys, and
348    * values are not supported.
349    *
350    * <p>Lookups by row key are often faster than lookups by column key, because the data is stored
351    * in a {@code Map<R, Map<C, V>>}. A method call like {@code column(columnKey).get(rowKey)} still
352    * runs quickly, since the row key is provided. However, {@code column(columnKey).size()} takes
353    * longer, since an iteration across all row keys occurs.
354    *
355    * <p>Note that this implementation is not synchronized. If multiple threads access this table
356    * concurrently and one of the threads modifies the table, it must be synchronized externally.
357    *
358    * <p>The table is serializable if {@code backingMap}, {@code factory}, the maps generated by
359    * {@code factory}, and the table contents are all serializable.
360    *
361    * <p>Note: the table assumes complete ownership over of {@code backingMap} and the maps returned
362    * by {@code factory}. Those objects should not be manually updated and they should not use soft,
363    * weak, or phantom references.
364    *
365    * @param backingMap place to store the mapping from each row key to its corresponding column key
366    *     / value map
367    * @param factory supplier of new, empty maps that will each hold all column key / value mappings
368    *     for a given row key
369    * @throws IllegalArgumentException if {@code backingMap} is not empty
370    * @since 10.0
371    */
newCustomTable( Map<R, Map<C, V>> backingMap, Supplier<? extends Map<C, V>> factory)372   public static <R, C, V> Table<R, C, V> newCustomTable(
373       Map<R, Map<C, V>> backingMap, Supplier<? extends Map<C, V>> factory) {
374     checkArgument(backingMap.isEmpty());
375     checkNotNull(factory);
376     // TODO(jlevy): Wrap factory to validate that the supplied maps are empty?
377     return new StandardTable<>(backingMap, factory);
378   }
379 
380   /**
381    * Returns a view of a table where each value is transformed by a function. All other properties
382    * of the table, such as iteration order, are left intact.
383    *
384    * <p>Changes in the underlying table are reflected in this view. Conversely, this view supports
385    * removal operations, and these are reflected in the underlying table.
386    *
387    * <p>It's acceptable for the underlying table to contain null keys, and even null values provided
388    * that the function is capable of accepting null input. The transformed table might contain null
389    * values, if the function sometimes gives a null result.
390    *
391    * <p>The returned table is not thread-safe or serializable, even if the underlying table is.
392    *
393    * <p>The function is applied lazily, invoked when needed. This is necessary for the returned
394    * table to be a view, but it means that the function will be applied many times for bulk
395    * operations like {@link Table#containsValue} and {@code Table.toString()}. For this to perform
396    * well, {@code function} should be fast. To avoid lazy evaluation when the returned table doesn't
397    * need to be a view, copy the returned table into a new table of your choosing.
398    *
399    * @since 10.0
400    */
401   public static <
402           R extends @Nullable Object,
403           C extends @Nullable Object,
404           V1 extends @Nullable Object,
405           V2 extends @Nullable Object>
transformValues( Table<R, C, V1> fromTable, Function<? super V1, V2> function)406       Table<R, C, V2> transformValues(
407           Table<R, C, V1> fromTable, Function<? super V1, V2> function) {
408     return new TransformedTable<>(fromTable, function);
409   }
410 
411   private static class TransformedTable<
412           R extends @Nullable Object,
413           C extends @Nullable Object,
414           V1 extends @Nullable Object,
415           V2 extends @Nullable Object>
416       extends AbstractTable<R, C, V2> {
417     final Table<R, C, V1> fromTable;
418     final Function<? super V1, V2> function;
419 
TransformedTable(Table<R, C, V1> fromTable, Function<? super V1, V2> function)420     TransformedTable(Table<R, C, V1> fromTable, Function<? super V1, V2> function) {
421       this.fromTable = checkNotNull(fromTable);
422       this.function = checkNotNull(function);
423     }
424 
425     @Override
contains(@heckForNull Object rowKey, @CheckForNull Object columnKey)426     public boolean contains(@CheckForNull Object rowKey, @CheckForNull Object columnKey) {
427       return fromTable.contains(rowKey, columnKey);
428     }
429 
430     @Override
431     @CheckForNull
get(@heckForNull Object rowKey, @CheckForNull Object columnKey)432     public V2 get(@CheckForNull Object rowKey, @CheckForNull Object columnKey) {
433       // The function is passed a null input only when the table contains a null
434       // value.
435       // The cast is safe because of the contains() check.
436       return contains(rowKey, columnKey)
437           ? function.apply(uncheckedCastNullableTToT(fromTable.get(rowKey, columnKey)))
438           : null;
439     }
440 
441     @Override
size()442     public int size() {
443       return fromTable.size();
444     }
445 
446     @Override
clear()447     public void clear() {
448       fromTable.clear();
449     }
450 
451     @Override
452     @CheckForNull
put( @arametricNullness R rowKey, @ParametricNullness C columnKey, @ParametricNullness V2 value)453     public V2 put(
454         @ParametricNullness R rowKey,
455         @ParametricNullness C columnKey,
456         @ParametricNullness V2 value) {
457       throw new UnsupportedOperationException();
458     }
459 
460     @Override
putAll(Table<? extends R, ? extends C, ? extends V2> table)461     public void putAll(Table<? extends R, ? extends C, ? extends V2> table) {
462       throw new UnsupportedOperationException();
463     }
464 
465     @Override
466     @CheckForNull
remove(@heckForNull Object rowKey, @CheckForNull Object columnKey)467     public V2 remove(@CheckForNull Object rowKey, @CheckForNull Object columnKey) {
468       return contains(rowKey, columnKey)
469           // The cast is safe because of the contains() check.
470           ? function.apply(uncheckedCastNullableTToT(fromTable.remove(rowKey, columnKey)))
471           : null;
472     }
473 
474     @Override
row(@arametricNullness R rowKey)475     public Map<C, V2> row(@ParametricNullness R rowKey) {
476       return Maps.transformValues(fromTable.row(rowKey), function);
477     }
478 
479     @Override
column(@arametricNullness C columnKey)480     public Map<R, V2> column(@ParametricNullness C columnKey) {
481       return Maps.transformValues(fromTable.column(columnKey), function);
482     }
483 
cellFunction()484     Function<Cell<R, C, V1>, Cell<R, C, V2>> cellFunction() {
485       return new Function<Cell<R, C, V1>, Cell<R, C, V2>>() {
486         @Override
487         public Cell<R, C, V2> apply(Cell<R, C, V1> cell) {
488           return immutableCell(
489               cell.getRowKey(), cell.getColumnKey(), function.apply(cell.getValue()));
490         }
491       };
492     }
493 
494     @Override
cellIterator()495     Iterator<Cell<R, C, V2>> cellIterator() {
496       return Iterators.transform(fromTable.cellSet().iterator(), cellFunction());
497     }
498 
499     @Override
rowKeySet()500     public Set<R> rowKeySet() {
501       return fromTable.rowKeySet();
502     }
503 
504     @Override
columnKeySet()505     public Set<C> columnKeySet() {
506       return fromTable.columnKeySet();
507     }
508 
509     @Override
createValues()510     Collection<V2> createValues() {
511       return Collections2.transform(fromTable.values(), function);
512     }
513 
514     @Override
rowMap()515     public Map<R, Map<C, V2>> rowMap() {
516       Function<Map<C, V1>, Map<C, V2>> rowFunction =
517           new Function<Map<C, V1>, Map<C, V2>>() {
518             @Override
519             public Map<C, V2> apply(Map<C, V1> row) {
520               return Maps.transformValues(row, function);
521             }
522           };
523       return Maps.transformValues(fromTable.rowMap(), rowFunction);
524     }
525 
526     @Override
columnMap()527     public Map<C, Map<R, V2>> columnMap() {
528       Function<Map<R, V1>, Map<R, V2>> columnFunction =
529           new Function<Map<R, V1>, Map<R, V2>>() {
530             @Override
531             public Map<R, V2> apply(Map<R, V1> column) {
532               return Maps.transformValues(column, function);
533             }
534           };
535       return Maps.transformValues(fromTable.columnMap(), columnFunction);
536     }
537   }
538 
539   /**
540    * Returns an unmodifiable view of the specified table. This method allows modules to provide
541    * users with "read-only" access to internal tables. Query operations on the returned table "read
542    * through" to the specified table, and attempts to modify the returned table, whether direct or
543    * via its collection views, result in an {@code UnsupportedOperationException}.
544    *
545    * <p>The returned table will be serializable if the specified table is serializable.
546    *
547    * <p>Consider using an {@link ImmutableTable}, which is guaranteed never to change.
548    *
549    * @since 11.0
550    */
551   public static <R extends @Nullable Object, C extends @Nullable Object, V extends @Nullable Object>
552       Table<R, C, V> unmodifiableTable(Table<? extends R, ? extends C, ? extends V> table) {
553     return new UnmodifiableTable<>(table);
554   }
555 
556   private static class UnmodifiableTable<
557           R extends @Nullable Object, C extends @Nullable Object, V extends @Nullable Object>
558       extends ForwardingTable<R, C, V> implements Serializable {
559     final Table<? extends R, ? extends C, ? extends V> delegate;
560 
561     UnmodifiableTable(Table<? extends R, ? extends C, ? extends V> delegate) {
562       this.delegate = checkNotNull(delegate);
563     }
564 
565     @SuppressWarnings("unchecked") // safe, covariant cast
566     @Override
567     protected Table<R, C, V> delegate() {
568       return (Table<R, C, V>) delegate;
569     }
570 
571     @Override
572     public Set<Cell<R, C, V>> cellSet() {
573       return Collections.unmodifiableSet(super.cellSet());
574     }
575 
576     @Override
577     public void clear() {
578       throw new UnsupportedOperationException();
579     }
580 
581     @Override
582     public Map<R, V> column(@ParametricNullness C columnKey) {
583       return Collections.unmodifiableMap(super.column(columnKey));
584     }
585 
586     @Override
587     public Set<C> columnKeySet() {
588       return Collections.unmodifiableSet(super.columnKeySet());
589     }
590 
591     @Override
592     public Map<C, Map<R, V>> columnMap() {
593       Function<Map<R, V>, Map<R, V>> wrapper = unmodifiableWrapper();
594       return Collections.unmodifiableMap(Maps.transformValues(super.columnMap(), wrapper));
595     }
596 
597     @Override
598     @CheckForNull
599     public V put(
600         @ParametricNullness R rowKey,
601         @ParametricNullness C columnKey,
602         @ParametricNullness V value) {
603       throw new UnsupportedOperationException();
604     }
605 
606     @Override
607     public void putAll(Table<? extends R, ? extends C, ? extends V> table) {
608       throw new UnsupportedOperationException();
609     }
610 
611     @Override
612     @CheckForNull
613     public V remove(@CheckForNull Object rowKey, @CheckForNull Object columnKey) {
614       throw new UnsupportedOperationException();
615     }
616 
617     @Override
618     public Map<C, V> row(@ParametricNullness R rowKey) {
619       return Collections.unmodifiableMap(super.row(rowKey));
620     }
621 
622     @Override
623     public Set<R> rowKeySet() {
624       return Collections.unmodifiableSet(super.rowKeySet());
625     }
626 
627     @Override
628     public Map<R, Map<C, V>> rowMap() {
629       Function<Map<C, V>, Map<C, V>> wrapper = unmodifiableWrapper();
630       return Collections.unmodifiableMap(Maps.transformValues(super.rowMap(), wrapper));
631     }
632 
633     @Override
634     public Collection<V> values() {
635       return Collections.unmodifiableCollection(super.values());
636     }
637 
638     private static final long serialVersionUID = 0;
639   }
640 
641   /**
642    * Returns an unmodifiable view of the specified row-sorted table. This method allows modules to
643    * provide users with "read-only" access to internal tables. Query operations on the returned
644    * table "read through" to the specified table, and attempts to modify the returned table, whether
645    * direct or via its collection views, result in an {@code UnsupportedOperationException}.
646    *
647    * <p>The returned table will be serializable if the specified table is serializable.
648    *
649    * @param table the row-sorted table for which an unmodifiable view is to be returned
650    * @return an unmodifiable view of the specified table
651    * @since 11.0
652    */
653   public static <R extends @Nullable Object, C extends @Nullable Object, V extends @Nullable Object>
654       RowSortedTable<R, C, V> unmodifiableRowSortedTable(
655           RowSortedTable<R, ? extends C, ? extends V> table) {
656     /*
657      * It's not ? extends R, because it's technically not covariant in R. Specifically,
658      * table.rowMap().comparator() could return a comparator that only works for the ? extends R.
659      * Collections.unmodifiableSortedMap makes the same distinction.
660      */
661     return new UnmodifiableRowSortedMap<>(table);
662   }
663 
664   private static final class UnmodifiableRowSortedMap<
665           R extends @Nullable Object, C extends @Nullable Object, V extends @Nullable Object>
666       extends UnmodifiableTable<R, C, V> implements RowSortedTable<R, C, V> {
667 
668     public UnmodifiableRowSortedMap(RowSortedTable<R, ? extends C, ? extends V> delegate) {
669       super(delegate);
670     }
671 
672     @Override
673     protected RowSortedTable<R, C, V> delegate() {
674       return (RowSortedTable<R, C, V>) super.delegate();
675     }
676 
677     @Override
678     public SortedMap<R, Map<C, V>> rowMap() {
679       Function<Map<C, V>, Map<C, V>> wrapper = unmodifiableWrapper();
680       return Collections.unmodifiableSortedMap(Maps.transformValues(delegate().rowMap(), wrapper));
681     }
682 
683     @Override
684     public SortedSet<R> rowKeySet() {
685       return Collections.unmodifiableSortedSet(delegate().rowKeySet());
686     }
687 
688     private static final long serialVersionUID = 0;
689   }
690 
691   @SuppressWarnings("unchecked")
692   private static <K extends @Nullable Object, V extends @Nullable Object>
693       Function<Map<K, V>, Map<K, V>> unmodifiableWrapper() {
694     return (Function) UNMODIFIABLE_WRAPPER;
695   }
696 
697   private static final Function<? extends Map<?, ?>, ? extends Map<?, ?>> UNMODIFIABLE_WRAPPER =
698       new Function<Map<Object, Object>, Map<Object, Object>>() {
699         @Override
700         public Map<Object, Object> apply(Map<Object, Object> input) {
701           return Collections.unmodifiableMap(input);
702         }
703       };
704 
705   /**
706    * Returns a synchronized (thread-safe) table backed by the specified table. In order to guarantee
707    * serial access, it is critical that <b>all</b> access to the backing table is accomplished
708    * through the returned table.
709    *
710    * <p>It is imperative that the user manually synchronize on the returned table when accessing any
711    * of its collection views:
712    *
713    * <pre>{@code
714    * Table<R, C, V> table = Tables.synchronizedTable(HashBasedTable.<R, C, V>create());
715    * ...
716    * Map<C, V> row = table.row(rowKey);  // Needn't be in synchronized block
717    * ...
718    * synchronized (table) {  // Synchronizing on table, not row!
719    *   Iterator<Entry<C, V>> i = row.entrySet().iterator(); // Must be in synchronized block
720    *   while (i.hasNext()) {
721    *     foo(i.next());
722    *   }
723    * }
724    * }</pre>
725    *
726    * <p>Failure to follow this advice may result in non-deterministic behavior.
727    *
728    * <p>The returned table will be serializable if the specified table is serializable.
729    *
730    * @param table the table to be wrapped in a synchronized view
731    * @return a synchronized view of the specified table
732    * @since 22.0
733    */
734   public static <R extends @Nullable Object, C extends @Nullable Object, V extends @Nullable Object>
735       Table<R, C, V> synchronizedTable(Table<R, C, V> table) {
736     return Synchronized.table(table, null);
737   }
738 
739   static boolean equalsImpl(Table<?, ?, ?> table, @CheckForNull Object obj) {
740     if (obj == table) {
741       return true;
742     } else if (obj instanceof Table) {
743       Table<?, ?, ?> that = (Table<?, ?, ?>) obj;
744       return table.cellSet().equals(that.cellSet());
745     } else {
746       return false;
747     }
748   }
749 }
750