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

Class Method, % Line, %
DenseImmutableTable 33.3% (3/9) 70.5% (31/44)
DenseImmutableTable$Column 0% (0/4) 0% (0/7)
DenseImmutableTable$ColumnMap 40% (2/5) 57.1% (4/7)
DenseImmutableTable$ImmutableArrayMap 14.3% (1/7) 30% (3/10)
DenseImmutableTable$ImmutableArrayMap$1 0% (0/2) 0% (0/8)
DenseImmutableTable$Row 0% (0/4) 0% (0/7)
DenseImmutableTable$RowMap 40% (2/5) 57.1% (4/7)
Total 22.2% (8/36) 46.7% (42/90)


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 com.google.common.annotations.GwtCompatible; 18 import com.google.common.collect.ImmutableMap.IteratorBasedImmutableMap; 19 import com.google.errorprone.annotations.Immutable; 20 import com.google.j2objc.annotations.WeakOuter; 21 import java.util.Map; 22 import org.checkerframework.checker.nullness.qual.Nullable; 23  24 /** A {@code RegularImmutableTable} optimized for dense data. */ 25 @GwtCompatible 26 @Immutable(containerOf = {"R", "C", "V"}) 27 final class DenseImmutableTable<R, C, V> extends RegularImmutableTable<R, C, V> { 28  private final ImmutableMap<R, Integer> rowKeyToIndex; 29  private final ImmutableMap<C, Integer> columnKeyToIndex; 30  private final ImmutableMap<R, ImmutableMap<C, V>> rowMap; 31  private final ImmutableMap<C, ImmutableMap<R, V>> columnMap; 32  33  @SuppressWarnings("Immutable") // We don't modify this after construction. 34  private final int[] rowCounts; 35  36  @SuppressWarnings("Immutable") // We don't modify this after construction. 37  private final int[] columnCounts; 38  39  @SuppressWarnings("Immutable") // We don't modify this after construction. 40  private final V[][] values; 41  42  // For each cell in iteration order, the index of that cell's row key in the row key list. 43  @SuppressWarnings("Immutable") // We don't modify this after construction. 44  private final int[] cellRowIndices; 45  46  // For each cell in iteration order, the index of that cell's column key in the column key list. 47  @SuppressWarnings("Immutable") // We don't modify this after construction. 48  private final int[] cellColumnIndices; 49  50  DenseImmutableTable( 51  ImmutableList<Cell<R, C, V>> cellList, 52  ImmutableSet<R> rowSpace, 53  ImmutableSet<C> columnSpace) { 54  @SuppressWarnings("unchecked") 55  V[][] array = (V[][]) new Object[rowSpace.size()][columnSpace.size()]; 56  this.values = array; 57  this.rowKeyToIndex = Maps.indexMap(rowSpace); 58  this.columnKeyToIndex = Maps.indexMap(columnSpace); 59  rowCounts = new int[rowKeyToIndex.size()]; 60  columnCounts = new int[columnKeyToIndex.size()]; 61  int[] cellRowIndices = new int[cellList.size()]; 62  int[] cellColumnIndices = new int[cellList.size()]; 63  for (int i = 0; i < cellList.size(); i++) { 64  Cell<R, C, V> cell = cellList.get(i); 65  R rowKey = cell.getRowKey(); 66  C columnKey = cell.getColumnKey(); 67  int rowIndex = rowKeyToIndex.get(rowKey); 68  int columnIndex = columnKeyToIndex.get(columnKey); 69  V existingValue = values[rowIndex][columnIndex]; 70  checkNoDuplicate(rowKey, columnKey, existingValue, cell.getValue()); 71  values[rowIndex][columnIndex] = cell.getValue(); 72  rowCounts[rowIndex]++; 73  columnCounts[columnIndex]++; 74  cellRowIndices[i] = rowIndex; 75  cellColumnIndices[i] = columnIndex; 76  } 77  this.cellRowIndices = cellRowIndices; 78  this.cellColumnIndices = cellColumnIndices; 79  this.rowMap = new RowMap(); 80  this.columnMap = new ColumnMap(); 81  } 82  83  /** An immutable map implementation backed by an indexed nullable array. */ 84  private abstract static class ImmutableArrayMap<K, V> extends IteratorBasedImmutableMap<K, V> { 85  private final int size; 86  87  ImmutableArrayMap(int size) { 88  this.size = size; 89  } 90  91  abstract ImmutableMap<K, Integer> keyToIndex(); 92  93  // True if getValue never returns null. 94  private boolean isFull() { 95  return size == keyToIndex().size(); 96  } 97  98  K getKey(int index) { 99  return keyToIndex().keySet().asList().get(index); 100  } 101  102  abstract @Nullable V getValue(int keyIndex); 103  104  @Override 105  ImmutableSet<K> createKeySet() { 106  return isFull() ? keyToIndex().keySet() : super.createKeySet(); 107  } 108  109  @Override 110  public int size() { 111  return size; 112  } 113  114  @Override 115  public V get(@Nullable Object key) { 116  Integer keyIndex = keyToIndex().get(key); 117  return (keyIndex == null) ? null : getValue(keyIndex); 118  } 119  120  @Override 121  UnmodifiableIterator<Entry<K, V>> entryIterator() { 122  return new AbstractIterator<Entry<K, V>>() { 123  private int index = -1; 124  private final int maxIndex = keyToIndex().size(); 125  126  @Override 127  protected Entry<K, V> computeNext() { 128  for (index++; index < maxIndex; index++) { 129  V value = getValue(index); 130  if (value != null) { 131  return Maps.immutableEntry(getKey(index), value); 132  } 133  } 134  return endOfData(); 135  } 136  }; 137  } 138  } 139  140  private final class Row extends ImmutableArrayMap<C, V> { 141  private final int rowIndex; 142  143  Row(int rowIndex) { 144  super(rowCounts[rowIndex]); 145  this.rowIndex = rowIndex; 146  } 147  148  @Override 149  ImmutableMap<C, Integer> keyToIndex() { 150  return columnKeyToIndex; 151  } 152  153  @Override 154  V getValue(int keyIndex) { 155  return values[rowIndex][keyIndex]; 156  } 157  158  @Override 159  boolean isPartialView() { 160  return true; 161  } 162  } 163  164  private final class Column extends ImmutableArrayMap<R, V> { 165  private final int columnIndex; 166  167  Column(int columnIndex) { 168  super(columnCounts[columnIndex]); 169  this.columnIndex = columnIndex; 170  } 171  172  @Override 173  ImmutableMap<R, Integer> keyToIndex() { 174  return rowKeyToIndex; 175  } 176  177  @Override 178  V getValue(int keyIndex) { 179  return values[keyIndex][columnIndex]; 180  } 181  182  @Override 183  boolean isPartialView() { 184  return true; 185  } 186  } 187  188  @WeakOuter 189  private final class RowMap extends ImmutableArrayMap<R, ImmutableMap<C, V>> { 190  private RowMap() { 191  super(rowCounts.length); 192  } 193  194  @Override 195  ImmutableMap<R, Integer> keyToIndex() { 196  return rowKeyToIndex; 197  } 198  199  @Override 200  ImmutableMap<C, V> getValue(int keyIndex) { 201  return new Row(keyIndex); 202  } 203  204  @Override 205  boolean isPartialView() { 206  return false; 207  } 208  } 209  210  @WeakOuter 211  private final class ColumnMap extends ImmutableArrayMap<C, ImmutableMap<R, V>> { 212  private ColumnMap() { 213  super(columnCounts.length); 214  } 215  216  @Override 217  ImmutableMap<C, Integer> keyToIndex() { 218  return columnKeyToIndex; 219  } 220  221  @Override 222  ImmutableMap<R, V> getValue(int keyIndex) { 223  return new Column(keyIndex); 224  } 225  226  @Override 227  boolean isPartialView() { 228  return false; 229  } 230  } 231  232  @Override 233  public ImmutableMap<C, Map<R, V>> columnMap() { 234  // Casts without copying. 235  ImmutableMap<C, ImmutableMap<R, V>> columnMap = this.columnMap; 236  return ImmutableMap.<C, Map<R, V>>copyOf(columnMap); 237  } 238  239  @Override 240  public ImmutableMap<R, Map<C, V>> rowMap() { 241  // Casts without copying. 242  ImmutableMap<R, ImmutableMap<C, V>> rowMap = this.rowMap; 243  return ImmutableMap.<R, Map<C, V>>copyOf(rowMap); 244  } 245  246  @Override 247  public V get(@Nullable Object rowKey, @Nullable Object columnKey) { 248  Integer rowIndex = rowKeyToIndex.get(rowKey); 249  Integer columnIndex = columnKeyToIndex.get(columnKey); 250  return ((rowIndex == null) || (columnIndex == null)) ? null : values[rowIndex][columnIndex]; 251  } 252  253  @Override 254  public int size() { 255  return cellRowIndices.length; 256  } 257  258  @Override 259  Cell<R, C, V> getCell(int index) { 260  int rowIndex = cellRowIndices[index]; 261  int columnIndex = cellColumnIndices[index]; 262  R rowKey = rowKeySet().asList().get(rowIndex); 263  C columnKey = columnKeySet().asList().get(columnIndex); 264  V value = values[rowIndex][columnIndex]; 265  return cellOf(rowKey, columnKey, value); 266  } 267  268  @Override 269  V getValue(int index) { 270  return values[cellRowIndices[index]][cellColumnIndices[index]]; 271  } 272  273  @Override 274  SerializedForm createSerializedForm() { 275  return SerializedForm.create(this, cellRowIndices, cellColumnIndices); 276  } 277 }