SquareChunk.java
/*******************************************************************************
* Copyright (c) 2021 Handy Tools for Distributed Computing (HanDist) project.
*
* This program and the accompanying materials are made available to you under
* the terms of the Eclipse Public License 1.0 which accompanies this
* distribution,
* and is available at https://www.eclipse.org/legal/epl-v10.html
*
* SPDX-License-Identifier: EPL-1.0
******************************************************************************/
package handist.collections;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.io.Serializable;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.KryoSerializable;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import handist.collections.function.LongTBiConsumer;
import handist.collections.function.SquareIndexTConsumer;
import handist.collections.function.SquareIndexTFunction;
/**
* @author yoshikikawanishi
*
* @param <T> type handled by the collection
*/
public class SquareChunk<T> implements Serializable, SquareRangedList<T>, KryoSerializable {
/**
* The class to create view for the specific column range in Square.
*
* @param <T> type handled by the collection
*/
static class ColumnView<T> extends MyView<T> {
private final int offset;
private final LongRange baseRange;
private final int stride;
private final Object[] a;
// TODO sublist based impl of iterators.
public ColumnView(int offset, int stride, LongRange baseRange, Object[] a) {
this.offset = offset;
this.baseRange = baseRange;
this.stride = stride;
this.a = a;
}
@SuppressWarnings("unchecked")
@Override
public <U> void forEachImpl(LongRange range, BiConsumer<? super T, Consumer<? super U>> action,
Consumer<? super U> receiver) {
rangeCheck(range);
long current = range.from;
int index = offset + (int) (range.from - baseRange.from);
while (current++ < range.to) {
action.accept((T) a[index], receiver);
index += stride;
}
}
@SuppressWarnings("unchecked")
@Override
public void forEachImpl(LongRange range, Consumer<? super T> action) {
rangeCheck(range);
long current = range.from;
int index = offset + (int) (range.from - baseRange.from);
while (current++ < range.to) {
action.accept((T) a[index]);
index += stride;
}
}
@SuppressWarnings("unchecked")
@Override
public void forEachImpl(LongRange range, LongTBiConsumer<? super T> action) {
rangeCheck(range);
long current = range.from;
int index = offset + (int) (range.from - baseRange.from) * stride;
while (current < range.to) {
action.accept(current++, (T) a[index]);
index += stride;
}
}
@Override
public LongRange getRange() {
return baseRange;
}
@Override
public Iterator<T> iterator() {
return new ColumnIterator<>(offset, baseRange, a, stride);
}
@Override
public RangedListIterator<T> listIterator() {
return new ColumnListIterator<>(offset, baseRange, a, stride);
}
@Override
public RangedListIterator<T> listIterator(long from) {
return new ColumnListIterator<>(offset, baseRange, from, a, stride);
}
@Override
public void rangeCheck(LongRange range) {
if (!baseRange.contains(range)) {
throw new IndexOutOfBoundsException(
"[ColumnView] range mismatch: " + this.getRange() + " does not include range");
}
}
@Override
protected Iterator<T> subIterator(LongRange range) {
// TODO check
final int newOffset = offset + (int) (range.from - baseRange.from) * stride;
return new ColumnIterator<>(newOffset, range, a, stride);
}
@Override
protected RangedListIterator<T> subListIterator(LongRange range) {
final int newOffset = offset + (int) (range.from - baseRange.from) * stride;
return new ColumnListIterator<>(newOffset, range, a, stride);
}
@Override
protected RangedListIterator<T> subListIterator(LongRange range, long from) {
final int newOffset = offset + (int) (range.from - baseRange.from) * stride;
return new ColumnListIterator<>(newOffset, range, from, a, stride);
}
}
/**
* The class to convert 1D to 2D.
*
* @param <T> type handled by the collection
*/
static class MySquareSiblingAccessor<T> implements SquareSiblingAccessor<T> {
private final int offset;
private final int innerSize;
private final Object[] a;
/**
* @param offset the offset of index
* @param innerSize the size of inner loop
* @param a the base array
*/
public MySquareSiblingAccessor(int offset, int innerSize, Object[] a) {
this.offset = offset;
this.innerSize = innerSize;
this.a = a;
}
@SuppressWarnings("unchecked")
@Override
public T get(int x, int y) {
assert (x <= 1 && x >= -1);
assert (y <= 1 && y >= -1);
return (T) a[offset + x * innerSize + y];
}
@Override
public void put(T v) {
a[offset] = v;
}
}
/**
* The class for implementing view of row and column.
*
* @param <T> type handled by the collection
*/
static abstract class MyView<T> extends RangedList<T> {
@Override
public RangedList<T> cloneRange(LongRange range) {
throw new UnsupportedOperationException("not implemented yet. may be shared abst class will be needed");
}
@Override
public boolean contains(Object o) {
throw new UnsupportedOperationException("not implemented yet. may be shared abst class will be needed");
}
@Override
public T get(long index) {
throw new UnsupportedOperationException("not implemented yet. may be shared abst class will be needed");
}
@Override
public abstract void rangeCheck(LongRange range);
@Override
public T set(long index, T value) {
throw new UnsupportedOperationException("not implemented yet. may be shared abst class will be needed");
}
@Override
public Object[] toArray() {
throw new UnsupportedOperationException("not implemented yet. may be shared abst class will be needed");
}
@Override
public Object[] toArray(LongRange r) {
throw new UnsupportedOperationException("not implemented yet. may be shared abst class will be needed");
}
@Override
public Chunk<T> toChunk(LongRange r) {
throw new UnsupportedOperationException("not implemented yet. may be shared abst class will be needed");
}
@Override
public List<T> toList(LongRange r) {
throw new UnsupportedOperationException("not implemented yet. may be shared abst class will be needed");
}
}
/**
* The class to create view for the specific row range in Square.
*/
static class RowView<T> extends MyView<T> {
private final int offset;
private final LongRange baseRange;
private final Object[] a;
// TODO sublist based impl of iterators.
public RowView(int offset, LongRange baseRange, Object[] a) {
this.offset = offset;
this.baseRange = baseRange;
this.a = a;
}
@SuppressWarnings("unchecked")
@Override
public <U> void forEachImpl(LongRange range, BiConsumer<? super T, Consumer<? super U>> action,
Consumer<? super U> receiver) {
rangeCheck(range);
long current = range.from;
int index = offset + (int) (range.from - baseRange.from);
while (current++ < range.to) {
action.accept((T) a[index++], receiver);
}
}
@SuppressWarnings("unchecked")
@Override
public void forEachImpl(LongRange range, Consumer<? super T> action) {
rangeCheck(range);
long current = range.from;
int index = offset + (int) (range.from - baseRange.from);
while (current++ < range.to) {
action.accept((T) a[index++]);
}
}
@SuppressWarnings("unchecked")
@Override
public void forEachImpl(LongRange range, LongTBiConsumer<? super T> action) {
rangeCheck(range);
long current = range.from;
int index = offset + (int) (range.from - baseRange.from);
while (current < range.to) {
action.accept(current++, (T) a[index++]);
}
}
@Override
public LongRange getRange() {
return baseRange;
}
@Override
public Iterator<T> iterator() {
return new ChunkIterator<>(offset, baseRange, a);
}
@Override
public RangedListIterator<T> listIterator() {
return new ChunkListIterator<>(offset, baseRange, a);
}
@Override
public RangedListIterator<T> listIterator(long from) {
return new ChunkListIterator<>(offset, baseRange, from, a);
}
@Override
public void rangeCheck(LongRange range) {
if (!baseRange.contains(range)) {
throw new IndexOutOfBoundsException(
"[RowView] range mismatch: " + this.getRange() + " does not include range");
}
}
@Override
protected Iterator<T> subIterator(LongRange range) {
rangeCheck(range);
final int newOffset = offset + (int) (range.from - baseRange.from);
return new ChunkIterator<>(newOffset, range, a);
}
@Override
protected RangedListIterator<T> subListIterator(LongRange range) {
rangeCheck(range);
final int newOffset = offset + (int) (range.from - baseRange.from);
return new ChunkListIterator<>(newOffset, range, a);
}
@Override
protected RangedListIterator<T> subListIterator(LongRange range, long from) {
rangeCheck(range);
final int newOffset = offset + (int) (range.from - baseRange.from);
return new ChunkListIterator<>(newOffset, range, from, a);
}
}
private static final long serialVersionUID = -8282656629771334491L;
/** Array containing the T objects */
private Object[] a;
/** Range on which this instance is defined */
private SquareRange range;
/** */
private long innerSize;
/**
* Builds a SquareChunk with the given range and no mapping.
* <p>
* The given SquareRange should have a strictly positive size. Giving a
* {@link SquareRange} instance with identical lower and upper bounds will
* result in a {@link IllegalArgumentException} being thrown.
* <p>
* If the {@link SquareRange} provided has a range that exceeds
* {@link Config#maxChunkSize} , an {@link IllegalArgumentException} will be be
* thrown.
*
* @param range the range of the chunk to build
* @throws IllegalArgumentException if a {@link SquareChunk} cannot be built
* with the provided range.
*/
public SquareChunk(SquareRange range) {
final long outerSize = range.outer.size();
this.innerSize = range.inner.size();
final long size = outerSize * innerSize;
if (range.isUpperTriangle) {
throw new IllegalArgumentException("Rectangle ranges are not supported by SquareChunk yet.");
}
// FIXME
if (size > Integer.MAX_VALUE) {
throw new RuntimeException("array size overflow");
}
if (size > Config.maxChunkSize) {
throw new IllegalArgumentException(
"The given range " + range + " exceeds the maximum Chunk size " + Config.maxChunkSize);
}
a = new Object[(int) size];
this.range = range;
}
/**
* Builds a {@link SquareChunk} with the provided {@link SquareRange} and an
* initial mapping for each long in the object array. The provided
* {@link SquareRange} and Object array should have the same size. An
* {@link IllegalArgumentException} will be thrown otherwise.
* <p>
* The given {@link SquareRange} should have a strictly positive size. Giving a
* {@link SquareRange} instance with identical lower and upper bounds will
* result in a {@link IllegalArgumentException} being thrown.
* <p>
* If the {@link SquareRange} provided has a range that exceeds
* {@link Config#maxChunkSize}, an {@link IllegalArgumentException} will be be
* thrown.
*
* @param range the range of the chunk to build
* @param a array with the initial mapping for every long in the provided
* range
* @throws IllegalArgumentException if a {@link SquareChunk} cannot be built
* with the provided range and object array.
*/
public SquareChunk(SquareRange range, Object[] a) {
this(range);
if (a.length != range.size()) {
throw new IllegalArgumentException("The length of the provided " + "array <" + a.length
+ "> does not match the size of the " + "LongRange <" + range.size() + ">");
}
// TODO Do we check for objects in array a that are not of type T?
// We can leave as is and let the code fail later in methods get and
// others where a ClassCastException should be thrown.
this.a = a;
}
/**
* Builds a {@link SquareChunk} with the provided {@link SquareRange}. The
* provided initializer generates the initial value of the element for each
* index. The given SquareRange should have a strictly positive size. Giving a
* {@link SquareRange} instance with identical lower and upper bounds will
* result in a {@link IllegalArgumentException} being thrown.
* <p>
* If the {@link SquareRange} provided has a range that exceeds
* {@link Config#maxChunkSize}, an {@link IllegalArgumentException} will be be
* thrown.
*
* @param range the range of the Squarechunk to build
* @param initializer generates the initial value of the element for each index.
* @throws IllegalArgumentException if a {@link SquareChunk} cannot be built
* with the provided range.
*/
public SquareChunk(SquareRange range, SquareIndexTFunction<T> initializer) {
this(range);
range.forEach((long index, long index2) -> {
set(index, index2, initializer.apply(index, index2));
});
}
/**
* Builds a {@link SquareChunk} with the provided {@link SquareRange} with each
* long in the provided range mapped to object t. The given LongRange should
* have a strictly positive size. Giving a {@link SquareRange} instance with
* identical lower and upper bounds will result in a
* {@link IllegalArgumentException} being thrown.
* <p>
* If the {@link SquareRange} provided has a range that exceeds
* {@link Config#maxChunkSize}, an {@link IllegalArgumentException} will be be
* thrown.
*
* @param range the range of the chunk to build
* @param t initial mapping for every long in the provided range
* @throws IllegalArgumentException if a {@link SquareChunk} cannot be built
* with the provided range.
*/
public SquareChunk(SquareRange range, T t) {
this(range);
// TODO Is this what we really want to do?
// The mapping will be on the SAME OBJECT for every long in LongRange.
// Don't we need a Generator<T> generator as argument and create an
// instance for each key with Arrays.setAll(a, generator) ?
Arrays.fill(a, t);
}
@Override
public RangedList<RangedList<T>> asColumnList() {
return new Chunk<>(range.inner, (Long columnIndex) -> {
return getColumnView(columnIndex);
});
}
@Override
public RangedList<RangedList<T>> asRowList() {
return new Chunk<>(range.outer, (Long rowIndex) -> {
return getRowView(rowIndex); // OK filter dependet
});
}
// /**
// * Returns a new Chunk defined on the same {@link LongRange} and with the same
// * contents as this instance.
// *
// * @return a copy of this instance
// */
// @Override
// public SquareChunk<T> clone() {
// // Object[] aClone = a.clone();
// final Object[] aClone = new Object[a.length];
//
// //// FIXME: 2018/09/19 Need deep copy?
// // for (int i = 0; i < a.length; i++) {
// // try {
// // aClone[i] = ((Cloneable) a[i]).clone();
// // } catch (CloneNotSupportedException e) {
// // e.printStackTrace();
// // }
// // }
//
// Arrays.fill(aClone, a[0]);
// System.arraycopy(a, 0, aClone, 0, a.length);
//
// return new SquareChunk<>(this.range, aClone);
// }
// @Override
// public SquareChunk<T> cloneRange(LongRange newRange) {
// return range == newRange ? clone() : toChunk(newRange);
// }
//
@Override
public boolean contains(Object v) {
for (final Object e : a) {
if (v == null ? e == null : v.equals(e)) {
return true;
}
}
return false;
}
/**
* (<em><tag></em>), row:<rowIndex> ->
* [<columnIndex>:<element>][<columnIndex>:<element>]...<br>
* (<em><tag></em>), row:<rowIndex> ->
* [<columnIndex>:<element>][<columnIndex>:<element>]...<br>
* ...
*
* @param tag header tag
*/
void debugPrint(String tag) {
debugPrint(tag, new PrintWriter(System.out));
}
/**
* (<em><tag></em>), row:<rowIndex> ->
* [<columnIndex>:<element>][<columnIndex>:<element>]...<br>
* (<em><tag></em>), row:<rowIndex> ->
* [<columnIndex>:<element>][<columnIndex>:<element>]...<br>
* ...
*
* @param tag header tag
* @param out {@link PrintWriter} to output
*/
void debugPrint(String tag, PrintWriter out) {
forEachRow((long index, RangedList<T> row) -> {
out.print("(" + tag + "), row:" + index + "->");
row.forEach((long i, T e) -> {
out.print("[" + i + ":" + e + "]");
});
out.println();
});
}
@Override
public boolean equals(Object o) {
if (o == null) {
return false;
}
if (!(o instanceof AbstractSquareRangedList)) {
return false;
}
final SquareRangedList<?> target = (SquareRangedList<?>) o;
// TODO this version is too slow,
// setupFrom will be the good candidate for fast simul scanner.
if (!getRange().equals(target.getRange())) {
return false;
}
for (final long i : getRange().outer) {
for (final long j : getRange().inner) {
if (!get(i, j).equals(target.get(i, j))) {
return false;
}
}
}
return true;
}
@SuppressWarnings("unchecked")
@Override
public void forEach(final Consumer<? super T> action) {
rangeCheck(range);
// TODO
// IntStream.range(begin, end).forEach();
for (final Object o : a) {
action.accept((T) o); // TODO filter dependent
}
}
@Override
public void forEach(final SquareIndexTConsumer<? super T> action) {
rangeCheck(range);
// TODO
// IntStream.range(begin, end).forEach();
long index = range.outer.from;
long index2 = range.inner.from;
int offset = 0;
while (true) {
@SuppressWarnings("unchecked")
final T v = (T) a[offset];
action.accept(index, index2, v);
index2++;
offset++;
if (index2 == range.inner.to) {
index2 = range.inner.from;
index++;
if (index == range.outer.to) {
return;
}
}
}
}
@SuppressWarnings("unchecked")
@Override
public void forEach(SquareRange range, final Consumer<? super T> action) {
rangeCheck(range);
// TODO
// IntStream.range(begin, end).forEach();
long index1 = range.outer.from;
long index2 = range.inner.from;
long offset1 = index1 - getRange().outer.from;
final long offset2 = index2 - getRange().inner.from;
// TODO overflow assert
int offset = (int) (offset1 * innerSize + offset2);
while (true) {
// TODO overflow assert
action.accept((T) a[offset]);
index2++;
offset++;
if (index2 == range.inner.to) {
index2 = range.inner.from; // TODO filter dependent
index1++;
if (index1 == range.outer.to) {
return;
}
offset1++;
offset = (int) (offset1 * innerSize + offset2);
}
}
}
@SuppressWarnings("unchecked")
@Override
public void forEach(SquareRange range, final SquareIndexTConsumer<? super T> action) {
rangeCheck(range);
// TODO
// IntStream.range(begin, end).forEach();
long index1 = range.outer.from;
long index2 = range.inner.from;
long offset1 = index1 - getRange().outer.from;
final long offset2 = index2 - getRange().inner.from;
// TODO overflow assert
int offset = (int) (offset1 * innerSize + offset2);
while (true) {
// TODO overflow assert
action.accept(index1, index2, (T) a[offset]);
index2++;
offset++;
if (index2 == range.inner.to) { // TODO filter dependent
index2 = range.inner.from;
index1++;
if (index1 == range.outer.to) {
return;
}
offset1++;
offset = (int) (offset1 * innerSize + offset2);
}
}
}
@Override
public void forEachColumn(LongRange range, LongTBiConsumer<RangedList<T>> columnAction) {
// TODO filter support
range = getRange().inner.intersection(range);
for (long index = range.from; index < range.to; index++) {
final RangedList<T> cView = getColumnView(index);
columnAction.accept(index, cView);
}
}
@Override
public void forEachColumn(LongTBiConsumer<RangedList<T>> columnAction) {
for (long index = getRange().inner.from; index < getRange().inner.to; index++) {
final RangedList<T> cView = getColumnView(index);
columnAction.accept(index, cView);
}
}
@Override
public void forEachRow(LongRange rRange, LongTBiConsumer<RangedList<T>> rowAction) {
rRange = getRange().outer.intersection(rRange);
for (long index = rRange.from; index < rRange.to; index++) {
final RangedList<T> rView = getRowView(index);
rowAction.accept(index, rView);
}
}
@Override
public void forEachRow(LongTBiConsumer<RangedList<T>> rowAction) {
for (long index = getRange().outer.from; index < getRange().outer.to; index++) {
final RangedList<T> rView = getRowView(index);
rowAction.accept(index, rView);
}
}
@Override
public void forEachWithSiblings(SquareRange range, final Consumer<SquareSiblingAccessor<T>> action) {
rangeCheck(range);
// TODO
// IntStream.range(begin, end).forEach();
long index1 = range.outer.from;
long index2 = range.inner.from;
long offset1 = index1 - getRange().outer.from;
final long offset2 = index2 - getRange().inner.from;
// TODO overflow assert
int offset = (int) (offset1 * innerSize + offset2);
while (true) {
// TODO overflow assert
// System.out.println("index:" + index1 + "," + index2 + ", offset" + offset1 +
// "," + offset2 + "," + offset);
final SquareSiblingAccessor<T> acc = new MySquareSiblingAccessor<>(offset, (int) innerSize, a);
action.accept(acc);
index2++;
offset++;
if (index2 == range.inner.to) { // TODO filter dependent
index2 = range.inner.from;
index1++;
if (index1 == range.outer.to) {
return;
}
offset1++;
// TODO overflow assert
offset = (int) (offset1 * innerSize + offset2);
}
}
}
/**
* {@inheritDoc}
*/
@Override
public T get(long index, long index2) { // TODO filter dependent
if (!getRange().outer.contains(index)) {
throw new IndexOutOfBoundsException(/* rangeMsg(index) */ index + " is outof " + getRange().outer);
}
if (!getRange().inner.contains(index2)) {
throw new IndexOutOfBoundsException(/* rangeMsg(index2) */ index2 + " is outof " + getRange().inner);
}
return getUnsafe(index, index2);
}
@Override
public RangedList<T> getColumnView(long column) {
if (!getRange().inner.contains(column)) {
throw new IndexOutOfBoundsException("column " + column + " is outof " + getRange());
}
final int offset = (int) (column - getRange().inner.from);
return new ColumnView<>(offset, (int) innerSize, getRange().outer, a); // TODO filter dependent
}
@Override
public SquareRange getRange() {
return range;
}
@Override
public RangedList<T> getRowView(long row) {
if (!getRange().outer.contains(row)) {
throw new IndexOutOfBoundsException("row " + row + " is outof " + getRange());
}
final int offset = (int) (innerSize * (row - getRange().outer.from));
return new RowView<>(offset, getRange().inner, a); // TODO filter dependent
}
/**
* Returns the element located at the provided index. The provided index is
* presumed valid and as such, no bound checking is done.
*
* @param index outer index whose value should be returned
* @param index2 inner index whose value should be returned
* @return the object stored at the provided index, possibly {@code null}
*/
@SuppressWarnings("unchecked")
final T getUnsafe(long index, long index2) { // when range check was done
final long offset1 = index - range.outer.from;
final long offset2 = index2 - range.inner.from;
return (T) a[(int) (offset1 * innerSize + offset2)];
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
return AbstractSquareRangedList.hashCode(this);
}
@Override
public Iterator<T> iterator() {
return new SquareChunkIterator<>(range, a);
}
@Deprecated
@Override
public void read(Kryo kryo, Input input) {
this.innerSize = input.readLong();
this.range = (SquareRange) kryo.readClassAndObject(input);
this.a = (Object[]) kryo.readClassAndObject(input);
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
this.innerSize = in.readLong();
this.range = (SquareRange) in.readObject();
this.a = (Object[]) in.readObject();
}
/**
* {@inheritDoc}
*/
@Override
public T set(long index, long index2, T value) {
if (!getRange().outer.contains(index)) {
throw new IndexOutOfBoundsException(/* rangeMsg(index) */ index + " is outof " + getRange().outer);
}
if (!getRange().inner.contains(index2)) {
throw new IndexOutOfBoundsException(/* rangeMsg(index2) */ index2 + " is outof " + getRange().inner);
}
return setUnsafe(index, index2, value);
}
@SuppressWarnings("unchecked")
private T setUnsafe(long index, long index2, T v) { // when range check was done
final long offset1 = index - range.outer.from;
final long offset2 = index2 - range.inner.from;
final long offset = offset1 * innerSize + offset2;
final T prev = (T) a[(int) offset];
a[(int) offset] = v;
return prev;
}
/**
* Initializes the values in this instance by applying the provided function on
* the elements contained in {@code source}
*
* @param <S> the type handled by the {@link RangedList} given as parameter,
* input for the function
* @param source {@link SquareChunk} instance from which entried for this
* instance will be extracted
* @param func function that takes an object of type S as parameter and
* returns a type T
*/
public <S> void setupFrom(SquareChunk<S> source, Function<? super S, ? extends T> func) {
// TODO 'source' should be SquareRangedList
// and this method also should be declared in SquareRangedList
rangeCheck(source.getRange());
// TODO filter dependent
final SquareIndexTConsumer<S> consumer = (long index1, long index2, S s) -> {
final T r = func.apply(s);
final long offset1 = index1 - getRange().outer.from;
final long offset2 = index2 - getRange().inner.from;
final long offset = offset1 * innerSize + offset2;
a[(int) offset] = r;
};
source.forEach(consumer);
}
@Override
public Iterator<T> subIterator(SquareRange range) {
final SquareRange r = range.intersection(getRange());
return new SquareChunkIterator<>(r, this.range, a);
}
@Override
public SquareRangedList<T> subView(SquareRange range) {
return new SquareRangedListView<>(this, range);
}
@Override
public Object[] toArray() {
return a;
}
@Override
public Object[] toArray(SquareRange newRange) {
// TODO : now copy array. more efficient implementation ?
final Object[] newRail = new Object[(int) newRange.size()];
final int[] count = { 0 };
forEach(newRange, (T t) -> {
newRail[count[0]] = t;
count[0]++;
});
return newRail;
}
@Override
public SquareChunk<T> toChunk(SquareRange newRange) {
// TODO : now copy chunk. more efficient implementation ?
final SquareChunk<T> newChunk = new SquareChunk<>(newRange);
forEach(newRange, (i, j, t) -> {
newChunk.set(i, j, t);
});
return newChunk;
}
@Override
public List<T> toList(SquareRange newRange) {
final ArrayList<T> list = new ArrayList<>((int) newRange.size());
forEach(newRange, (t) -> list.add(t)); // check range at forEach
return list;
}
@Override
public String toString() {
final StringWriter out = new StringWriter();
debugPrint(" ", new PrintWriter(out));
return out.toString();
}
@Deprecated
@Override
public void write(Kryo kryo, Output output) {
output.writeLong(innerSize);
kryo.writeClassAndObject(output, range);
kryo.writeClassAndObject(output, a);
}
private void writeObject(ObjectOutputStream out) throws IOException {
out.writeLong(innerSize);
out.writeObject(range);
out.writeObject(a);
}
}