001/*
002 * Copyright (C) 2009 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.checkNotNull;
020
021import com.google.common.annotations.GwtCompatible;
022import com.google.common.base.Objects;
023
024import java.util.Comparator;
025import java.util.Iterator;
026import java.util.List;
027import java.util.Map;
028
029import javax.annotation.Nullable;
030
031/**
032 * An immutable {@link Table} with reliable user-specified iteration order.
033 * Does not permit null keys or values.
034 *
035 * <p><b>Note</b>: Although this class is not final, it cannot be subclassed as
036 * it has no public or protected constructors. Thus, instances of this class are
037 * guaranteed to be immutable.
038 *
039 * <p>See the Guava User Guide article on <a href=
040 * "http://code.google.com/p/guava-libraries/wiki/ImmutableCollectionsExplained">
041 * immutable collections</a>.
042 *
043 * @author Gregory Kick
044 * @since 11.0
045 */
046@GwtCompatible
047// TODO(gak): make serializable
048public abstract class ImmutableTable<R, C, V> extends AbstractTable<R, C, V> {
049  private static final ImmutableTable<Object, Object, Object> EMPTY
050    = new SparseImmutableTable<Object, Object, Object>(
051        ImmutableList.<Cell<Object, Object, Object>>of(),
052        ImmutableSet.of(), ImmutableSet.of());
053  
054  /** Returns an empty immutable table. */
055  @SuppressWarnings("unchecked")
056  public static <R, C, V> ImmutableTable<R, C, V> of() {
057    return (ImmutableTable<R, C, V>) EMPTY;
058  }
059
060  /** Returns an immutable table containing a single cell. */
061  public static <R, C, V> ImmutableTable<R, C, V> of(R rowKey,
062      C columnKey, V value) {
063    return new SingletonImmutableTable<R, C, V>(rowKey, columnKey, value);
064  }
065
066  /**
067   * Returns an immutable copy of the provided table.
068   *
069   * <p>The {@link Table#cellSet()} iteration order of the provided table
070   * determines the iteration ordering of all views in the returned table. Note
071   * that some views of the original table and the copied table may have
072   * different iteration orders. For more control over the ordering, create a
073   * {@link Builder} and call {@link Builder#orderRowsBy},
074   * {@link Builder#orderColumnsBy}, and {@link Builder#putAll}
075   *
076   * <p>Despite the method name, this method attempts to avoid actually copying
077   * the data when it is safe to do so. The exact circumstances under which a
078   * copy will or will not be performed are undocumented and subject to change.
079   */
080  public static <R, C, V> ImmutableTable<R, C, V> copyOf(
081      Table<? extends R, ? extends C, ? extends V> table) {
082    if (table instanceof ImmutableTable) {
083      @SuppressWarnings("unchecked")
084      ImmutableTable<R, C, V> parameterizedTable
085          = (ImmutableTable<R, C, V>) table;
086      return parameterizedTable;
087    } else {
088      int size = table.size();
089      switch (size) {
090        case 0:
091          return of();
092        case 1:
093          Cell<? extends R, ? extends C, ? extends V> onlyCell
094              = Iterables.getOnlyElement(table.cellSet());
095          return ImmutableTable.<R, C, V>of(onlyCell.getRowKey(),
096              onlyCell.getColumnKey(), onlyCell.getValue());
097        default:
098          ImmutableSet.Builder<Cell<R, C, V>> cellSetBuilder
099              = 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   */
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   */
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     */
166    public Builder() {}
167
168    /**
169     * Specifies the ordering of the generated table's rows.
170     */
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     */
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     */
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     */
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     */
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     */
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
250  ImmutableTable() {}
251
252  @Override public ImmutableSet<Cell<R, C, V>> cellSet() {
253    return (ImmutableSet<Cell<R, C, V>>) super.cellSet();
254  }
255
256  @Override
257  abstract ImmutableSet<Cell<R, C, V>> createCellSet();
258
259  @Override
260  final UnmodifiableIterator<Cell<R, C, V>> cellIterator() {
261    throw new AssertionError("should never be called");
262  }
263
264  @Override
265  public ImmutableCollection<V> values() {
266    return (ImmutableCollection<V>) super.values();
267  }
268
269  @Override
270  abstract ImmutableCollection<V> createValues();
271
272  @Override
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   */
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
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   */
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   */
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
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   */
323  @Override public abstract ImmutableMap<R, Map<C, V>> rowMap();
324
325  @Override
326  public boolean contains(@Nullable Object rowKey, @Nullable Object columnKey) {
327    return get(rowKey, columnKey) != null;    
328  }
329
330  @Override
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   */
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   */
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   */
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   */
372  @Deprecated @Override public final V remove(Object rowKey, Object columnKey) {
373    throw new UnsupportedOperationException();
374  }
375}