Coverage Summary for Class: ImmutableTable (com.google.common.collect)

Class Method, % Line, %
ImmutableTable 24% (6/25) 23.1% (9/39)
ImmutableTable$Builder 37.5% (3/8) 25% (7/28)
ImmutableTable$SerializedForm 0% (0/3) 0% (0/20)
Total 25% (9/36) 18.4% (16/87)


1 /* 2  * Copyright (C) 2009 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  21 import com.google.common.annotations.GwtCompatible; 22 import com.google.common.base.MoreObjects; 23 import com.google.errorprone.annotations.CanIgnoreReturnValue; 24 import com.google.errorprone.annotations.DoNotCall; 25 import com.google.errorprone.annotations.DoNotMock; 26 import java.io.Serializable; 27 import java.util.Comparator; 28 import java.util.Iterator; 29 import java.util.List; 30 import java.util.Map; 31 import java.util.Spliterator; 32 import java.util.function.BinaryOperator; 33 import java.util.function.Function; 34 import java.util.stream.Collector; 35 import org.checkerframework.checker.nullness.qual.Nullable; 36  37 /** 38  * A {@link Table} whose contents will never change, with many other important properties detailed 39  * at {@link ImmutableCollection}. 40  * 41  * <p>See the Guava User Guide article on <a href= 42  * "https://github.com/google/guava/wiki/ImmutableCollectionsExplained"> immutable collections</a>. 43  * 44  * @author Gregory Kick 45  * @since 11.0 46  */ 47 @GwtCompatible 48 public abstract class ImmutableTable<R, C, V> extends AbstractTable<R, C, V> 49  implements Serializable { 50  51  /** 52  * Returns a {@code Collector} that accumulates elements into an {@code ImmutableTable}. Each 53  * input element is mapped to one cell in the returned table, with the rows, columns, and values 54  * generated by applying the specified functions. 55  * 56  * <p>The returned {@code Collector} will throw a {@code NullPointerException} at collection time 57  * if the row, column, or value functions return null on any input. 58  * 59  * @since 21.0 60  */ 61  public static <T, R, C, V> Collector<T, ?, ImmutableTable<R, C, V>> toImmutableTable( 62  Function<? super T, ? extends R> rowFunction, 63  Function<? super T, ? extends C> columnFunction, 64  Function<? super T, ? extends V> valueFunction) { 65  return TableCollectors.toImmutableTable(rowFunction, columnFunction, valueFunction); 66  } 67  68  /** 69  * Returns a {@code Collector} that accumulates elements into an {@code ImmutableTable}. Each 70  * input element is mapped to one cell in the returned table, with the rows, columns, and values 71  * generated by applying the specified functions. If multiple inputs are mapped to the same row 72  * and column pair, they will be combined with the specified merging function in encounter order. 73  * 74  * <p>The returned {@code Collector} will throw a {@code NullPointerException} at collection time 75  * if the row, column, value, or merging functions return null on any input. 76  * 77  * @since 21.0 78  */ 79  public static <T, R, C, V> Collector<T, ?, ImmutableTable<R, C, V>> toImmutableTable( 80  Function<? super T, ? extends R> rowFunction, 81  Function<? super T, ? extends C> columnFunction, 82  Function<? super T, ? extends V> valueFunction, 83  BinaryOperator<V> mergeFunction) { 84  return TableCollectors.toImmutableTable( 85  rowFunction, columnFunction, valueFunction, mergeFunction); 86  } 87  88  /** 89  * Returns an empty immutable table. 90  * 91  * <p><b>Performance note:</b> the instance returned is a singleton. 92  */ 93  @SuppressWarnings("unchecked") 94  public static <R, C, V> ImmutableTable<R, C, V> of() { 95  return (ImmutableTable<R, C, V>) SparseImmutableTable.EMPTY; 96  } 97  98  /** Returns an immutable table containing a single cell. */ 99  public static <R, C, V> ImmutableTable<R, C, V> of(R rowKey, C columnKey, V value) { 100  return new SingletonImmutableTable<>(rowKey, columnKey, value); 101  } 102  103  /** 104  * Returns an immutable copy of the provided table. 105  * 106  * <p>The {@link Table#cellSet()} iteration order of the provided table determines the iteration 107  * ordering of all views in the returned table. Note that some views of the original table and the 108  * copied table may have different iteration orders. For more control over the ordering, create a 109  * {@link Builder} and call {@link Builder#orderRowsBy}, {@link Builder#orderColumnsBy}, and 110  * {@link Builder#putAll} 111  * 112  * <p>Despite the method name, this method attempts to avoid actually copying the data when it is 113  * safe to do so. The exact circumstances under which a copy will or will not be performed are 114  * undocumented and subject to change. 115  */ 116  public static <R, C, V> ImmutableTable<R, C, V> copyOf( 117  Table<? extends R, ? extends C, ? extends V> table) { 118  if (table instanceof ImmutableTable) { 119  @SuppressWarnings("unchecked") 120  ImmutableTable<R, C, V> parameterizedTable = (ImmutableTable<R, C, V>) table; 121  return parameterizedTable; 122  } else { 123  return copyOf(table.cellSet()); 124  } 125  } 126  127  static <R, C, V> ImmutableTable<R, C, V> copyOf( 128  Iterable<? extends Cell<? extends R, ? extends C, ? extends V>> cells) { 129  ImmutableTable.Builder<R, C, V> builder = ImmutableTable.builder(); 130  for (Cell<? extends R, ? extends C, ? extends V> cell : cells) { 131  builder.put(cell); 132  } 133  return builder.build(); 134  } 135  136  /** 137  * Returns a new builder. The generated builder is equivalent to the builder created by the {@link 138  * Builder#Builder() ImmutableTable.Builder()} constructor. 139  */ 140  public static <R, C, V> Builder<R, C, V> builder() { 141  return new Builder<>(); 142  } 143  144  /** 145  * Verifies that {@code rowKey}, {@code columnKey} and {@code value} are non-null, and returns a 146  * new entry with those values. 147  */ 148  static <R, C, V> Cell<R, C, V> cellOf(R rowKey, C columnKey, V value) { 149  return Tables.immutableCell( 150  checkNotNull(rowKey, "rowKey"), 151  checkNotNull(columnKey, "columnKey"), 152  checkNotNull(value, "value")); 153  } 154  155  /** 156  * A builder for creating immutable table instances, especially {@code public static final} tables 157  * ("constant tables"). Example: 158  * 159  * <pre>{@code 160  * static final ImmutableTable<Integer, Character, String> SPREADSHEET = 161  * new ImmutableTable.Builder<Integer, Character, String>() 162  * .put(1, 'A', "foo") 163  * .put(1, 'B', "bar") 164  * .put(2, 'A', "baz") 165  * .build(); 166  * }</pre> 167  * 168  * <p>By default, the order in which cells are added to the builder determines the iteration 169  * ordering of all views in the returned table, with {@link #putAll} following the {@link 170  * Table#cellSet()} iteration order. However, if {@link #orderRowsBy} or {@link #orderColumnsBy} 171  * is called, the views are sorted by the supplied comparators. 172  * 173  * <p>For empty or single-cell immutable tables, {@link #of()} and {@link #of(Object, Object, 174  * Object)} are even more convenient. 175  * 176  * <p>Builder instances can be reused - it is safe to call {@link #build} multiple times to build 177  * multiple tables in series. Each table is a superset of the tables created before it. 178  * 179  * @since 11.0 180  */ 181  @DoNotMock 182  public static final class Builder<R, C, V> { 183  private final List<Cell<R, C, V>> cells = Lists.newArrayList(); 184  private @Nullable Comparator<? super R> rowComparator; 185  private @Nullable Comparator<? super C> columnComparator; 186  187  /** 188  * Creates a new builder. The returned builder is equivalent to the builder generated by {@link 189  * ImmutableTable#builder}. 190  */ 191  public Builder() {} 192  193  /** Specifies the ordering of the generated table's rows. */ 194  @CanIgnoreReturnValue 195  public Builder<R, C, V> orderRowsBy(Comparator<? super R> rowComparator) { 196  this.rowComparator = checkNotNull(rowComparator, "rowComparator"); 197  return this; 198  } 199  200  /** Specifies the ordering of the generated table's columns. */ 201  @CanIgnoreReturnValue 202  public Builder<R, C, V> orderColumnsBy(Comparator<? super C> columnComparator) { 203  this.columnComparator = checkNotNull(columnComparator, "columnComparator"); 204  return this; 205  } 206  207  /** 208  * Associates the ({@code rowKey}, {@code columnKey}) pair with {@code value} in the built 209  * table. Duplicate key pairs are not allowed and will cause {@link #build} to fail. 210  */ 211  @CanIgnoreReturnValue 212  public Builder<R, C, V> put(R rowKey, C columnKey, V value) { 213  cells.add(cellOf(rowKey, columnKey, value)); 214  return this; 215  } 216  217  /** 218  * Adds the given {@code cell} to the table, making it immutable if necessary. Duplicate key 219  * pairs are not allowed and will cause {@link #build} to fail. 220  */ 221  @CanIgnoreReturnValue 222  public Builder<R, C, V> put(Cell<? extends R, ? extends C, ? extends V> cell) { 223  if (cell instanceof Tables.ImmutableCell) { 224  checkNotNull(cell.getRowKey(), "row"); 225  checkNotNull(cell.getColumnKey(), "column"); 226  checkNotNull(cell.getValue(), "value"); 227  @SuppressWarnings("unchecked") // all supported methods are covariant 228  Cell<R, C, V> immutableCell = (Cell<R, C, V>) cell; 229  cells.add(immutableCell); 230  } else { 231  put(cell.getRowKey(), cell.getColumnKey(), cell.getValue()); 232  } 233  return this; 234  } 235  236  /** 237  * Associates all of the given table's keys and values in the built table. Duplicate row key 238  * column key pairs are not allowed, and will cause {@link #build} to fail. 239  * 240  * @throws NullPointerException if any key or value in {@code table} is null 241  */ 242  @CanIgnoreReturnValue 243  public Builder<R, C, V> putAll(Table<? extends R, ? extends C, ? extends V> table) { 244  for (Cell<? extends R, ? extends C, ? extends V> cell : table.cellSet()) { 245  put(cell); 246  } 247  return this; 248  } 249  250  @CanIgnoreReturnValue 251  Builder<R, C, V> combine(Builder<R, C, V> other) { 252  this.cells.addAll(other.cells); 253  return this; 254  } 255  256  /** 257  * Returns a newly-created immutable table. 258  * 259  * @throws IllegalArgumentException if duplicate key pairs were added 260  */ 261  public ImmutableTable<R, C, V> build() { 262  int size = cells.size(); 263  switch (size) { 264  case 0: 265  return of(); 266  case 1: 267  return new SingletonImmutableTable<>(Iterables.getOnlyElement(cells)); 268  default: 269  return RegularImmutableTable.forCells(cells, rowComparator, columnComparator); 270  } 271  } 272  } 273  274  ImmutableTable() {} 275  276  @Override 277  public ImmutableSet<Cell<R, C, V>> cellSet() { 278  return (ImmutableSet<Cell<R, C, V>>) super.cellSet(); 279  } 280  281  @Override 282  abstract ImmutableSet<Cell<R, C, V>> createCellSet(); 283  284  @Override 285  final UnmodifiableIterator<Cell<R, C, V>> cellIterator() { 286  throw new AssertionError("should never be called"); 287  } 288  289  @Override 290  final Spliterator<Cell<R, C, V>> cellSpliterator() { 291  throw new AssertionError("should never be called"); 292  } 293  294  @Override 295  public ImmutableCollection<V> values() { 296  return (ImmutableCollection<V>) super.values(); 297  } 298  299  @Override 300  abstract ImmutableCollection<V> createValues(); 301  302  @Override 303  final Iterator<V> valuesIterator() { 304  throw new AssertionError("should never be called"); 305  } 306  307  /** 308  * {@inheritDoc} 309  * 310  * @throws NullPointerException if {@code columnKey} is {@code null} 311  */ 312  @Override 313  public ImmutableMap<R, V> column(C columnKey) { 314  checkNotNull(columnKey, "columnKey"); 315  return MoreObjects.firstNonNull( 316  (ImmutableMap<R, V>) columnMap().get(columnKey), ImmutableMap.<R, V>of()); 317  } 318  319  @Override 320  public ImmutableSet<C> columnKeySet() { 321  return columnMap().keySet(); 322  } 323  324  /** 325  * {@inheritDoc} 326  * 327  * <p>The value {@code Map<R, V>} instances in the returned map are {@link ImmutableMap} instances 328  * as well. 329  */ 330  @Override 331  public abstract ImmutableMap<C, Map<R, V>> columnMap(); 332  333  /** 334  * {@inheritDoc} 335  * 336  * @throws NullPointerException if {@code rowKey} is {@code null} 337  */ 338  @Override 339  public ImmutableMap<C, V> row(R rowKey) { 340  checkNotNull(rowKey, "rowKey"); 341  return MoreObjects.firstNonNull( 342  (ImmutableMap<C, V>) rowMap().get(rowKey), ImmutableMap.<C, V>of()); 343  } 344  345  @Override 346  public ImmutableSet<R> rowKeySet() { 347  return rowMap().keySet(); 348  } 349  350  /** 351  * {@inheritDoc} 352  * 353  * <p>The value {@code Map<C, V>} instances in the returned map are {@link ImmutableMap} instances 354  * as well. 355  */ 356  @Override 357  public abstract ImmutableMap<R, Map<C, V>> rowMap(); 358  359  @Override 360  public boolean contains(@Nullable Object rowKey, @Nullable Object columnKey) { 361  return get(rowKey, columnKey) != null; 362  } 363  364  @Override 365  public boolean containsValue(@Nullable Object value) { 366  return values().contains(value); 367  } 368  369  /** 370  * Guaranteed to throw an exception and leave the table unmodified. 371  * 372  * @throws UnsupportedOperationException always 373  * @deprecated Unsupported operation. 374  */ 375  @Deprecated 376  @Override 377  @DoNotCall("Always throws UnsupportedOperationException") 378  public final void clear() { 379  throw new UnsupportedOperationException(); 380  } 381  382  /** 383  * Guaranteed to throw an exception and leave the table unmodified. 384  * 385  * @throws UnsupportedOperationException always 386  * @deprecated Unsupported operation. 387  */ 388  @CanIgnoreReturnValue 389  @Deprecated 390  @Override 391  @DoNotCall("Always throws UnsupportedOperationException") 392  public final V put(R rowKey, C columnKey, V value) { 393  throw new UnsupportedOperationException(); 394  } 395  396  /** 397  * Guaranteed to throw an exception and leave the table unmodified. 398  * 399  * @throws UnsupportedOperationException always 400  * @deprecated Unsupported operation. 401  */ 402  @Deprecated 403  @Override 404  @DoNotCall("Always throws UnsupportedOperationException") 405  public final void putAll(Table<? extends R, ? extends C, ? extends V> table) { 406  throw new UnsupportedOperationException(); 407  } 408  409  /** 410  * Guaranteed to throw an exception and leave the table unmodified. 411  * 412  * @throws UnsupportedOperationException always 413  * @deprecated Unsupported operation. 414  */ 415  @CanIgnoreReturnValue 416  @Deprecated 417  @Override 418  @DoNotCall("Always throws UnsupportedOperationException") 419  public final V remove(Object rowKey, Object columnKey) { 420  throw new UnsupportedOperationException(); 421  } 422  423  /** Creates the common serialized form for this table. */ 424  abstract SerializedForm createSerializedForm(); 425  426  /** 427  * Serialized type for all ImmutableTable instances. It captures the logical contents and 428  * preserves iteration order of all views. 429  */ 430  static final class SerializedForm implements Serializable { 431  private final Object[] rowKeys; 432  private final Object[] columnKeys; 433  434  private final Object[] cellValues; 435  private final int[] cellRowIndices; 436  private final int[] cellColumnIndices; 437  438  private SerializedForm( 439  Object[] rowKeys, 440  Object[] columnKeys, 441  Object[] cellValues, 442  int[] cellRowIndices, 443  int[] cellColumnIndices) { 444  this.rowKeys = rowKeys; 445  this.columnKeys = columnKeys; 446  this.cellValues = cellValues; 447  this.cellRowIndices = cellRowIndices; 448  this.cellColumnIndices = cellColumnIndices; 449  } 450  451  static SerializedForm create( 452  ImmutableTable<?, ?, ?> table, int[] cellRowIndices, int[] cellColumnIndices) { 453  return new SerializedForm( 454  table.rowKeySet().toArray(), 455  table.columnKeySet().toArray(), 456  table.values().toArray(), 457  cellRowIndices, 458  cellColumnIndices); 459  } 460  461  Object readResolve() { 462  if (cellValues.length == 0) { 463  return of(); 464  } 465  if (cellValues.length == 1) { 466  return of(rowKeys[0], columnKeys[0], cellValues[0]); 467  } 468  ImmutableList.Builder<Cell<Object, Object, Object>> cellListBuilder = 469  new ImmutableList.Builder<>(cellValues.length); 470  for (int i = 0; i < cellValues.length; i++) { 471  cellListBuilder.add( 472  cellOf(rowKeys[cellRowIndices[i]], columnKeys[cellColumnIndices[i]], cellValues[i])); 473  } 474  return RegularImmutableTable.forOrderedComponents( 475  cellListBuilder.build(), ImmutableSet.copyOf(rowKeys), ImmutableSet.copyOf(columnKeys)); 476  } 477  478  private static final long serialVersionUID = 0; 479  } 480  481  final Object writeReplace() { 482  return createSerializedForm(); 483  } 484 }