1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package com.google.common.collect;
16
17 import com.google.common.annotations.GwtCompatible;
18
19 import java.util.LinkedHashMap;
20 import java.util.Map;
21
22 import javax.annotation.concurrent.Immutable;
23
24
25
26
27 @GwtCompatible
28 @Immutable
29 final class SparseImmutableTable<R, C, V>
30 extends RegularImmutableTable<R, C, V> {
31
32 private final ImmutableMap<R, Map<C, V>> rowMap;
33 private final ImmutableMap<C, Map<R, V>> columnMap;
34 private final int[] iterationOrderRow;
35 private final int[] iterationOrderColumn;
36
37 SparseImmutableTable(ImmutableList<Cell<R, C, V>> cellList,
38 ImmutableSet<R> rowSpace, ImmutableSet<C> columnSpace) {
39 Map<R, Integer> rowIndex = Maps.newHashMap();
40 Map<R, Map<C, V>> rows = Maps.newLinkedHashMap();
41 for (R row : rowSpace) {
42 rowIndex.put(row, rows.size());
43 rows.put(row, new LinkedHashMap<C, V>());
44 }
45 Map<C, Map<R, V>> columns = Maps.newLinkedHashMap();
46 for (C col : columnSpace) {
47 columns.put(col, new LinkedHashMap<R, V>());
48 }
49 int[] iterationOrderRow = new int[cellList.size()];
50 int[] iterationOrderColumn = new int[cellList.size()];
51 for (int i = 0; i < cellList.size(); i++) {
52 Cell<R, C, V> cell = cellList.get(i);
53 R rowKey = cell.getRowKey();
54 C columnKey = cell.getColumnKey();
55 V value = cell.getValue();
56
57 iterationOrderRow[i] = rowIndex.get(rowKey);
58 Map<C, V> thisRow = rows.get(rowKey);
59 iterationOrderColumn[i] = thisRow.size();
60 V oldValue = thisRow.put(columnKey, value);
61 if (oldValue != null) {
62 throw new IllegalArgumentException("Duplicate value for row=" + rowKey + ", column="
63 + columnKey + ": " + value + ", " + oldValue);
64 }
65 columns.get(columnKey).put(rowKey, value);
66 }
67 this.iterationOrderRow = iterationOrderRow;
68 this.iterationOrderColumn = iterationOrderColumn;
69 ImmutableMap.Builder<R, Map<C, V>> rowBuilder = ImmutableMap.builder();
70 for (Map.Entry<R, Map<C, V>> row : rows.entrySet()) {
71 rowBuilder.put(row.getKey(), ImmutableMap.copyOf(row.getValue()));
72 }
73 this.rowMap = rowBuilder.build();
74
75 ImmutableMap.Builder<C, Map<R, V>> columnBuilder = ImmutableMap.builder();
76 for (Map.Entry<C, Map<R, V>> col : columns.entrySet()) {
77 columnBuilder.put(col.getKey(), ImmutableMap.copyOf(col.getValue()));
78 }
79 this.columnMap = columnBuilder.build();
80 }
81
82 @Override public ImmutableMap<C, Map<R, V>> columnMap() {
83 return columnMap;
84 }
85
86 @Override public ImmutableMap<R, Map<C, V>> rowMap() {
87 return rowMap;
88 }
89
90 @Override
91 public int size() {
92 return iterationOrderRow.length;
93 }
94
95 @Override
96 Cell<R, C, V> getCell(int index) {
97 int rowIndex = iterationOrderRow[index];
98 Map.Entry<R, Map<C, V>> rowEntry = rowMap.entrySet().asList().get(rowIndex);
99 ImmutableMap<C, V> row = (ImmutableMap<C, V>) rowEntry.getValue();
100 int columnIndex = iterationOrderColumn[index];
101 Map.Entry<C, V> colEntry = row.entrySet().asList().get(columnIndex);
102 return cellOf(rowEntry.getKey(), colEntry.getKey(), colEntry.getValue());
103 }
104
105 @Override
106 V getValue(int index) {
107 int rowIndex = iterationOrderRow[index];
108 ImmutableMap<C, V> row = (ImmutableMap<C, V>) rowMap.values().asList().get(rowIndex);
109 int columnIndex = iterationOrderColumn[index];
110 return row.values().asList().get(columnIndex);
111 }
112 }