1/* 2 * Copyright (C) 2013 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 15package com.google.common.collect; 16 17import com.google.common.annotations.GwtCompatible; 18 19import java.util.AbstractCollection; 20import java.util.AbstractSet; 21import java.util.Collection; 22import java.util.Iterator; 23import java.util.Map; 24import java.util.Set; 25 26import javax.annotation.Nullable; 27 28/** 29 * Skeletal, implementation-agnostic implementation of the {@link Table} interface. 30 * 31 * @author Louis Wasserman 32 */ 33@GwtCompatible 34abstract class AbstractTable<R, C, V> implements Table<R, C, V> { 35 36 @Override 37 public boolean containsRow(@Nullable Object rowKey) { 38 return Maps.safeContainsKey(rowMap(), rowKey); 39 } 40 41 @Override 42 public boolean containsColumn(@Nullable Object columnKey) { 43 return Maps.safeContainsKey(columnMap(), columnKey); 44 } 45 46 @Override 47 public Set<R> rowKeySet() { 48 return rowMap().keySet(); 49 } 50 51 @Override 52 public Set<C> columnKeySet() { 53 return columnMap().keySet(); 54 } 55 56 @Override 57 public boolean containsValue(@Nullable Object value) { 58 for (Map<C, V> row : rowMap().values()) { 59 if (row.containsValue(value)) { 60 return true; 61 } 62 } 63 return false; 64 } 65 66 @Override 67 public boolean contains(@Nullable Object rowKey, @Nullable Object columnKey) { 68 Map<C, V> row = Maps.safeGet(rowMap(), rowKey); 69 return row != null && Maps.safeContainsKey(row, columnKey); 70 } 71 72 @Override 73 public V get(@Nullable Object rowKey, @Nullable Object columnKey) { 74 Map<C, V> row = Maps.safeGet(rowMap(), rowKey); 75 return (row == null) ? null : Maps.safeGet(row, columnKey); 76 } 77 78 @Override 79 public boolean isEmpty() { 80 return size() == 0; 81 } 82 83 @Override 84 public void clear() { 85 Iterators.clear(cellSet().iterator()); 86 } 87 88 @Override 89 public V remove(@Nullable Object rowKey, @Nullable Object columnKey) { 90 Map<C, V> row = Maps.safeGet(rowMap(), rowKey); 91 return (row == null) ? null : Maps.safeRemove(row, columnKey); 92 } 93 94 @Override 95 public V put(R rowKey, C columnKey, V value) { 96 return row(rowKey).put(columnKey, value); 97 } 98 99 @Override 100 public void putAll(Table<? extends R, ? extends C, ? extends V> table) { 101 for (Table.Cell<? extends R, ? extends C, ? extends V> cell : table.cellSet()) { 102 put(cell.getRowKey(), cell.getColumnKey(), cell.getValue()); 103 } 104 } 105 106 private transient Set<Cell<R, C, V>> cellSet; 107 108 @Override 109 public Set<Cell<R, C, V>> cellSet() { 110 Set<Cell<R, C, V>> result = cellSet; 111 return (result == null) ? cellSet = createCellSet() : result; 112 } 113 114 Set<Cell<R, C, V>> createCellSet() { 115 return new CellSet(); 116 } 117 118 abstract Iterator<Table.Cell<R, C, V>> cellIterator(); 119 120 class CellSet extends AbstractSet<Cell<R, C, V>> { 121 @Override 122 public boolean contains(Object o) { 123 if (o instanceof Cell) { 124 Cell<?, ?, ?> cell = (Cell<?, ?, ?>) o; 125 Map<C, V> row = Maps.safeGet(rowMap(), cell.getRowKey()); 126 return row != null && Collections2.safeContains( 127 row.entrySet(), Maps.immutableEntry(cell.getColumnKey(), cell.getValue())); 128 } 129 return false; 130 } 131 132 @Override 133 public boolean remove(@Nullable Object o) { 134 if (o instanceof Cell) { 135 Cell<?, ?, ?> cell = (Cell<?, ?, ?>) o; 136 Map<C, V> row = Maps.safeGet(rowMap(), cell.getRowKey()); 137 return row != null && Collections2.safeRemove( 138 row.entrySet(), Maps.immutableEntry(cell.getColumnKey(), cell.getValue())); 139 } 140 return false; 141 } 142 143 @Override 144 public void clear() { 145 AbstractTable.this.clear(); 146 } 147 148 @Override 149 public Iterator<Table.Cell<R, C, V>> iterator() { 150 return cellIterator(); 151 } 152 153 @Override 154 public int size() { 155 return AbstractTable.this.size(); 156 } 157 } 158 159 private transient Collection<V> values; 160 161 @Override 162 public Collection<V> values() { 163 Collection<V> result = values; 164 return (result == null) ? values = createValues() : result; 165 } 166 167 Collection<V> createValues() { 168 return new Values(); 169 } 170 171 Iterator<V> valuesIterator() { 172 return new TransformedIterator<Cell<R, C, V>, V>(cellSet().iterator()) { 173 @Override 174 V transform(Cell<R, C, V> cell) { 175 return cell.getValue(); 176 } 177 }; 178 } 179 180 class Values extends AbstractCollection<V> { 181 @Override 182 public Iterator<V> iterator() { 183 return valuesIterator(); 184 } 185 186 @Override 187 public boolean contains(Object o) { 188 return containsValue(o); 189 } 190 191 @Override 192 public void clear() { 193 AbstractTable.this.clear(); 194 } 195 196 @Override 197 public int size() { 198 return AbstractTable.this.size(); 199 } 200 } 201 202 @Override public boolean equals(@Nullable Object obj) { 203 return Tables.equalsImpl(this, obj); 204 } 205 206 @Override public int hashCode() { 207 return cellSet().hashCode(); 208 } 209 210 /** 211 * Returns the string representation {@code rowMap().toString()}. 212 */ 213 @Override public String toString() { 214 return rowMap().toString(); 215 } 216} 217