aboutsummaryrefslogtreecommitdiffstats
path: root/guava/src/com/google/common/collect/ArrayTable.java
diff options
context:
space:
mode:
Diffstat (limited to 'guava/src/com/google/common/collect/ArrayTable.java')
-rw-r--r--guava/src/com/google/common/collect/ArrayTable.java382
1 files changed, 192 insertions, 190 deletions
diff --git a/guava/src/com/google/common/collect/ArrayTable.java b/guava/src/com/google/common/collect/ArrayTable.java
index 554265c..28eb5b8 100644
--- a/guava/src/com/google/common/collect/ArrayTable.java
+++ b/guava/src/com/google/common/collect/ArrayTable.java
@@ -17,23 +17,21 @@
package com.google.common.collect;
import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkElementIndex;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.annotations.Beta;
-import com.google.common.annotations.GwtCompatible;
-import com.google.common.annotations.GwtIncompatible;
import com.google.common.base.Objects;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.util.AbstractCollection;
+import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
-import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Set;
import javax.annotation.Nullable;
@@ -76,15 +74,10 @@ import javax.annotation.Nullable;
* implementations, synchronization is unnecessary between a thread that writes
* to one cell and a thread that reads from another.
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#Table">
- * {@code Table}</a>.
- *
* @author Jared Levy
* @since 10.0
*/
@Beta
-@GwtCompatible(emulated = true)
public final class ArrayTable<R, C, V> implements Table<R, C, V>, Serializable {
/**
@@ -162,23 +155,22 @@ public final class ArrayTable<R, C, V> implements Table<R, C, V>, Serializable {
* columnKeys is empty but rowKeys isn't, the table is empty but
* containsRow() can return true and rowKeySet() isn't empty.
*/
- rowKeyToIndex = index(rowList);
- columnKeyToIndex = index(columnList);
+ ImmutableMap.Builder<R, Integer> rowBuilder = ImmutableMap.builder();
+ for (int i = 0; i < rowList.size(); i++) {
+ rowBuilder.put(rowList.get(i), i);
+ }
+ rowKeyToIndex = rowBuilder.build();
+
+ ImmutableMap.Builder<C, Integer> columnBuilder = ImmutableMap.builder();
+ for (int i = 0; i < columnList.size(); i++) {
+ columnBuilder.put(columnList.get(i), i);
+ }
+ columnKeyToIndex = columnBuilder.build();
@SuppressWarnings("unchecked")
V[][] tmpArray
= (V[][]) new Object[rowList.size()][columnList.size()];
array = tmpArray;
- // Necessary because in GWT the arrays are initialized with "undefined" instead of null.
- eraseAll();
- }
-
- private static <E> ImmutableMap<E, Integer> index(List<E> list) {
- ImmutableMap.Builder<E, Integer> columnBuilder = ImmutableMap.builder();
- for (int i = 0; i < list.size(); i++) {
- columnBuilder.put(list.get(i), i);
- }
- return columnBuilder.build();
}
private ArrayTable(Table<R, C, V> table) {
@@ -194,116 +186,11 @@ public final class ArrayTable<R, C, V> implements Table<R, C, V>, Serializable {
@SuppressWarnings("unchecked")
V[][] copy = (V[][]) new Object[rowList.size()][columnList.size()];
array = copy;
- // Necessary because in GWT the arrays are initialized with "undefined" instead of null.
- eraseAll();
for (int i = 0; i < rowList.size(); i++) {
System.arraycopy(table.array[i], 0, copy[i], 0, table.array[i].length);
}
}
- private abstract static class ArrayMap<K, V> extends Maps.ImprovedAbstractMap<K, V> {
- private final ImmutableMap<K, Integer> keyIndex;
-
- private ArrayMap(ImmutableMap<K, Integer> keyIndex) {
- this.keyIndex = keyIndex;
- }
-
- @Override
- public Set<K> keySet() {
- return keyIndex.keySet();
- }
-
- K getKey(int index) {
- return keyIndex.keySet().asList().get(index);
- }
-
- abstract String getKeyRole();
-
- @Nullable abstract V getValue(int index);
-
- @Nullable abstract V setValue(int index, V newValue);
-
- @Override
- public int size() {
- return keyIndex.size();
- }
-
- @Override
- public boolean isEmpty() {
- return keyIndex.isEmpty();
- }
-
- @Override
- protected Set<Entry<K, V>> createEntrySet() {
- return new Maps.EntrySet<K, V>() {
- @Override
- Map<K, V> map() {
- return ArrayMap.this;
- }
-
- @Override
- public Iterator<Entry<K, V>> iterator() {
- return new AbstractIndexedListIterator<Entry<K, V>>(size()) {
- @Override
- protected Entry<K, V> get(final int index) {
- return new AbstractMapEntry<K, V>() {
- @Override
- public K getKey() {
- return ArrayMap.this.getKey(index);
- }
-
- @Override
- public V getValue() {
- return ArrayMap.this.getValue(index);
- }
-
- @Override
- public V setValue(V value) {
- return ArrayMap.this.setValue(index, value);
- }
- };
- }
- };
- }
- };
- }
-
- @Override
- public boolean containsKey(@Nullable Object key) {
- return keyIndex.containsKey(key);
- }
-
- @Override
- public V get(@Nullable Object key) {
- Integer index = keyIndex.get(key);
- if (index == null) {
- return null;
- } else {
- return getValue(index);
- }
- }
-
- @Override
- public V put(K key, V value) {
- Integer index = keyIndex.get(key);
- if (index == null) {
- throw new IllegalArgumentException(
- getKeyRole() + " " + key + " not in " + keyIndex.keySet());
- }
- return setValue(index, value);
- }
-
- @Override
- public V remove(Object key) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void clear() {
- throw new UnsupportedOperationException();
- }
- }
-
/**
* Returns, as an immutable list, the row keys provided when the table was
* constructed, including those that are mapped to null values only.
@@ -335,9 +222,6 @@ public final class ArrayTable<R, C, V> implements Table<R, C, V>, Serializable {
* allowed column keys
*/
public V at(int rowIndex, int columnIndex) {
- // In GWT array access never throws IndexOutOfBoundsException.
- checkElementIndex(rowIndex, rowList.size());
- checkElementIndex(columnIndex, columnList.size());
return array[rowIndex][columnIndex];
}
@@ -357,9 +241,6 @@ public final class ArrayTable<R, C, V> implements Table<R, C, V>, Serializable {
* allowed column keys
*/
public V set(int rowIndex, int columnIndex, @Nullable V value) {
- // In GWT array access never throws IndexOutOfBoundsException.
- checkElementIndex(rowIndex, rowList.size());
- checkElementIndex(columnIndex, columnList.size());
V oldValue = array[rowIndex][columnIndex];
array[rowIndex][columnIndex] = value;
return oldValue;
@@ -375,7 +256,6 @@ public final class ArrayTable<R, C, V> implements Table<R, C, V>, Serializable {
*
* @param valueClass class of values stored in the returned array
*/
- @GwtIncompatible("reflection")
public V[][] toArray(Class<V> valueClass) {
// Can change to use varargs in JDK 1.6 if we want
@SuppressWarnings("unchecked") // TODO: safe?
@@ -451,8 +331,12 @@ public final class ArrayTable<R, C, V> implements Table<R, C, V>, Serializable {
public V get(@Nullable Object rowKey, @Nullable Object columnKey) {
Integer rowIndex = rowKeyToIndex.get(rowKey);
Integer columnIndex = columnKeyToIndex.get(columnKey);
+ return getIndexed(rowIndex, columnIndex);
+ }
+
+ private V getIndexed(Integer rowIndex, Integer columnIndex) {
return (rowIndex == null || columnIndex == null)
- ? null : at(rowIndex, columnIndex);
+ ? null : array[rowIndex][columnIndex];
}
/**
@@ -602,7 +486,7 @@ public final class ArrayTable<R, C, V> implements Table<R, C, V>, Serializable {
}
@Override
public V getValue() {
- return at(rowIndex, columnIndex);
+ return array[rowIndex][columnIndex];
}
};
}
@@ -620,7 +504,7 @@ public final class ArrayTable<R, C, V> implements Table<R, C, V>, Serializable {
Integer columnIndex = columnKeyToIndex.get(cell.getColumnKey());
return rowIndex != null
&& columnIndex != null
- && Objects.equal(at(rowIndex, columnIndex), cell.getValue());
+ && Objects.equal(array[rowIndex][columnIndex], cell.getValue());
}
return false;
}
@@ -646,27 +530,68 @@ public final class ArrayTable<R, C, V> implements Table<R, C, V>, Serializable {
? ImmutableMap.<R, V>of() : new Column(columnIndex);
}
- private class Column extends ArrayMap<R, V> {
+ private class Column extends AbstractMap<R, V> {
final int columnIndex;
Column(int columnIndex) {
- super(rowKeyToIndex);
this.columnIndex = columnIndex;
}
- @Override
- String getKeyRole() {
- return "Row";
+ ColumnEntrySet entrySet;
+
+ @Override public Set<Entry<R, V>> entrySet() {
+ ColumnEntrySet set = entrySet;
+ return (set == null) ? entrySet = new ColumnEntrySet(columnIndex) : set;
+ }
+
+ @Override public V get(Object rowKey) {
+ Integer rowIndex = rowKeyToIndex.get(rowKey);
+ return getIndexed(rowIndex, columnIndex);
+ }
+
+ @Override public boolean containsKey(Object rowKey) {
+ return rowKeyToIndex.containsKey(rowKey);
+ }
+
+ @Override public V put(R rowKey, V value) {
+ checkNotNull(rowKey);
+ Integer rowIndex = rowKeyToIndex.get(rowKey);
+ checkArgument(rowIndex != null, "Row %s not in %s", rowKey, rowList);
+ return set(rowIndex, columnIndex, value);
+ }
+
+ @Override public Set<R> keySet() {
+ return rowKeySet();
+ }
+ }
+
+ private class ColumnEntrySet extends AbstractSet<Entry<R, V>> {
+ final int columnIndex;
+
+ ColumnEntrySet(int columnIndex) {
+ this.columnIndex = columnIndex;
}
- @Override
- V getValue(int index) {
- return at(index, columnIndex);
+ @Override public Iterator<Entry<R, V>> iterator() {
+ return new AbstractIndexedListIterator<Entry<R, V>>(size()) {
+ @Override protected Entry<R, V> get(final int rowIndex) {
+ return new AbstractMapEntry<R, V>() {
+ @Override public R getKey() {
+ return rowList.get(rowIndex);
+ }
+ @Override public V getValue() {
+ return array[rowIndex][columnIndex];
+ }
+ @Override public V setValue(V value) {
+ return ArrayTable.this.set(rowIndex, columnIndex, value);
+ }
+ };
+ }
+ };
}
- @Override
- V setValue(int index, V newValue) {
- return set(index, columnIndex, newValue);
+ @Override public int size() {
+ return rowList.size();
}
}
@@ -689,32 +614,47 @@ public final class ArrayTable<R, C, V> implements Table<R, C, V>, Serializable {
return (map == null) ? columnMap = new ColumnMap() : map;
}
- private class ColumnMap extends ArrayMap<C, Map<R, V>> {
- private ColumnMap() {
- super(columnKeyToIndex);
+ private class ColumnMap extends AbstractMap<C, Map<R, V>> {
+ transient ColumnMapEntrySet entrySet;
+
+ @Override public Set<Entry<C, Map<R, V>>> entrySet() {
+ ColumnMapEntrySet set = entrySet;
+ return (set == null) ? entrySet = new ColumnMapEntrySet() : set;
}
- @Override
- String getKeyRole() {
- return "Column";
+ @Override public Map<R, V> get(Object columnKey) {
+ Integer columnIndex = columnKeyToIndex.get(columnKey);
+ return (columnIndex == null) ? null : new Column(columnIndex);
}
- @Override
- Map<R, V> getValue(int index) {
- return new Column(index);
+ @Override public boolean containsKey(Object columnKey) {
+ return containsColumn(columnKey);
}
- @Override
- Map<R, V> setValue(int index, Map<R, V> newValue) {
- throw new UnsupportedOperationException();
+ @Override public Set<C> keySet() {
+ return columnKeySet();
}
- @Override
- public Map<R, V> put(C key, Map<R, V> value) {
+ @Override public Map<R, V> remove(Object columnKey) {
throw new UnsupportedOperationException();
}
}
+ private class ColumnMapEntrySet extends AbstractSet<Entry<C, Map<R, V>>> {
+ @Override public Iterator<Entry<C, Map<R, V>>> iterator() {
+ return new AbstractIndexedListIterator<Entry<C, Map<R, V>>>(size()) {
+ @Override protected Entry<C, Map<R, V>> get(int index) {
+ return Maps.<C, Map<R, V>>immutableEntry(columnList.get(index),
+ new Column(index));
+ }
+ };
+ }
+
+ @Override public int size() {
+ return columnList.size();
+ }
+ }
+
/**
* Returns a view of all mappings that have the given row key. If the
* row key isn't in {@link #rowKeySet()}, an empty immutable map is
@@ -735,27 +675,69 @@ public final class ArrayTable<R, C, V> implements Table<R, C, V>, Serializable {
return (rowIndex == null) ? ImmutableMap.<C, V>of() : new Row(rowIndex);
}
- private class Row extends ArrayMap<C, V> {
+ private class Row extends AbstractMap<C, V> {
final int rowIndex;
Row(int rowIndex) {
- super(columnKeyToIndex);
this.rowIndex = rowIndex;
}
- @Override
- String getKeyRole() {
- return "Column";
+ RowEntrySet entrySet;
+
+ @Override public Set<Entry<C, V>> entrySet() {
+ RowEntrySet set = entrySet;
+ return (set == null) ? entrySet = new RowEntrySet(rowIndex) : set;
+ }
+
+ @Override public V get(Object columnKey) {
+ Integer columnIndex = columnKeyToIndex.get(columnKey);
+ return getIndexed(rowIndex, columnIndex);
+ }
+
+ @Override public boolean containsKey(Object columnKey) {
+ return containsColumn(columnKey);
+ }
+
+ @Override public V put(C columnKey, V value) {
+ checkNotNull(columnKey);
+ Integer columnIndex = columnKeyToIndex.get(columnKey);
+ checkArgument(columnIndex != null,
+ "Column %s not in %s", columnKey, columnList);
+ return set(rowIndex, columnIndex, value);
}
- @Override
- V getValue(int index) {
- return at(rowIndex, index);
+ @Override public Set<C> keySet() {
+ return columnKeySet();
}
+ }
+
+ private class RowEntrySet extends AbstractSet<Entry<C, V>> {
+ final int rowIndex;
- @Override
- V setValue(int index, V newValue) {
- return set(rowIndex, index, newValue);
+ RowEntrySet(int rowIndex) {
+ this.rowIndex = rowIndex;
+ }
+
+ @Override public Iterator<Entry<C, V>> iterator() {
+ return new AbstractIndexedListIterator<Entry<C, V>>(size()) {
+ @Override protected Entry<C, V> get(final int columnIndex) {
+ return new AbstractMapEntry<C, V>() {
+ @Override public C getKey() {
+ return columnList.get(columnIndex);
+ }
+ @Override public V getValue() {
+ return array[rowIndex][columnIndex];
+ }
+ @Override public V setValue(V value) {
+ return ArrayTable.this.set(rowIndex, columnIndex, value);
+ }
+ };
+ }
+ };
+ }
+
+ @Override public int size() {
+ return columnList.size();
}
}
@@ -778,32 +760,47 @@ public final class ArrayTable<R, C, V> implements Table<R, C, V>, Serializable {
return (map == null) ? rowMap = new RowMap() : map;
}
- private class RowMap extends ArrayMap<R, Map<C, V>> {
- private RowMap() {
- super(rowKeyToIndex);
+ private class RowMap extends AbstractMap<R, Map<C, V>> {
+ transient RowMapEntrySet entrySet;
+
+ @Override public Set<Entry<R, Map<C, V>>> entrySet() {
+ RowMapEntrySet set = entrySet;
+ return (set == null) ? entrySet = new RowMapEntrySet() : set;
}
- @Override
- String getKeyRole() {
- return "Row";
+ @Override public Map<C, V> get(Object rowKey) {
+ Integer rowIndex = rowKeyToIndex.get(rowKey);
+ return (rowIndex == null) ? null : new Row(rowIndex);
}
- @Override
- Map<C, V> getValue(int index) {
- return new Row(index);
+ @Override public boolean containsKey(Object rowKey) {
+ return containsRow(rowKey);
}
- @Override
- Map<C, V> setValue(int index, Map<C, V> newValue) {
- throw new UnsupportedOperationException();
+ @Override public Set<R> keySet() {
+ return rowKeySet();
}
- @Override
- public Map<C, V> put(R key, Map<C, V> value) {
+ @Override public Map<C, V> remove(Object rowKey) {
throw new UnsupportedOperationException();
}
}
+ private class RowMapEntrySet extends AbstractSet<Entry<R, Map<C, V>>> {
+ @Override public Iterator<Entry<R, Map<C, V>>> iterator() {
+ return new AbstractIndexedListIterator<Entry<R, Map<C, V>>>(size()) {
+ @Override protected Entry<R, Map<C, V>> get(int index) {
+ return Maps.<R, Map<C, V>>immutableEntry(rowList.get(index),
+ new Row(index));
+ }
+ };
+ }
+
+ @Override public int size() {
+ return rowList.size();
+ }
+ }
+
private transient Collection<V> values;
/**
@@ -823,10 +820,11 @@ public final class ArrayTable<R, C, V> implements Table<R, C, V>, Serializable {
private class Values extends AbstractCollection<V> {
@Override public Iterator<V> iterator() {
- return new TransformedIterator<Cell<R, C, V>, V>(cellSet().iterator()) {
- @Override
- V transform(Cell<R, C, V> cell) {
- return cell.getValue();
+ return new AbstractIndexedListIterator<V>(size()) {
+ @Override protected V get(int index) {
+ int rowIndex = index / columnList.size();
+ int columnIndex = index % columnList.size();
+ return array[rowIndex][columnIndex];
}
};
}
@@ -834,6 +832,10 @@ public final class ArrayTable<R, C, V> implements Table<R, C, V>, Serializable {
@Override public int size() {
return ArrayTable.this.size();
}
+
+ @Override public boolean contains(Object value) {
+ return containsValue(value);
+ }
}
private static final long serialVersionUID = 0;