All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.joda.collect.grid.DenseImmutableGrid Maven / Gradle / Ivy

The newest version!
/*
 *  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.io.Serializable;
import java.util.AbstractList;
import java.util.AbstractSet;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Set;

import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;

/**
 * Immutable implementation of the {@code Grid} data structure based on an array.
 * 

* This uses one item of memory for each possible combination of row and column. * * @param the type of the value * @author Stephen Colebourne */ final class DenseImmutableGrid extends ImmutableGrid implements Serializable { /** Serialization version. */ private static final long serialVersionUID = 1L; /** * The number of rows. */ private final int rowCount; /** * The number of columns. */ private final int columnCount; /** * The size. */ private final int size; /** * The values. */ private final V[] values; //----------------------------------------------------------------------- /** * Creates a {@code DenseImmutableGrid} copying from another grid. * * @param the type of the value * @param grid the grid to copy, not null * @return the mutable grid, not null */ @SuppressWarnings("unchecked") static DenseImmutableGrid create(Grid grid) { if (grid instanceof DenseGrid) { return new DenseImmutableGrid((DenseGrid) grid); } int rowCount = grid.rowCount(); int columnCount = grid.columnCount(); validateCounts(rowCount, columnCount); V[] values = (V[]) new Object[rowCount * columnCount]; for (Cell cell : grid.cells()) { values[cell.getRow() * columnCount + cell.getColumn()] = cell.getValue(); } return new DenseImmutableGrid(rowCount, columnCount, grid.size(), values); } //----------------------------------------------------------------------- /** * Restricted constructor. */ private DenseImmutableGrid(int rowCount, int columnCount, int size, V[] values) { validateCounts(rowCount, columnCount); this.rowCount = rowCount; this.columnCount = columnCount; this.size = size; this.values = values; } /** * Restricted constructor. */ DenseImmutableGrid(DenseGrid grid) { this.rowCount = grid.rowCount(); this.columnCount = grid.columnCount(); this.size = grid.size(); this.values = grid.valuesArray(); } //----------------------------------------------------------------------- @Override public int rowCount() { return rowCount; } @Override public int columnCount() { return columnCount; } @Override public int size() { return size; } @Override public boolean contains(int row, int column) { if (exists(row, column)) { return values[row * columnCount + column] != null; } return false; } @Override public boolean containsValue(Object valueToFind) { if (valueToFind != null) { for (Object value : values) { if (valueToFind.equals(value)) { return true; } } } return false; } @Override public V get(int row, int column) { if (exists(row, column)) { return values[row * columnCount + column]; } return null; } @Override public Cell cell(int row, int column) { V value = get(row, column); return (value != null ? ImmutableCell.of(row, column, value) : null); } //----------------------------------------------------------------------- @Override public Set> cells() { return new Cells(this); } /** * View onto the grid. */ static class Cells extends AbstractSet> { private final DenseImmutableGrid grid; Cells(DenseImmutableGrid grid) { this.grid = grid; } @Override public int size() { return grid.size; } @Override public boolean contains(Object obj) { Cell cell = (Cell) obj; return Objects.equal(cell.getValue(), grid.get(cell.getRow(), cell.getColumn())); } @Override public Iterator> iterator() { return new Iterator>() { private MutableCell cell = new MutableCell(); private int count; private int current = -1; @Override public boolean hasNext() { return (count < grid.size); } @Override public Cell next() { if (!hasNext()) { throw new NoSuchElementException("No more elements"); } current++; for ( ; current < grid.values.length; current++) { if (grid.values[current] != null) { break; } } V value = grid.values[current]; count++; cell.set(current / grid.columnCount, current % grid.columnCount, value); return cell; } @Override public void remove() { throw new UnsupportedOperationException("Immutable"); } }; } } //----------------------------------------------------------------------- @Override @SuppressWarnings("unchecked") public ImmutableCollection values() { Object[] array = new Object[size]; int index = 0; for (Object object : values) { if (object != null) { array[index++] = object; } } return ImmutableList.copyOf((V[]) array); } //----------------------------------------------------------------------- @Override public List row(int row) { Preconditions.checkElementIndex(row, rowCount(), "Row index"); int base = row * rowCount; return new Inner(this, base, columnCount, 1); } @Override public List> rows() { return new Outer(this, rowCount, columnCount, columnCount, 1); } @Override public List column(int column) { Preconditions.checkElementIndex(column, columnCount(), "Column index"); return new Inner(this, column, rowCount, columnCount); } @Override public List> columns() { return new Outer(this, columnCount, 1, rowCount, columnCount); } static class Outer extends AbstractList> { private final DenseImmutableGrid grid; private final int size; private final int gap; private final int innerSize; private final int innerGap; Outer(DenseImmutableGrid grid, int size, int gap, int innerSize, int innerGap) { this.grid = grid; this.size = size; this.gap = gap; this.innerSize = innerSize; this.innerGap = innerGap; } @Override public int size() { return size; } @Override public List get(int index) { Preconditions.checkElementIndex(index, size); int base = index * gap; return new Inner(grid, base, innerSize, innerGap); } } static class Inner extends AbstractList { private final DenseImmutableGrid grid; private final int size; private final int offset; private final int gap; Inner(DenseImmutableGrid grid, int offset, int size, int gap) { this.grid = grid; this.size = size; this.offset = offset; this.gap = gap; } @Override public int size() { return size; } @Override public V get(int index) { Preconditions.checkElementIndex(index, size); int arrayIndex = index * gap + offset; return grid.values[arrayIndex]; } } //----------------------------------------------------------------------- /** * Returns a clone of the internal array. * * @return the array, not null */ V[] valuesArray() { return values.clone(); } //----------------------------------------------------------------------- @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (obj instanceof DenseImmutableGrid) { DenseImmutableGrid other = (DenseImmutableGrid) obj; return Arrays.equals(values, other.values); } return super.equals(obj); } @Override public int hashCode() { int hash = 0; for (int i = 0; i < values.length; i++) { Object value = values[i]; if (value != null) { int row = i / columnCount; int column = i % columnCount; hash += (row ^ Integer.rotateLeft(column, 16) ^ value.hashCode()); } } return rowCount ^ Integer.rotateLeft(columnCount, 16) ^ hash; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy