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

Class Method, % Line, %
RegularImmutableTable 62.5% (5/8) 75% (21/28)
RegularImmutableTable$1 0% (0/2) 0% (0/9)
RegularImmutableTable$CellSet 0% (0/5) 0% (0/9)
RegularImmutableTable$Values 0% (0/4) 0% (0/4)
Total 26.3% (5/19) 42% (21/50)


1 /* 2  * Copyright (C) 2009 The Guava Authors 3  * 4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5  * in compliance with the License. You may obtain a copy of the License at 6  * 7  * http://www.apache.org/licenses/LICENSE-2.0 8  * 9  * Unless required by applicable law or agreed to in writing, software distributed under the License 10  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11  * or implied. See the License for the specific language governing permissions and limitations under 12  * the License. 13  */ 14  15 package com.google.common.collect; 16  17 import static com.google.common.base.Preconditions.checkArgument; 18 import static com.google.common.base.Preconditions.checkNotNull; 19  20 import com.google.common.annotations.GwtCompatible; 21 import com.google.j2objc.annotations.WeakOuter; 22 import java.util.Collections; 23 import java.util.Comparator; 24 import java.util.LinkedHashSet; 25 import java.util.List; 26 import java.util.Set; 27 import org.checkerframework.checker.nullness.qual.Nullable; 28  29 /** 30  * An implementation of {@link ImmutableTable} holding an arbitrary number of cells. 31  * 32  * @author Gregory Kick 33  */ 34 @GwtCompatible 35 abstract class RegularImmutableTable<R, C, V> extends ImmutableTable<R, C, V> { 36  RegularImmutableTable() {} 37  38  abstract Cell<R, C, V> getCell(int iterationIndex); 39  40  @Override 41  final ImmutableSet<Cell<R, C, V>> createCellSet() { 42  return isEmpty() ? ImmutableSet.<Cell<R, C, V>>of() : new CellSet(); 43  } 44  45  @WeakOuter 46  private final class CellSet extends IndexedImmutableSet<Cell<R, C, V>> { 47  @Override 48  public int size() { 49  return RegularImmutableTable.this.size(); 50  } 51  52  @Override 53  Cell<R, C, V> get(int index) { 54  return getCell(index); 55  } 56  57  @Override 58  public boolean contains(@Nullable Object object) { 59  if (object instanceof Cell) { 60  Cell<?, ?, ?> cell = (Cell<?, ?, ?>) object; 61  Object value = RegularImmutableTable.this.get(cell.getRowKey(), cell.getColumnKey()); 62  return value != null && value.equals(cell.getValue()); 63  } 64  return false; 65  } 66  67  @Override 68  boolean isPartialView() { 69  return false; 70  } 71  } 72  73  abstract V getValue(int iterationIndex); 74  75  @Override 76  final ImmutableCollection<V> createValues() { 77  return isEmpty() ? ImmutableList.<V>of() : new Values(); 78  } 79  80  @WeakOuter 81  private final class Values extends ImmutableList<V> { 82  @Override 83  public int size() { 84  return RegularImmutableTable.this.size(); 85  } 86  87  @Override 88  public V get(int index) { 89  return getValue(index); 90  } 91  92  @Override 93  boolean isPartialView() { 94  return true; 95  } 96  } 97  98  static <R, C, V> RegularImmutableTable<R, C, V> forCells( 99  List<Cell<R, C, V>> cells, 100  final @Nullable Comparator<? super R> rowComparator, 101  final @Nullable Comparator<? super C> columnComparator) { 102  checkNotNull(cells); 103  if (rowComparator != null || columnComparator != null) { 104  /* 105  * This sorting logic leads to a cellSet() ordering that may not be expected and that isn't 106  * documented in the Javadoc. If a row Comparator is provided, cellSet() iterates across the 107  * columns in the first row, the columns in the second row, etc. If a column Comparator is 108  * provided but a row Comparator isn't, cellSet() iterates across the rows in the first 109  * column, the rows in the second column, etc. 110  */ 111  Comparator<Cell<R, C, V>> comparator = 112  new Comparator<Cell<R, C, V>>() { 113  @Override 114  public int compare(Cell<R, C, V> cell1, Cell<R, C, V> cell2) { 115  int rowCompare = 116  (rowComparator == null) 117  ? 0 118  : rowComparator.compare(cell1.getRowKey(), cell2.getRowKey()); 119  if (rowCompare != 0) { 120  return rowCompare; 121  } 122  return (columnComparator == null) 123  ? 0 124  : columnComparator.compare(cell1.getColumnKey(), cell2.getColumnKey()); 125  } 126  }; 127  Collections.sort(cells, comparator); 128  } 129  return forCellsInternal(cells, rowComparator, columnComparator); 130  } 131  132  static <R, C, V> RegularImmutableTable<R, C, V> forCells(Iterable<Cell<R, C, V>> cells) { 133  return forCellsInternal(cells, null, null); 134  } 135  136  private static <R, C, V> RegularImmutableTable<R, C, V> forCellsInternal( 137  Iterable<Cell<R, C, V>> cells, 138  @Nullable Comparator<? super R> rowComparator, 139  @Nullable Comparator<? super C> columnComparator) { 140  Set<R> rowSpaceBuilder = new LinkedHashSet<>(); 141  Set<C> columnSpaceBuilder = new LinkedHashSet<>(); 142  ImmutableList<Cell<R, C, V>> cellList = ImmutableList.copyOf(cells); 143  for (Cell<R, C, V> cell : cells) { 144  rowSpaceBuilder.add(cell.getRowKey()); 145  columnSpaceBuilder.add(cell.getColumnKey()); 146  } 147  148  ImmutableSet<R> rowSpace = 149  (rowComparator == null) 150  ? ImmutableSet.copyOf(rowSpaceBuilder) 151  : ImmutableSet.copyOf(ImmutableList.sortedCopyOf(rowComparator, rowSpaceBuilder)); 152  ImmutableSet<C> columnSpace = 153  (columnComparator == null) 154  ? ImmutableSet.copyOf(columnSpaceBuilder) 155  : ImmutableSet.copyOf(ImmutableList.sortedCopyOf(columnComparator, columnSpaceBuilder)); 156  157  return forOrderedComponents(cellList, rowSpace, columnSpace); 158  } 159  160  /** A factory that chooses the most space-efficient representation of the table. */ 161  static <R, C, V> RegularImmutableTable<R, C, V> forOrderedComponents( 162  ImmutableList<Cell<R, C, V>> cellList, 163  ImmutableSet<R> rowSpace, 164  ImmutableSet<C> columnSpace) { 165  // use a dense table if more than half of the cells have values 166  // TODO(gak): tune this condition based on empirical evidence 167  return (cellList.size() > (((long) rowSpace.size() * columnSpace.size()) / 2)) 168  ? new DenseImmutableTable<R, C, V>(cellList, rowSpace, columnSpace) 169  : new SparseImmutableTable<R, C, V>(cellList, rowSpace, columnSpace); 170  } 171  172  /** @throws IllegalArgumentException if {@code existingValue} is not null. */ 173  /* 174  * We could have declared this method 'static' but the additional compile-time checks achieved by 175  * referencing the type variables seem worthwhile. 176  */ 177  final void checkNoDuplicate(R rowKey, C columnKey, V existingValue, V newValue) { 178  checkArgument( 179  existingValue == null, 180  "Duplicate key: (row=%s, column=%s), values: [%s, %s].", 181  rowKey, 182  columnKey, 183  newValue, 184  existingValue); 185  } 186 }