001/*
002 * Copyright (C) 2008 The Guava Authors
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package com.google.common.collect;
018
019import static com.google.common.base.Preconditions.checkArgument;
020import static com.google.common.base.Preconditions.checkNotNull;
021
022import com.google.common.annotations.Beta;
023import com.google.common.annotations.GwtCompatible;
024import com.google.common.base.Function;
025import com.google.common.base.Objects;
026import com.google.common.base.Supplier;
027import com.google.common.collect.Table.Cell;
028
029import java.io.Serializable;
030import java.util.Collection;
031import java.util.Collections;
032import java.util.Iterator;
033import java.util.Map;
034import java.util.Set;
035import java.util.SortedMap;
036import java.util.SortedSet;
037
038import javax.annotation.Nullable;
039
040/**
041 * Provides static methods that involve a {@code Table}.
042 *
043 * <p>See the Guava User Guide article on <a href=
044 * "https://github.com/google/guava/wiki/CollectionUtilitiesExplained#tables">
045 * {@code Tables}</a>.
046 *
047 * @author Jared Levy
048 * @author Louis Wasserman
049 * @since 7.0
050 */
051@GwtCompatible
052public final class Tables {
053  private Tables() {}
054
055  /**
056   * Returns an immutable cell with the specified row key, column key, and
057   * value.
058   *
059   * <p>The returned cell is serializable.
060   *
061   * @param rowKey the row key to be associated with the returned cell
062   * @param columnKey the column key to be associated with the returned cell
063   * @param value the value to be associated with the returned cell
064   */
065  public static <R, C, V> Cell<R, C, V> immutableCell(
066      @Nullable R rowKey, @Nullable C columnKey, @Nullable V value) {
067    return new ImmutableCell<R, C, V>(rowKey, columnKey, value);
068  }
069
070  static final class ImmutableCell<R, C, V> extends AbstractCell<R, C, V> implements Serializable {
071    private final R rowKey;
072    private final C columnKey;
073    private final V value;
074
075    ImmutableCell(@Nullable R rowKey, @Nullable C columnKey, @Nullable V value) {
076      this.rowKey = rowKey;
077      this.columnKey = columnKey;
078      this.value = value;
079    }
080
081    @Override
082    public R getRowKey() {
083      return rowKey;
084    }
085
086    @Override
087    public C getColumnKey() {
088      return columnKey;
089    }
090
091    @Override
092    public V getValue() {
093      return value;
094    }
095
096    private static final long serialVersionUID = 0;
097  }
098
099  abstract static class AbstractCell<R, C, V> implements Cell<R, C, V> {
100    // needed for serialization
101    AbstractCell() {}
102
103    @Override
104    public boolean equals(Object obj) {
105      if (obj == this) {
106        return true;
107      }
108      if (obj instanceof Cell) {
109        Cell<?, ?, ?> other = (Cell<?, ?, ?>) obj;
110        return Objects.equal(getRowKey(), other.getRowKey())
111            && Objects.equal(getColumnKey(), other.getColumnKey())
112            && Objects.equal(getValue(), other.getValue());
113      }
114      return false;
115    }
116
117    @Override
118    public int hashCode() {
119      return Objects.hashCode(getRowKey(), getColumnKey(), getValue());
120    }
121
122    @Override
123    public String toString() {
124      return "(" + getRowKey() + "," + getColumnKey() + ")=" + getValue();
125    }
126  }
127
128  /**
129   * Creates a transposed view of a given table that flips its row and column
130   * keys. In other words, calling {@code get(columnKey, rowKey)} on the
131   * generated table always returns the same value as calling {@code
132   * get(rowKey, columnKey)} on the original table. Updating the original table
133   * changes the contents of the transposed table and vice versa.
134   *
135   * <p>The returned table supports update operations as long as the input table
136   * supports the analogous operation with swapped rows and columns. For
137   * example, in a {@link HashBasedTable} instance, {@code
138   * rowKeySet().iterator()} supports {@code remove()} but {@code
139   * columnKeySet().iterator()} doesn't. With a transposed {@link
140   * HashBasedTable}, it's the other way around.
141   */
142  public static <R, C, V> Table<C, R, V> transpose(Table<R, C, V> table) {
143    return (table instanceof TransposeTable)
144        ? ((TransposeTable<R, C, V>) table).original
145        : new TransposeTable<C, R, V>(table);
146  }
147
148  private static class TransposeTable<C, R, V> extends AbstractTable<C, R, V> {
149    final Table<R, C, V> original;
150
151    TransposeTable(Table<R, C, V> original) {
152      this.original = checkNotNull(original);
153    }
154
155    @Override
156    public void clear() {
157      original.clear();
158    }
159
160    @Override
161    public Map<C, V> column(R columnKey) {
162      return original.row(columnKey);
163    }
164
165    @Override
166    public Set<R> columnKeySet() {
167      return original.rowKeySet();
168    }
169
170    @Override
171    public Map<R, Map<C, V>> columnMap() {
172      return original.rowMap();
173    }
174
175    @Override
176    public boolean contains(@Nullable Object rowKey, @Nullable Object columnKey) {
177      return original.contains(columnKey, rowKey);
178    }
179
180    @Override
181    public boolean containsColumn(@Nullable Object columnKey) {
182      return original.containsRow(columnKey);
183    }
184
185    @Override
186    public boolean containsRow(@Nullable Object rowKey) {
187      return original.containsColumn(rowKey);
188    }
189
190    @Override
191    public boolean containsValue(@Nullable Object value) {
192      return original.containsValue(value);
193    }
194
195    @Override
196    public V get(@Nullable Object rowKey, @Nullable Object columnKey) {
197      return original.get(columnKey, rowKey);
198    }
199
200    @Override
201    public V put(C rowKey, R columnKey, V value) {
202      return original.put(columnKey, rowKey, value);
203    }
204
205    @Override
206    public void putAll(Table<? extends C, ? extends R, ? extends V> table) {
207      original.putAll(transpose(table));
208    }
209
210    @Override
211    public V remove(@Nullable Object rowKey, @Nullable Object columnKey) {
212      return original.remove(columnKey, rowKey);
213    }
214
215    @Override
216    public Map<R, V> row(C rowKey) {
217      return original.column(rowKey);
218    }
219
220    @Override
221    public Set<C> rowKeySet() {
222      return original.columnKeySet();
223    }
224
225    @Override
226    public Map<C, Map<R, V>> rowMap() {
227      return original.columnMap();
228    }
229
230    @Override
231    public int size() {
232      return original.size();
233    }
234
235    @Override
236    public Collection<V> values() {
237      return original.values();
238    }
239
240    // Will cast TRANSPOSE_CELL to a type that always succeeds
241    private static final Function<Cell<?, ?, ?>, Cell<?, ?, ?>> TRANSPOSE_CELL =
242        new Function<Cell<?, ?, ?>, Cell<?, ?, ?>>() {
243          @Override
244          public Cell<?, ?, ?> apply(Cell<?, ?, ?> cell) {
245            return immutableCell(cell.getColumnKey(), cell.getRowKey(), cell.getValue());
246          }
247        };
248
249    @SuppressWarnings("unchecked")
250    @Override
251    Iterator<Cell<C, R, V>> cellIterator() {
252      return Iterators.transform(original.cellSet().iterator(), (Function) TRANSPOSE_CELL);
253    }
254  }
255
256  /**
257   * Creates a table that uses the specified backing map and factory. It can
258   * generate a table based on arbitrary {@link Map} classes.
259   *
260   * <p>The {@code factory}-generated and {@code backingMap} classes determine
261   * the table iteration order. However, the table's {@code row()} method
262   * returns instances of a different class than {@code factory.get()} does.
263   *
264   * <p>Call this method only when the simpler factory methods in classes like
265   * {@link HashBasedTable} and {@link TreeBasedTable} won't suffice.
266   *
267   * <p>The views returned by the {@code Table} methods {@link Table#column},
268   * {@link Table#columnKeySet}, and {@link Table#columnMap} have iterators that
269   * don't support {@code remove()}. Otherwise, all optional operations are
270   * supported. Null row keys, columns keys, and values are not supported.
271   *
272   * <p>Lookups by row key are often faster than lookups by column key, because
273   * the data is stored in a {@code Map<R, Map<C, V>>}. A method call like
274   * {@code column(columnKey).get(rowKey)} still runs quickly, since the row key
275   * is provided. However, {@code column(columnKey).size()} takes longer, since
276   * an iteration across all row keys occurs.
277   *
278   * <p>Note that this implementation is not synchronized. If multiple threads
279   * access this table concurrently and one of the threads modifies the table,
280   * it must be synchronized externally.
281   *
282   * <p>The table is serializable if {@code backingMap}, {@code factory}, the
283   * maps generated by {@code factory}, and the table contents are all
284   * serializable.
285   *
286   * <p>Note: the table assumes complete ownership over of {@code backingMap}
287   * and the maps returned by {@code factory}. Those objects should not be
288   * manually updated and they should not use soft, weak, or phantom references.
289   *
290   * @param backingMap place to store the mapping from each row key to its
291   *     corresponding column key / value map
292   * @param factory supplier of new, empty maps that will each hold all column
293   *     key / value mappings for a given row key
294   * @throws IllegalArgumentException if {@code backingMap} is not empty
295   * @since 10.0
296   */
297  @Beta
298  public static <R, C, V> Table<R, C, V> newCustomTable(
299      Map<R, Map<C, V>> backingMap, Supplier<? extends Map<C, V>> factory) {
300    checkArgument(backingMap.isEmpty());
301    checkNotNull(factory);
302    // TODO(jlevy): Wrap factory to validate that the supplied maps are empty?
303    return new StandardTable<R, C, V>(backingMap, factory);
304  }
305
306  /**
307   * Returns a view of a table where each value is transformed by a function.
308   * All other properties of the table, such as iteration order, are left
309   * intact.
310   *
311   * <p>Changes in the underlying table are reflected in this view. Conversely,
312   * this view supports removal operations, and these are reflected in the
313   * underlying table.
314   *
315   * <p>It's acceptable for the underlying table to contain null keys, and even
316   * null values provided that the function is capable of accepting null input.
317   * The transformed table might contain null values, if the function sometimes
318   * gives a null result.
319   *
320   * <p>The returned table is not thread-safe or serializable, even if the
321   * underlying table is.
322   *
323   * <p>The function is applied lazily, invoked when needed. This is necessary
324   * for the returned table to be a view, but it means that the function will be
325   * applied many times for bulk operations like {@link Table#containsValue} and
326   * {@code Table.toString()}. For this to perform well, {@code function} should
327   * be fast. To avoid lazy evaluation when the returned table doesn't need to
328   * be a view, copy the returned table into a new table of your choosing.
329   *
330   * @since 10.0
331   */
332  @Beta
333  public static <R, C, V1, V2> Table<R, C, V2> transformValues(
334      Table<R, C, V1> fromTable, Function<? super V1, V2> function) {
335    return new TransformedTable<R, C, V1, V2>(fromTable, function);
336  }
337
338  private static class TransformedTable<R, C, V1, V2> extends AbstractTable<R, C, V2> {
339    final Table<R, C, V1> fromTable;
340    final Function<? super V1, V2> function;
341
342    TransformedTable(Table<R, C, V1> fromTable, Function<? super V1, V2> function) {
343      this.fromTable = checkNotNull(fromTable);
344      this.function = checkNotNull(function);
345    }
346
347    @Override
348    public boolean contains(Object rowKey, Object columnKey) {
349      return fromTable.contains(rowKey, columnKey);
350    }
351
352    @Override
353    public V2 get(Object rowKey, Object columnKey) {
354      // The function is passed a null input only when the table contains a null
355      // value.
356      return contains(rowKey, columnKey) ? function.apply(fromTable.get(rowKey, columnKey)) : null;
357    }
358
359    @Override
360    public int size() {
361      return fromTable.size();
362    }
363
364    @Override
365    public void clear() {
366      fromTable.clear();
367    }
368
369    @Override
370    public V2 put(R rowKey, C columnKey, V2 value) {
371      throw new UnsupportedOperationException();
372    }
373
374    @Override
375    public void putAll(Table<? extends R, ? extends C, ? extends V2> table) {
376      throw new UnsupportedOperationException();
377    }
378
379    @Override
380    public V2 remove(Object rowKey, Object columnKey) {
381      return contains(rowKey, columnKey)
382          ? function.apply(fromTable.remove(rowKey, columnKey))
383          : null;
384    }
385
386    @Override
387    public Map<C, V2> row(R rowKey) {
388      return Maps.transformValues(fromTable.row(rowKey), function);
389    }
390
391    @Override
392    public Map<R, V2> column(C columnKey) {
393      return Maps.transformValues(fromTable.column(columnKey), function);
394    }
395
396    Function<Cell<R, C, V1>, Cell<R, C, V2>> cellFunction() {
397      return new Function<Cell<R, C, V1>, Cell<R, C, V2>>() {
398        @Override
399        public Cell<R, C, V2> apply(Cell<R, C, V1> cell) {
400          return immutableCell(
401              cell.getRowKey(), cell.getColumnKey(), function.apply(cell.getValue()));
402        }
403      };
404    }
405
406    @Override
407    Iterator<Cell<R, C, V2>> cellIterator() {
408      return Iterators.transform(fromTable.cellSet().iterator(), cellFunction());
409    }
410
411    @Override
412    public Set<R> rowKeySet() {
413      return fromTable.rowKeySet();
414    }
415
416    @Override
417    public Set<C> columnKeySet() {
418      return fromTable.columnKeySet();
419    }
420
421    @Override
422    Collection<V2> createValues() {
423      return Collections2.transform(fromTable.values(), function);
424    }
425
426    @Override
427    public Map<R, Map<C, V2>> rowMap() {
428      Function<Map<C, V1>, Map<C, V2>> rowFunction =
429          new Function<Map<C, V1>, Map<C, V2>>() {
430            @Override
431            public Map<C, V2> apply(Map<C, V1> row) {
432              return Maps.transformValues(row, function);
433            }
434          };
435      return Maps.transformValues(fromTable.rowMap(), rowFunction);
436    }
437
438    @Override
439    public Map<C, Map<R, V2>> columnMap() {
440      Function<Map<R, V1>, Map<R, V2>> columnFunction =
441          new Function<Map<R, V1>, Map<R, V2>>() {
442            @Override
443            public Map<R, V2> apply(Map<R, V1> column) {
444              return Maps.transformValues(column, function);
445            }
446          };
447      return Maps.transformValues(fromTable.columnMap(), columnFunction);
448    }
449  }
450
451  /**
452   * Returns an unmodifiable view of the specified table. This method allows modules to provide
453   * users with "read-only" access to internal tables. Query operations on the returned table
454   * "read through" to the specified table, and attempts to modify the returned table, whether
455   * direct or via its collection views, result in an {@code UnsupportedOperationException}.
456   *
457   * <p>The returned table will be serializable if the specified table is serializable.
458   *
459   * <p>Consider using an {@link ImmutableTable}, which is guaranteed never to change.
460   *
461   * @param table
462   *          the table for which an unmodifiable view is to be returned
463   * @return an unmodifiable view of the specified table
464   * @since 11.0
465   */
466  public static <R, C, V> Table<R, C, V> unmodifiableTable(
467      Table<? extends R, ? extends C, ? extends V> table) {
468    return new UnmodifiableTable<R, C, V>(table);
469  }
470
471  private static class UnmodifiableTable<R, C, V> extends ForwardingTable<R, C, V>
472      implements Serializable {
473    final Table<? extends R, ? extends C, ? extends V> delegate;
474
475    UnmodifiableTable(Table<? extends R, ? extends C, ? extends V> delegate) {
476      this.delegate = checkNotNull(delegate);
477    }
478
479    @SuppressWarnings("unchecked") // safe, covariant cast
480    @Override
481    protected Table<R, C, V> delegate() {
482      return (Table<R, C, V>) delegate;
483    }
484
485    @Override
486    public Set<Cell<R, C, V>> cellSet() {
487      return Collections.unmodifiableSet(super.cellSet());
488    }
489
490    @Override
491    public void clear() {
492      throw new UnsupportedOperationException();
493    }
494
495    @Override
496    public Map<R, V> column(@Nullable C columnKey) {
497      return Collections.unmodifiableMap(super.column(columnKey));
498    }
499
500    @Override
501    public Set<C> columnKeySet() {
502      return Collections.unmodifiableSet(super.columnKeySet());
503    }
504
505    @Override
506    public Map<C, Map<R, V>> columnMap() {
507      Function<Map<R, V>, Map<R, V>> wrapper = unmodifiableWrapper();
508      return Collections.unmodifiableMap(Maps.transformValues(super.columnMap(), wrapper));
509    }
510
511    @Override
512    public V put(@Nullable R rowKey, @Nullable C columnKey, @Nullable V value) {
513      throw new UnsupportedOperationException();
514    }
515
516    @Override
517    public void putAll(Table<? extends R, ? extends C, ? extends V> table) {
518      throw new UnsupportedOperationException();
519    }
520
521    @Override
522    public V remove(@Nullable Object rowKey, @Nullable Object columnKey) {
523      throw new UnsupportedOperationException();
524    }
525
526    @Override
527    public Map<C, V> row(@Nullable R rowKey) {
528      return Collections.unmodifiableMap(super.row(rowKey));
529    }
530
531    @Override
532    public Set<R> rowKeySet() {
533      return Collections.unmodifiableSet(super.rowKeySet());
534    }
535
536    @Override
537    public Map<R, Map<C, V>> rowMap() {
538      Function<Map<C, V>, Map<C, V>> wrapper = unmodifiableWrapper();
539      return Collections.unmodifiableMap(Maps.transformValues(super.rowMap(), wrapper));
540    }
541
542    @Override
543    public Collection<V> values() {
544      return Collections.unmodifiableCollection(super.values());
545    }
546
547    private static final long serialVersionUID = 0;
548  }
549
550  /**
551   * Returns an unmodifiable view of the specified row-sorted table. This method allows modules to
552   * provide users with "read-only" access to internal tables. Query operations on the returned
553   * table "read through" to the specified table, and attemps to modify the returned table, whether
554   * direct or via its collection views, result in an {@code UnsupportedOperationException}.
555   *
556   * <p>The returned table will be serializable if the specified table is serializable.
557   *
558   * @param table the row-sorted table for which an unmodifiable view is to be returned
559   * @return an unmodifiable view of the specified table
560   * @since 11.0
561   */
562  @Beta
563  public static <R, C, V> RowSortedTable<R, C, V> unmodifiableRowSortedTable(
564      RowSortedTable<R, ? extends C, ? extends V> table) {
565    /*
566     * It's not ? extends R, because it's technically not covariant in R. Specifically,
567     * table.rowMap().comparator() could return a comparator that only works for the ? extends R.
568     * Collections.unmodifiableSortedMap makes the same distinction.
569     */
570    return new UnmodifiableRowSortedMap<R, C, V>(table);
571  }
572
573  static final class UnmodifiableRowSortedMap<R, C, V> extends UnmodifiableTable<R, C, V>
574      implements RowSortedTable<R, C, V> {
575
576    public UnmodifiableRowSortedMap(RowSortedTable<R, ? extends C, ? extends V> delegate) {
577      super(delegate);
578    }
579
580    @Override
581    protected RowSortedTable<R, C, V> delegate() {
582      return (RowSortedTable<R, C, V>) super.delegate();
583    }
584
585    @Override
586    public SortedMap<R, Map<C, V>> rowMap() {
587      Function<Map<C, V>, Map<C, V>> wrapper = unmodifiableWrapper();
588      return Collections.unmodifiableSortedMap(Maps.transformValues(delegate().rowMap(), wrapper));
589    }
590
591    @Override
592    public SortedSet<R> rowKeySet() {
593      return Collections.unmodifiableSortedSet(delegate().rowKeySet());
594    }
595
596    private static final long serialVersionUID = 0;
597  }
598
599  @SuppressWarnings("unchecked")
600  private static <K, V> Function<Map<K, V>, Map<K, V>> unmodifiableWrapper() {
601    return (Function) UNMODIFIABLE_WRAPPER;
602  }
603
604  private static final Function<? extends Map<?, ?>, ? extends Map<?, ?>> UNMODIFIABLE_WRAPPER =
605      new Function<Map<Object, Object>, Map<Object, Object>>() {
606        @Override
607        public Map<Object, Object> apply(Map<Object, Object> input) {
608          return Collections.unmodifiableMap(input);
609        }
610      };
611
612  static boolean equalsImpl(Table<?, ?, ?> table, @Nullable Object obj) {
613    if (obj == table) {
614      return true;
615    } else if (obj instanceof Table) {
616      Table<?, ?, ?> that = (Table<?, ?, ?>) obj;
617      return table.cellSet().equals(that.cellSet());
618    } else {
619      return false;
620    }
621  }
622}