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.Objects; 23 24 import java.util.Comparator; 25 import java.util.Iterator; 26 import java.util.List; 27 import java.util.Map; 28 29 import javax.annotation.Nullable; 30 31 /** 32 * An immutable {@link Table} with reliable user-specified iteration order. 33 * Does not permit null keys or values. 34 * 35 * <p><b>Note</b>: Although this class is not final, it cannot be subclassed as 36 * it has no public or protected constructors. Thus, instances of this class are 37 * guaranteed to be immutable. 38 * 39 * <p>See the Guava User Guide article on <a href= 40 * "http://code.google.com/p/guava-libraries/wiki/ImmutableCollectionsExplained"> 41 * immutable collections</a>. 42 * 43 * @author Gregory Kick 44 * @since 11.0 45 */ 46 @GwtCompatible 47 // TODO(gak): make serializable 48 public abstract class ImmutableTable<R, C, V> extends AbstractTable<R, C, V> { 49 private static final ImmutableTable<Object, Object, Object> EMPTY 50 = new SparseImmutableTable<Object, Object, Object>( 51 ImmutableList.<Cell<Object, Object, Object>>of(), 52 ImmutableSet.of(), ImmutableSet.of()); 53 54 /** Returns an empty immutable table. */ 55 @SuppressWarnings("unchecked") of()56 public static <R, C, V> ImmutableTable<R, C, V> of() { 57 return (ImmutableTable<R, C, V>) EMPTY; 58 } 59 60 /** Returns an immutable table containing a single cell. */ of(R rowKey, C columnKey, V value)61 public static <R, C, V> ImmutableTable<R, C, V> of(R rowKey, 62 C columnKey, V value) { 63 return new SingletonImmutableTable<R, C, V>(rowKey, columnKey, value); 64 } 65 66 /** 67 * Returns an immutable copy of the provided table. 68 * 69 * <p>The {@link Table#cellSet()} iteration order of the provided table 70 * determines the iteration ordering of all views in the returned table. Note 71 * that some views of the original table and the copied table may have 72 * different iteration orders. For more control over the ordering, create a 73 * {@link Builder} and call {@link Builder#orderRowsBy}, 74 * {@link Builder#orderColumnsBy}, and {@link Builder#putAll} 75 * 76 * <p>Despite the method name, this method attempts to avoid actually copying 77 * the data when it is safe to do so. The exact circumstances under which a 78 * copy will or will not be performed are undocumented and subject to change. 79 */ copyOf( Table<? extends R, ? extends C, ? extends V> table)80 public static <R, C, V> ImmutableTable<R, C, V> copyOf( 81 Table<? extends R, ? extends C, ? extends V> table) { 82 if (table instanceof ImmutableTable) { 83 @SuppressWarnings("unchecked") 84 ImmutableTable<R, C, V> parameterizedTable 85 = (ImmutableTable<R, C, V>) table; 86 return parameterizedTable; 87 } else { 88 int size = table.size(); 89 switch (size) { 90 case 0: 91 return of(); 92 case 1: 93 Cell<? extends R, ? extends C, ? extends V> onlyCell 94 = Iterables.getOnlyElement(table.cellSet()); 95 return ImmutableTable.<R, C, V>of(onlyCell.getRowKey(), 96 onlyCell.getColumnKey(), onlyCell.getValue()); 97 default: 98 ImmutableSet.Builder<Cell<R, C, V>> cellSetBuilder 99 = ImmutableSet.builder(); 100 for (Cell<? extends R, ? extends C, ? extends V> cell : 101 table.cellSet()) { 102 /* 103 * Must cast to be able to create a Cell<R, C, V> rather than a 104 * Cell<? extends R, ? extends C, ? extends V> 105 */ 106 cellSetBuilder.add(cellOf((R) cell.getRowKey(), 107 (C) cell.getColumnKey(), (V) cell.getValue())); 108 } 109 return RegularImmutableTable.forCells(cellSetBuilder.build()); 110 } 111 } 112 } 113 114 /** 115 * Returns a new builder. The generated builder is equivalent to the builder 116 * created by the {@link Builder#ImmutableTable.Builder()} constructor. 117 */ builder()118 public static <R, C, V> Builder<R, C, V> builder() { 119 return new Builder<R, C, V>(); 120 } 121 122 /** 123 * Verifies that {@code rowKey}, {@code columnKey} and {@code value} are 124 * non-null, and returns a new entry with those values. 125 */ cellOf(R rowKey, C columnKey, V value)126 static <R, C, V> Cell<R, C, V> cellOf(R rowKey, C columnKey, V value) { 127 return Tables.immutableCell(checkNotNull(rowKey), checkNotNull(columnKey), 128 checkNotNull(value)); 129 } 130 131 /** 132 * A builder for creating immutable table instances, especially {@code public 133 * static final} tables ("constant tables"). Example: <pre> {@code 134 * 135 * static final ImmutableTable<Integer, Character, String> SPREADSHEET = 136 * new ImmutableTable.Builder<Integer, Character, String>() 137 * .put(1, 'A', "foo") 138 * .put(1, 'B', "bar") 139 * .put(2, 'A', "baz") 140 * .build();}</pre> 141 * 142 * <p>By default, the order in which cells are added to the builder determines 143 * the iteration ordering of all views in the returned table, with {@link 144 * #putAll} following the {@link Table#cellSet()} iteration order. However, if 145 * {@link #orderRowsBy} or {@link #orderColumnsBy} is called, the views are 146 * sorted by the supplied comparators. 147 * 148 * For empty or single-cell immutable tables, {@link #of()} and 149 * {@link #of(Object, Object, Object)} are even more convenient. 150 * 151 * <p>Builder instances can be reused - it is safe to call {@link #build} 152 * multiple times to build multiple tables in series. Each table is a superset 153 * of the tables created before it. 154 * 155 * @since 11.0 156 */ 157 public static final class Builder<R, C, V> { 158 private final List<Cell<R, C, V>> cells = Lists.newArrayList(); 159 private Comparator<? super R> rowComparator; 160 private Comparator<? super C> columnComparator; 161 162 /** 163 * Creates a new builder. The returned builder is equivalent to the builder 164 * generated by {@link ImmutableTable#builder}. 165 */ Builder()166 public Builder() {} 167 168 /** 169 * Specifies the ordering of the generated table's rows. 170 */ orderRowsBy(Comparator<? super R> rowComparator)171 public Builder<R, C, V> orderRowsBy(Comparator<? super R> rowComparator) { 172 this.rowComparator = checkNotNull(rowComparator); 173 return this; 174 } 175 176 /** 177 * Specifies the ordering of the generated table's columns. 178 */ orderColumnsBy( Comparator<? super C> columnComparator)179 public Builder<R, C, V> orderColumnsBy( 180 Comparator<? super C> columnComparator) { 181 this.columnComparator = checkNotNull(columnComparator); 182 return this; 183 } 184 185 /** 186 * Associates the ({@code rowKey}, {@code columnKey}) pair with {@code 187 * value} in the built table. Duplicate key pairs are not allowed and will 188 * cause {@link #build} to fail. 189 */ put(R rowKey, C columnKey, V value)190 public Builder<R, C, V> put(R rowKey, C columnKey, V value) { 191 cells.add(cellOf(rowKey, columnKey, value)); 192 return this; 193 } 194 195 /** 196 * Adds the given {@code cell} to the table, making it immutable if 197 * necessary. Duplicate key pairs are not allowed and will cause {@link 198 * #build} to fail. 199 */ put( Cell<? extends R, ? extends C, ? extends V> cell)200 public Builder<R, C, V> put( 201 Cell<? extends R, ? extends C, ? extends V> cell) { 202 if (cell instanceof Tables.ImmutableCell) { 203 checkNotNull(cell.getRowKey()); 204 checkNotNull(cell.getColumnKey()); 205 checkNotNull(cell.getValue()); 206 @SuppressWarnings("unchecked") // all supported methods are covariant 207 Cell<R, C, V> immutableCell = (Cell<R, C, V>) cell; 208 cells.add(immutableCell); 209 } else { 210 put(cell.getRowKey(), cell.getColumnKey(), cell.getValue()); 211 } 212 return this; 213 } 214 215 /** 216 * Associates all of the given table's keys and values in the built table. 217 * Duplicate row key column key pairs are not allowed, and will cause 218 * {@link #build} to fail. 219 * 220 * @throws NullPointerException if any key or value in {@code table} is null 221 */ putAll( Table<? extends R, ? extends C, ? extends V> table)222 public Builder<R, C, V> putAll( 223 Table<? extends R, ? extends C, ? extends V> table) { 224 for (Cell<? extends R, ? extends C, ? extends V> cell : table.cellSet()) { 225 put(cell); 226 } 227 return this; 228 } 229 230 /** 231 * Returns a newly-created immutable table. 232 * 233 * @throws IllegalArgumentException if duplicate key pairs were added 234 */ build()235 public ImmutableTable<R, C, V> build() { 236 int size = cells.size(); 237 switch (size) { 238 case 0: 239 return of(); 240 case 1: 241 return new SingletonImmutableTable<R, C, V>( 242 Iterables.getOnlyElement(cells)); 243 default: 244 return RegularImmutableTable.forCells( 245 cells, rowComparator, columnComparator); 246 } 247 } 248 } 249 ImmutableTable()250 ImmutableTable() {} 251 cellSet()252 @Override public ImmutableSet<Cell<R, C, V>> cellSet() { 253 return (ImmutableSet<Cell<R, C, V>>) super.cellSet(); 254 } 255 256 @Override createCellSet()257 abstract ImmutableSet<Cell<R, C, V>> createCellSet(); 258 259 @Override cellIterator()260 final UnmodifiableIterator<Cell<R, C, V>> cellIterator() { 261 throw new AssertionError("should never be called"); 262 } 263 264 @Override values()265 public ImmutableCollection<V> values() { 266 return (ImmutableCollection<V>) super.values(); 267 } 268 269 @Override createValues()270 abstract ImmutableCollection<V> createValues(); 271 272 @Override valuesIterator()273 final Iterator<V> valuesIterator() { 274 throw new AssertionError("should never be called"); 275 } 276 277 /** 278 * {@inheritDoc} 279 * 280 * @throws NullPointerException if {@code columnKey} is {@code null} 281 */ column(C columnKey)282 @Override public ImmutableMap<R, V> column(C columnKey) { 283 checkNotNull(columnKey); 284 return Objects.firstNonNull( 285 (ImmutableMap<R, V>) columnMap().get(columnKey), 286 ImmutableMap.<R, V>of()); 287 } 288 columnKeySet()289 @Override public ImmutableSet<C> columnKeySet() { 290 return columnMap().keySet(); 291 } 292 293 /** 294 * {@inheritDoc} 295 * 296 * <p>The value {@code Map<R, V>} instances in the returned map are 297 * {@link ImmutableMap} instances as well. 298 */ columnMap()299 @Override public abstract ImmutableMap<C, Map<R, V>> columnMap(); 300 301 /** 302 * {@inheritDoc} 303 * 304 * @throws NullPointerException if {@code rowKey} is {@code null} 305 */ row(R rowKey)306 @Override public ImmutableMap<C, V> row(R rowKey) { 307 checkNotNull(rowKey); 308 return Objects.firstNonNull( 309 (ImmutableMap<C, V>) rowMap().get(rowKey), 310 ImmutableMap.<C, V>of()); 311 } 312 rowKeySet()313 @Override public ImmutableSet<R> rowKeySet() { 314 return rowMap().keySet(); 315 } 316 317 /** 318 * {@inheritDoc} 319 * 320 * <p>The value {@code Map<C, V>} instances in the returned map are 321 * {@link ImmutableMap} instances as well. 322 */ rowMap()323 @Override public abstract ImmutableMap<R, Map<C, V>> rowMap(); 324 325 @Override contains(@ullable Object rowKey, @Nullable Object columnKey)326 public boolean contains(@Nullable Object rowKey, @Nullable Object columnKey) { 327 return get(rowKey, columnKey) != null; 328 } 329 330 @Override containsValue(@ullable Object value)331 public boolean containsValue(@Nullable Object value) { 332 return values().contains(value); 333 } 334 335 /** 336 * Guaranteed to throw an exception and leave the table unmodified. 337 * 338 * @throws UnsupportedOperationException always 339 * @deprecated Unsupported operation. 340 */ clear()341 @Deprecated @Override public final void clear() { 342 throw new UnsupportedOperationException(); 343 } 344 345 /** 346 * Guaranteed to throw an exception and leave the table unmodified. 347 * 348 * @throws UnsupportedOperationException always 349 * @deprecated Unsupported operation. 350 */ put(R rowKey, C columnKey, V value)351 @Deprecated @Override public final V put(R rowKey, C columnKey, V value) { 352 throw new UnsupportedOperationException(); 353 } 354 355 /** 356 * Guaranteed to throw an exception and leave the table unmodified. 357 * 358 * @throws UnsupportedOperationException always 359 * @deprecated Unsupported operation. 360 */ putAll( Table<? extends R, ? extends C, ? extends V> table)361 @Deprecated @Override public final void putAll( 362 Table<? extends R, ? extends C, ? extends V> table) { 363 throw new UnsupportedOperationException(); 364 } 365 366 /** 367 * Guaranteed to throw an exception and leave the table unmodified. 368 * 369 * @throws UnsupportedOperationException always 370 * @deprecated Unsupported operation. 371 */ remove(Object rowKey, Object columnKey)372 @Deprecated @Override public final V remove(Object rowKey, Object columnKey) { 373 throw new UnsupportedOperationException(); 374 } 375 } 376