Indexer.java
/*
* Copyright (C) 2014-2020 Samuel Audet
*
* Licensed either under the Apache License, Version 2.0, or (at your option)
* under the terms of the GNU General Public License as published by
* the Free Software Foundation (subject to the "Classpath" exception),
* either version 2, or any later version (collectively, 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
* http://www.gnu.org/licenses/
* http://www.gnu.org/software/classpath/license.html
*
* or as provided in the LICENSE.txt file that accompanied this code.
* 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.bytedeco.javacpp.indexer;
import java.nio.Buffer;
import org.bytedeco.javacpp.Pointer;
/**
* Top-level class of all data indexers, providing easy-to-use and efficient
* multidimensional access to primitive arrays, NIO buffers, and the raw memory interface.
* <p>
* Subclasses have {@code create()} factory methods for arrays, buffers, and pointers.
* The latter ones feature a {@code direct} argument that, when set to {@code false},
* instructs the method to create a large enough array, fill its content with the data
* from the pointer, and return an array-backed indexer, with the {@link #release()}
* method overridden to write back changes to the pointer. This doubles the memory
* usage, but is the only way to get acceptable performance on some implementations,
* such as Android. When {@code direct == true}, the raw memory interface (supporting
* long indexing) is used if available, and if not a buffer-backed indexer is returned.
*
* @see Raw
*
* @author Samuel Audet
*/
public abstract class Indexer implements AutoCloseable {
/** Calls {@link #release()}. */
@Override public void close() {
release();
}
/** See {@link Index#sizes}. */
@Deprecated protected long[] sizes;
/** See {@link StrideIndex#strides}. */
@Deprecated protected long[] strides;
/** The Index to be used for {@link #index(long...)}. */
protected final Index index;
/** Constructor to set the {@link #index}. */
protected Indexer(Index index) {
this.index = index;
this.sizes = index.sizes();
if (index instanceof StrideIndex) {
this.strides = ((StrideIndex)index).strides();
}
}
/** Calls {@code Indexer(Index.create(sizes, strides))}. */
protected Indexer(long[] sizes, long[] strides) {
this(Index.create(sizes, strides));
}
/** Returns {@code index.rank()}. */
public int rank() { return index.rank(); }
/** Returns {@code index.sizes()}. */
public long[] sizes() { return index.sizes(); }
/** Returns {@link #strides} or {@code null} if there are no strides. */
@Deprecated public long[] strides() { return strides; }
/** Returns {@code index.size(i)}. */
public long size(int i) { return index.size(i); }
/** Returns {@code strides[i]} or {@code -1} if there are no strides. */
@Deprecated public long stride(int i) { return strides != null ? strides[i] : -1; }
/** Returns {@code sizes.length > 0 && sizes.length < 4 ? sizes[0] : -1}. */
@Deprecated public long rows() { return sizes.length > 0 && sizes.length < 4 ? sizes[0] : -1; }
/** Returns {@code sizes.length > 1 && sizes.length < 4 ? sizes[1] : -1}. */
@Deprecated public long cols() { return sizes.length > 1 && sizes.length < 4 ? sizes[1] : -1; }
/** Returns {@code sizes.length > 1 && sizes.length < 4 ? sizes[1] : -1}. */
@Deprecated public long width() { return sizes.length > 1 && sizes.length < 4 ? sizes[1] : -1; }
/** Returns {@code sizes.length > 0 && sizes.length < 4 ? sizes[0] : -1}. */
@Deprecated public long height() { return sizes.length > 0 && sizes.length < 4 ? sizes[0] : -1; }
/** Returns {@code sizes.length > 2 && sizes.length < 4 ? sizes[2] : -1}. */
@Deprecated public long channels() { return sizes.length > 2 && sizes.length < 4 ? sizes[2] : -1; }
protected static final long checkIndex(long i, long size) {
if (i < 0 || i >= size) {
throw new IndexOutOfBoundsException(Long.toString(i));
}
return i;
}
/** See {@link StrideIndex#defaultStrides(long...)}. */
@Deprecated public static long[] strides(long... sizes) {
return StrideIndex.defaultStrides(sizes);
}
/** Returns {@code index.index(i)}. */
public long index(long i) {
return index.index(i);
}
/** Returns {@code index.index(i, j)}. */
public long index(long i, long j) {
return index.index(i, j);
}
/** Returns {@code index.index(i, j, k)}. */
public long index(long i, long j, long k) {
return index.index(i, j, k);
}
/** Returns {@code index.index(indices)}. */
public long index(long... indices) {
return index.index(indices);
}
/** The associated (optional) {@link Indexable}. */
protected Indexable indexable;
/** Returns {@link #indexable}. */
public Indexable indexable() { return indexable; }
/** Sets {@link #indexable} and returns this. */
public Indexer indexable(Indexable indexable) { this.indexable = indexable; return this; }
/** Returns the backing array, or {@code null} if none */
public Object array() { return null; }
/** Returns the backing buffer, or {@code null} if none */
public Buffer buffer() { return null; }
/** Returns the backing pointer, or {@code null} if none */
public Pointer pointer() { return null; }
/** Makes sure changes are reflected onto the backing memory and clears any references. */
public abstract void release();
/** Calls {@code get(int...indices)} and returns the value as a double. */
public abstract double getDouble(long... indices);
/** Casts value to primitive type and calls {@code put(long[] indices, <type> value)}. */
public abstract Indexer putDouble(long[] indices, double value);
/** Returns a new Indexer using the same data, but with a different Index. */
public abstract <I extends Indexer> I reindex(Index index);
@Override public String toString() {
long rows = sizes.length > 0 ? sizes[0] : 1,
cols = sizes.length > 1 ? sizes[1] : 1,
channels = sizes.length > 2 ? sizes[2] : 1;
StringBuilder s = new StringBuilder(rows > 1 ? "\n[ " : "[ ");
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
if (channels > 1) {
s.append("(");
}
for (int k = 0; k < channels; k++) {
double v = getDouble(i, j, k);
s.append((float)v);
if (k < channels - 1) {
s.append(", ");
}
}
if (channels > 1) {
s.append(")");
}
if (j < cols - 1) {
s.append(", ");
}
}
if (i < rows - 1) {
s.append("\n ");
}
}
s.append(" ]");
return s.toString();
}
}