AbstractGrid.java
/*
* Copyright 2014-present Stephen Colebourne
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.joda.collect.grid;
import java.util.AbstractList;
import java.util.List;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
/**
* Abstract implementation of the {@code Grid} data structure.
*
* @param <V> the type of the value
* @author Stephen Colebourne
*/
abstract class AbstractGrid<V> implements Grid<V> {
/**
* Validates the row and column counts.
*
* @param rowCount the row count
* @param columnCount the column count
*/
static void validateCounts(int rowCount, int columnCount) {
if (rowCount < 0) {
throw new IllegalArgumentException("Row count must not be negative: " + rowCount + " < 0");
}
if (columnCount < 0) {
throw new IllegalArgumentException("Column count must not be negative: " + columnCount + " < 0");
}
}
//-----------------------------------------------------------------------
/**
* Restricted constructor.
*/
AbstractGrid() {
}
//-----------------------------------------------------------------------
@Override
public boolean exists(int row, int column) {
return row >= 0 && row < rowCount() && column >= 0 && column < columnCount();
}
//-----------------------------------------------------------------------
@Override
public boolean isFull() {
return size() == rowCount() * columnCount();
}
@Override
public boolean isEmpty() {
return size() == 0;
}
@Override
public int size() {
return cells().size();
}
@Override
public boolean contains(int row, int column) {
return cell(row, column) != null;
}
@Override
public boolean containsValue(Object valueToFind) {
return (valueToFind != null ? values().contains(valueToFind) : false);
}
@Override
public V get(int row, int column) {
Cell<V> cell = cell(row, column);
return (cell != null ? cell.getValue() : null);
}
@Override
public Cell<V> cell(int row, int column) {
if (exists(row, column)) {
for (Cell<V> cell : cells()) {
if (cell.getRow() == row && cell.getColumn() == column) {
return cell;
}
}
}
return null;
}
//-----------------------------------------------------------------------
@Override
public ImmutableCollection<V> values() {
Builder<V> builder = ImmutableList.builder();
for (Cell<V> cell : cells()) {
builder.add(cell.getValue());
}
return builder.build();
}
//-----------------------------------------------------------------------
@Override
public List<V> row(int row) {
Preconditions.checkElementIndex(row, rowCount(), "Row index");
return new Inner<V>(this, columnCount(), row, true);
}
@Override
public List<List<V>> rows() {
return new Outer<V>(this, rowCount(), columnCount(), true);
}
@Override
public List<V> column(int column) {
Preconditions.checkElementIndex(column, columnCount(), "Column index");
return new Inner<V>(this, rowCount(), column, false);
}
@Override
public List<List<V>> columns() {
return new Outer<V>(this, columnCount(), rowCount(), false);
}
static class Outer<V> extends AbstractList<List<V>> {
private final Grid<V> grid;
private final int size;
private final int innerSize;
private final boolean rows;
Outer(Grid<V> grid, int size, int innerSize, boolean rows) {
this.grid = grid;
this.size = size;
this.innerSize = innerSize;
this.rows = rows;
}
@Override
public int size() {
return size;
}
@Override
public List<V> get(int index) {
Preconditions.checkElementIndex(index, size);
return new Inner<V>(grid, innerSize, index, rows);
}
}
static class Inner<V> extends AbstractList<V> {
private final Grid<V> grid;
private final int size;
private final int outerIndex;
private final boolean rows;
Inner(Grid<V> grid, int size, int outerIndex, boolean rows) {
this.grid = grid;
this.size = size;
this.outerIndex = outerIndex;
this.rows = rows;
}
@Override
public int size() {
return size;
}
@Override
public V get(int index) {
Preconditions.checkElementIndex(index, size);
if (rows) {
return grid.get(outerIndex, index);
} else {
return grid.get(index, outerIndex);
}
}
@Override
public V set(int index, V newValue) {
V old = get(index);
if (rows) {
if (newValue == null) {
grid.remove(outerIndex, index);
} else {
grid.put(outerIndex, index, newValue);
}
} else {
if (newValue == null) {
grid.remove(index, outerIndex);
} else {
grid.put(index, outerIndex, newValue);
}
}
return old;
}
}
//-----------------------------------------------------------------------
Cell<V> finder(int row, int column) {
@SuppressWarnings({ "unchecked", "rawtypes" })
Cell<V> finder = new ImmutableCell(row, column, "");
return finder;
}
//-----------------------------------------------------------------------
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj instanceof Grid) {
Grid<?> other = (Grid<?>) obj;
return rowCount() == other.rowCount() &&
columnCount() == other.columnCount() &&
cells().equals(other.cells());
}
return false;
}
@Override
public int hashCode() {
return rowCount() ^ Integer.rotateLeft(columnCount(), 16) ^ cells().hashCode();
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder(size() * 16);
buf.append('[').append(rowCount()).append('x').append(columnCount()).append(':');
if (size() > 0) {
for (Cell<V> cell : cells()) {
buf.append(cell).append(',').append(' ');
}
buf.setLength(buf.length() - 2);
}
buf.append(']');
return buf.toString();
}
}