nom.tam.util.ColumnTable Maven / Gradle / Ivy
package nom.tam.util;
/*
* #%L
* nom.tam FITS library
* %%
* Copyright (C) 2004 - 2015 nom-tam-fits
* %%
* This is free and unencumbered software released into the public domain.
*
* Anyone is free to copy, modify, publish, use, compile, sell, or
* distribute this software, either in source code form or as a compiled
* binary, for any purpose, commercial or non-commercial, and by any
* means.
*
* In jurisdictions that recognize copyright laws, the author or authors
* of this software dedicate any and all copyright interest in the
* software to the public domain. We make this dedication for the benefit
* of the public at large and to the detriment of our heirs and
* successors. We intend this dedication to be an overt act of
* relinquishment in perpetuity of all present and future rights to this
* software under copyright law.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
* #L%
*/
import java.io.IOException;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import nom.tam.util.type.PrimitiveType;
import nom.tam.util.type.PrimitiveTypeHandler;
import nom.tam.util.type.PrimitiveTypes;
/**
* A data table is conventionally considered to consist of rows and columns,
* where the structure within each column is constant, but different columns may
* have different structures. I.e., structurally columns may differ but rows are
* identical. Typically tabular data is usually stored in row order which can
* make it extremely difficult to access efficiently using Java. This class
* provides efficient access to data which is stored in row order and allows
* users to get and set the elements of the table. The table can consist only of
* arrays of primitive types. Data stored in column order can be efficiently
* read and written using the BufferedDataXputStream classes. The table is
* represented entirely as a set of one-dimensional primitive arrays. For a
* given column, a row consists of some number of contiguous elements of the
* array. Each column is required to have the same number of rows. Information
* regarding the dimensionality of columns and possible data pointers is
* retained for use by clients which can understand them.
*/
public class ColumnTable implements DataTable {
private static final int MAX_COLUMN_INDEXES = 256;
private static final int MAX_TYPE_VALUE = MAX_COLUMN_INDEXES;
private interface PointerAccess {
void set(ColumnTable> table, X array);
X get(ColumnTable> table);
void write(ColumnTable> table, ArrayDataOutput os, int index, int arrOffset, int size) throws IOException;
void read(ColumnTable> table, ArrayDataInput is, int index, int arrOffset, int size) throws IOException;
}
private static final Map, PointerAccess>> POINTER_ACCESSORS;
private static final PointerAccess>[] POINTER_ACCESSORS_BY_TYPE = new PointerAccess>[MAX_TYPE_VALUE];
static {
POINTER_ACCESSORS_BY_TYPE[PrimitiveTypes.BYTE.type()] = new PointerAccess() {
@Override
public byte[][] get(ColumnTable> table) {
return table.bytePointers;
}
@Override
public void set(ColumnTable> table, byte[][] array) {
table.bytePointers = array;
}
@Override
public void write(ColumnTable> table, ArrayDataOutput os, int index, int arrOffset, int size) throws IOException {
os.write(table.bytePointers[index], arrOffset, size);
}
@Override
@SuppressFBWarnings(value = "RR_NOT_CHECKED", justification = "this read will never return less than the requested length")
public void read(ColumnTable> table, ArrayDataInput is, int index, int arrOffset, int size) throws IOException {
is.read(table.bytePointers[index], arrOffset, size);
}
};
POINTER_ACCESSORS_BY_TYPE[PrimitiveTypes.BOOLEAN.type()] = new PointerAccess() {
@Override
public boolean[][] get(ColumnTable> table) {
return table.booleanPointers;
}
@Override
public void set(ColumnTable> table, boolean[][] array) {
table.booleanPointers = array;
}
@Override
public void write(ColumnTable> table, ArrayDataOutput os, int index, int arrOffset, int size) throws IOException {
os.write(table.booleanPointers[index], arrOffset, size);
}
@Override
public void read(ColumnTable> table, ArrayDataInput is, int index, int arrOffset, int size) throws IOException {
is.read(table.booleanPointers[index], arrOffset, size);
}
};
POINTER_ACCESSORS_BY_TYPE[PrimitiveTypes.SHORT.type()] = new PointerAccess() {
@Override
public short[][] get(ColumnTable> table) {
return table.shortPointers;
}
@Override
public void set(ColumnTable> table, short[][] array) {
table.shortPointers = array;
}
@Override
public void write(ColumnTable> table, ArrayDataOutput os, int index, int arrOffset, int size) throws IOException {
os.write(table.shortPointers[index], arrOffset, size);
}
@Override
public void read(ColumnTable> table, ArrayDataInput is, int index, int arrOffset, int size) throws IOException {
is.read(table.shortPointers[index], arrOffset, size);
}
};
POINTER_ACCESSORS_BY_TYPE[PrimitiveTypes.CHAR.type()] = new PointerAccess() {
@Override
public char[][] get(ColumnTable> table) {
return table.charPointers;
}
@Override
public void set(ColumnTable> table, char[][] array) {
table.charPointers = array;
}
@Override
public void write(ColumnTable> table, ArrayDataOutput os, int index, int arrOffset, int size) throws IOException {
os.write(table.charPointers[index], arrOffset, size);
}
@Override
@SuppressFBWarnings(value = "RR_NOT_CHECKED", justification = "this read will never return less than the requested length")
public void read(ColumnTable> table, ArrayDataInput is, int index, int arrOffset, int size) throws IOException {
is.read(table.charPointers[index], arrOffset, size);
}
};
POINTER_ACCESSORS_BY_TYPE[PrimitiveTypes.INT.type()] = new PointerAccess() {
@Override
public int[][] get(ColumnTable> table) {
return table.intPointers;
}
@Override
public void set(ColumnTable> table, int[][] array) {
table.intPointers = array;
}
@Override
public void write(ColumnTable> table, ArrayDataOutput os, int index, int arrOffset, int size) throws IOException {
os.write(table.intPointers[index], arrOffset, size);
}
@Override
public void read(ColumnTable> table, ArrayDataInput is, int index, int arrOffset, int size) throws IOException {
is.read(table.intPointers[index], arrOffset, size);
}
};
POINTER_ACCESSORS_BY_TYPE[PrimitiveTypes.LONG.type()] = new PointerAccess() {
@Override
public long[][] get(ColumnTable> table) {
return table.longPointers;
}
@Override
public void set(ColumnTable> table, long[][] array) {
table.longPointers = array;
}
@Override
public void write(ColumnTable> table, ArrayDataOutput os, int index, int arrOffset, int size) throws IOException {
os.write(table.longPointers[index], arrOffset, size);
}
@Override
public void read(ColumnTable> table, ArrayDataInput is, int index, int arrOffset, int size) throws IOException {
is.read(table.longPointers[index], arrOffset, size);
}
};
POINTER_ACCESSORS_BY_TYPE[PrimitiveTypes.FLOAT.type()] = new PointerAccess() {
@Override
public float[][] get(ColumnTable> table) {
return table.floatPointers;
}
@Override
public void set(ColumnTable> table, float[][] array) {
table.floatPointers = array;
}
@Override
public void write(ColumnTable> table, ArrayDataOutput os, int index, int arrOffset, int size) throws IOException {
os.write(table.floatPointers[index], arrOffset, size);
}
@Override
public void read(ColumnTable> table, ArrayDataInput is, int index, int arrOffset, int size) throws IOException {
is.read(table.floatPointers[index], arrOffset, size);
}
};
POINTER_ACCESSORS_BY_TYPE[PrimitiveTypes.DOUBLE.type()] = new PointerAccess() {
@Override
public double[][] get(ColumnTable> table) {
return table.doublePointers;
}
@Override
public void set(ColumnTable> table, double[][] array) {
table.doublePointers = array;
}
@Override
public void write(ColumnTable> table, ArrayDataOutput os, int index, int arrOffset, int size) throws IOException {
os.write(table.doublePointers[index], arrOffset, size);
}
@Override
public void read(ColumnTable> table, ArrayDataInput is, int index, int arrOffset, int size) throws IOException {
is.read(table.doublePointers[index], arrOffset, size);
}
};
Map, PointerAccess>> pointerAccess = new HashMap, PointerAccess>>();
pointerAccess.put(PrimitiveTypes.BYTE, POINTER_ACCESSORS_BY_TYPE[PrimitiveTypes.BYTE.type()]);
pointerAccess.put(PrimitiveTypes.BOOLEAN, POINTER_ACCESSORS_BY_TYPE[PrimitiveTypes.BOOLEAN.type()]);
pointerAccess.put(PrimitiveTypes.CHAR, POINTER_ACCESSORS_BY_TYPE[PrimitiveTypes.CHAR.type()]);
pointerAccess.put(PrimitiveTypes.SHORT, POINTER_ACCESSORS_BY_TYPE[PrimitiveTypes.SHORT.type()]);
pointerAccess.put(PrimitiveTypes.INT, POINTER_ACCESSORS_BY_TYPE[PrimitiveTypes.INT.type()]);
pointerAccess.put(PrimitiveTypes.LONG, POINTER_ACCESSORS_BY_TYPE[PrimitiveTypes.LONG.type()]);
pointerAccess.put(PrimitiveTypes.FLOAT, POINTER_ACCESSORS_BY_TYPE[PrimitiveTypes.FLOAT.type()]);
pointerAccess.put(PrimitiveTypes.DOUBLE, POINTER_ACCESSORS_BY_TYPE[PrimitiveTypes.DOUBLE.type()]);
POINTER_ACCESSORS = Collections.unmodifiableMap(pointerAccess);
}
/** The columns to be read/written */
private Object[] arrays;
/** The number of elements in a row for each column */
private int[] sizes;
/** The number of rows */
private int nrow;
/**
* The base type of each row (using the second character of the [x class
* names of the arrays.
*/
private char[] types;
private Class>[] bases;
// The following arrays are used to avoid having to check
// casts during the I/O loops.
// They point to elements of arrays.
private byte[][] bytePointers;
private short[][] shortPointers;
private int[][] intPointers;
private long[][] longPointers;
private float[][] floatPointers;
private double[][] doublePointers;
private char[][] charPointers;
private boolean[][] booleanPointers;
/**
* Allow the client to provide opaque data.
*/
private T extraState;
/**
* Create the object after checking consistency.
*
* @param arrays
* An array of one-d primitive arrays.
* @param sizes
* The number of elements in each row for the corresponding
* column
* @throws TableException
* if the structure of the columns is not consistent
*/
public ColumnTable(Object[] arrays, int[] sizes) throws TableException {
setup(arrays, sizes);
}
/**
* Add a column .
*
* @param newColumn
* the column to add.
* @param size
* size for the column
* @throws TableException
* if the structure of the new column does not fit the structure
* of the rows/columns
*/
public void addColumn(Object newColumn, int size) throws TableException {
String classname = newColumn.getClass().getName();
this.nrow = checkColumnConsistency(newColumn, classname, this.nrow, size);
int ncol = this.arrays.length;
Object[] newArrays = new Object[ncol + 1];
int[] newSizes = new int[ncol + 1];
Class>[] newBases = new Class[ncol + 1];
char[] newTypes = new char[ncol + 1];
System.arraycopy(this.arrays, 0, newArrays, 0, ncol);
System.arraycopy(this.sizes, 0, newSizes, 0, ncol);
System.arraycopy(this.bases, 0, newBases, 0, ncol);
System.arraycopy(this.types, 0, newTypes, 0, ncol);
this.arrays = newArrays;
this.sizes = newSizes;
this.bases = newBases;
this.types = newTypes;
this.arrays[ncol] = newColumn;
this.sizes[ncol] = size;
this.bases[ncol] = ArrayFuncs.getBaseClass(newColumn);
this.types[ncol] = classname.charAt(1);
addPointer(newColumn);
}
/**
* Add a pointer in the pointer lists.
*
* @param data
* data pointer to add
* @throws TableException
* if the structure of the specified array does not fit the
* structure of the rows/columns
*/
protected void addPointer(Object data) throws TableException {
PointerAccess
© 2015 - 2025 Weber Informatics LLC | Privacy Policy