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 }