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