// $Id: ArrayMultiArray.java,v 1.3 2003-02-03 20:09:03 donm Exp $
/*
* Copyright 1997-2000 Unidata Program Center/University Corporation for
* Atmospheric Research, P.O. Box 3000, Boulder, CO 80307,
* support@unidata.ucar.edu.
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or (at
* your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package ucar.multiarray;
import java.lang.reflect.Array;
import java.io.IOException;
/**
* MultiArray implementation which is an adapter for java language arrays.
* If you have a java array and want to wrap it
* in a MultiArray interface, use this class.
* Rank of these is always > 0, use ScalarMultiArray
* for scalars.
* <p>
* The set, setXXX, get, getXXX methods use the
* corresponding methods from java.lang.reflect.Array,
* the conversion and exception characteristics of the methods
* here are like the ones found there.
*
* @see java.lang.reflect.Array
* @see MultiArray
* @see ScalarMultiArray
*
* @author $Author: donm $
* @version $Revision: 1.3 $ $Date: 2003-02-03 20:09:03 $
*/
/*
* Implementation note:
* It has been suggested that we "factor common code in the get/set
* methods".
*
* public int getInt(int[] index)
* {
* return get(index).intValue();
* }
*
* This is probably desireable from a maintenance or clarity
* point of view.
* One would need to prove that this is not desireable from
* from a performance point of view to justify leaving it
* the way it is.
* For now, it seems to work the way it is, so I'm leaving it.
* Think of it as having been machine generated.
*/
public class
ArrayMultiArray
implements MultiArray
{
/**
* Package private constructor which avoids some of the
* protections of the public constructor below.
*/
ArrayMultiArray(Object aro, int theRank, Class componentType)
{
jla = aro;
rank = theRank;
this.componentType = componentType;
}
/**
* Given a java Object, typically an array of primitive
* (or an array of array of primitive ...), Provide a MultiArray
* interface to the provided object.
* The wrapper provided does not copy the object, so it remains
* accessable via the language [] notation
* and the java.lang.reflect.Array methods.
* Synchronization not provided by this interface.
* @param aro a (multi-dimensional) array of primitives.
*/
public
ArrayMultiArray(Object aro) {
int rank_ = 0;
Class componentType_ = aro.getClass();
while(componentType_.isArray())
{
rank_++;
componentType_ = componentType_.getComponentType();
}
if(rank_ == 0)
throw new IllegalArgumentException();
jla = aro;
rank = rank_;
componentType = componentType_;
}
/**
* Create a new MultiArray of the given componentType and shape.
* Storage for the values is allocated and owned by this with
* default initialization.
* @param componentType Class of the primitives or objects to
* be contained.
* @param dimensions the shape of the MultiArray.
* dimensions.length determines the rank of the new MultiArray.
*/
public
ArrayMultiArray(Class componentType, int [] dimensions)
{
rank = dimensions.length;
if(rank == 0)
throw new IllegalArgumentException();
this.componentType = componentType;
jla = Array.newInstance(componentType, dimensions);
}
/**
* A copy constructor.
* <p>
* Create a new MultiArray with the same componentType and shape
* as the argument
* @param ma the MultiArray to copy.
*/
public
ArrayMultiArray(MultiArray ma)
throws IOException
{
rank = ma.getRank();
if(rank == 0)
throw new IllegalArgumentException();
componentType = ma.getComponentType();
final int [] lengths = ma.getLengths();
jla = Array.newInstance(componentType, lengths);
IndexIterator odo = new IndexIterator(lengths);
for(; odo.notDone(); odo.incr())
{
final int [] index = odo.value();
this.set(index, ma.get(index));
}
}
/* Begin MultiArray Inquiry methods from MultiArrayInfo */
/**
* Returns the Class object representing the component
* type of the wrapped array. If the rank is greater than
* 1, this will be the component type of the leaf (rightmost)
* nested array.
* @see MultiArrayInfo#getComponentType
* @return Class the component type
*/
public Class
getComponentType() { return componentType; }
/**
* @see MultiArrayInfo#getRank
* @return int number of dimensions of the array
*/
public int
getRank() { return rank;}
/**
* As if java.lang.reflect.Array.getLength() were called recursively
* on the wrapped object, return the dimension lengths.
* @see MultiArrayInfo#getLengths
*
* @return int array whose length is the rank of this
* MultiArray and whose elements represent the
* length of each of it's dimensions
*/
public int []
getLengths() {
int [] lengths = new int[rank];
Object oo = jla;
for(int ii = 0; ii < rank; ii++) {
lengths[ii] = Array.getLength(oo);
oo = Array.get(oo, 0);
}
return lengths;
}
/**
* Returns <code>true</code> if and only if the effective dimension
* lengths can change. Always returns <code>false</code> for this class.
* @see MultiArrayInfo#isUnlimited
* @return boolean <code>false</code>
*/
public boolean
isUnlimited() { return false; }
/**
* Always returns false for this class.
* @see MultiArrayInfo#isScalar
* @return false
*/
public boolean
isScalar() { return rank == 0; }
/* End MultiArrayInfo */
/* Begin MultiArray Access methods from Accessor */
/**
* @see Accessor#get
*/
public Object
get(int [] index)
{
if(index.length < rank)
throw new IllegalArgumentException();
final int end = rank -1;
Object oo = jla;
for(int ii = 0 ; ii < end; ii++)
oo = Array.get(oo, index[ii]);
return Array.get(oo, index[end]);
}
/**
* @see Accessor#getBoolean
*/
public boolean
getBoolean(int[] index)
{
if(index.length < rank)
throw new IllegalArgumentException();
final int end = rank -1;
Object oo = jla;
for(int ii = 0 ; ii < end; ii++)
oo = Array.get(oo, index[ii]);
return Array.getBoolean(oo, index[end]);
}
/**
* @see Accessor#getChar
*/
public char
getChar(int[] index)
{
if(index.length < rank)
throw new IllegalArgumentException();
final int end = rank -1;
Object oo = jla;
for(int ii = 0 ; ii < end; ii++)
oo = Array.get(oo, index[ii]);
return Array.getChar(oo, index[end]);
}
/**
* @see Accessor#getByte
*/
public byte
getByte(int[] index)
{
if(index.length < rank)
throw new IllegalArgumentException();
final int end = rank -1;
Object oo = jla;
for(int ii = 0 ; ii < end; ii++)
oo = Array.get(oo, index[ii]);
return Array.getByte(oo, index[end]);
}
/**
* @see Accessor#getShort
*/
public short
getShort(int[] index)
{
if(index.length < rank)
throw new IllegalArgumentException();
final int end = rank -1;
Object oo = jla;
for(int ii = 0 ; ii < end; ii++)
oo = Array.get(oo, index[ii]);
return Array.getShort(oo, index[end]);
}
/**
* @see Accessor#getInt
*/
public int
getInt(int[] index)
{
if(index.length < rank)
throw new IllegalArgumentException();
final int end = rank -1;
Object oo = jla;
for(int ii = 0 ; ii < end; ii++)
oo = Array.get(oo, index[ii]);
return Array.getInt(oo, index[end]);
}
/**
* @see Accessor#getLong
*/
public long
getLong(int[] index)
{
if(index.length < rank)
throw new IllegalArgumentException();
final int end = rank -1;
Object oo = jla;
for(int ii = 0 ; ii < end; ii++)
oo = Array.get(oo, index[ii]);
return Array.getLong(oo, index[end]);
}
/**
* @see Accessor#getFloat
*/
public float
getFloat(int[] index)
{
if(index.length < rank)
throw new IllegalArgumentException();
final int end = rank -1;
Object oo = jla;
for(int ii = 0 ; ii < end; ii++)
oo = Array.get(oo, index[ii]);
return Array.getFloat(oo, index[end]);
}
/**
* @see Accessor#getDouble
*/
public double
getDouble(int[] index)
{
if(index.length < rank)
throw new IllegalArgumentException();
final int end = rank -1;
Object oo = jla;
for(int ii = 0 ; ii < end; ii++)
oo = Array.get(oo, index[ii]);
return Array.getDouble(oo, index[end]);
}
/**
* @see Accessor#set
*/
public void
set(int [] index, Object value)
{
if(index.length < rank)
throw new IllegalArgumentException();
final int end = rank -1;
Object oo = jla;
for(int ii = 0 ; ii < end; ii++)
oo = Array.get(oo, index[ii]);
Array.set(oo, index[end], value);
return;
}
/**
* @see Accessor#setBoolean
*/
public void
setBoolean(int [] index, boolean value)
{
if(index.length < rank)
throw new IllegalArgumentException();
final int end = rank -1;
Object oo = jla;
for(int ii = 0 ; ii < end; ii++)
oo = Array.get(oo, index[ii]);
Array.setBoolean(oo, index[end], value);
}
/**
* @see Accessor#setChar
*/
public void
setChar(int [] index, char value)
{
if(index.length < rank)
throw new IllegalArgumentException();
final int end = rank -1;
Object oo = jla;
for(int ii = 0 ; ii < end; ii++)
oo = Array.get(oo, index[ii]);
Array.setChar(oo, index[end], value);
}
/**
* @see Accessor#setByte
*/
public void
setByte(int [] index, byte value)
{
if(index.length < rank)
throw new IllegalArgumentException();
final int end = rank -1;
Object oo = jla;
for(int ii = 0 ; ii < end; ii++)
oo = Array.get(oo, index[ii]);
Array.setByte(oo, index[end], value);
}
/**
* @see Accessor#setShort
*/
public void
setShort(int [] index, short value)
{
if(index.length < rank)
throw new IllegalArgumentException();
final int end = rank -1;
Object oo = jla;
for(int ii = 0 ; ii < end; ii++)
oo = Array.get(oo, index[ii]);
Array.setShort(oo, index[end], value);
}
/**
* @see Accessor#setInt
*/
public void
setInt(int [] index, int value)
{
if(index.length < rank)
throw new IllegalArgumentException();
final int end = rank -1;
Object oo = jla;
for(int ii = 0 ; ii < end; ii++)
oo = Array.get(oo, index[ii]);
Array.setInt(oo, index[end], value);
}
/**
* @see Accessor#setLong
*/
public void
setLong(int [] index, long value)
{
if(index.length < rank)
throw new IllegalArgumentException();
final int end = rank -1;
Object oo = jla;
for(int ii = 0 ; ii < end; ii++)
oo = Array.get(oo, index[ii]);
Array.setLong(oo, index[end], value);
}
/**
* @see Accessor#setFloat
*/
public void
setFloat(int [] index, float value)
{
if(index.length < rank)
throw new IllegalArgumentException();
final int end = rank -1;
Object oo = jla;
for(int ii = 0 ; ii < end; ii++)
oo = Array.get(oo, index[ii]);
Array.setFloat(oo, index[end], value);
}
/**
* @see Accessor#setDouble
*/
public void
setDouble(int[] index, double value)
{
if(index.length < rank)
throw new IllegalArgumentException();
final int end = rank -1;
Object oo = jla;
for(int ii = 0 ; ii < end; ii++)
oo = Array.get(oo, index[ii]);
Array.setDouble(oo, index[end], value);
}
/**
* @see Accessor#copyout
*/
public MultiArray
copyout(int [] origin, int [] shape)
{
if(origin.length != rank
|| shape.length != rank)
throw new IllegalArgumentException("Rank Mismatch");
final int [] shp = (int []) shape.clone();
final int [] pducts = new int[shp.length];
final int product = MultiArrayImpl.numberOfElements(shp,
pducts);
final Object dst = Array.newInstance(getComponentType(),
product);
int ji = rank -1;
int src_pos = origin[ji];
if(ji == 0)
{
// rank == 1
// No loop required
System.arraycopy(jla, src_pos,
dst, 0, product);
}
else
{
ji--;
final int contig = pducts[ji];
final OffsetIndexIterator odo =
new OffsetIndexIterator(truncCopy(origin),
getTruncLengths());
for(int dst_pos = 0; dst_pos < product;
dst_pos += contig)
{
System.arraycopy(getLeaf(odo.value()), src_pos,
dst, dst_pos, contig);
odo.incr();
}
}
return new MultiArrayImpl(shp, pducts,
dst);
}
/* TODO: specialize & optimise? */
/**
* @see Accessor#copyin
*/
public void
copyin(int [] origin, MultiArray data)
throws IOException
{
if(origin.length != rank
|| data.getRank() != rank)
throw new IllegalArgumentException("Rank Mismatch");
// else
if(data.getComponentType() != componentType)
throw new ArrayStoreException();
// else
AbstractAccessor.copy(data, data.getLengths(), this, origin);
}
/**
* @see Accessor#toArray
*/
public Object
toArray()
{
return this.toArray(null, null, null);
}
public Object getStorage () {
return jla;
}
/**
* @see Accessor#toArray
*/
public Object
toArray(Object dst, int [] origin, int [] shape)
{
if(origin == null)
origin = new int[rank];
else if(origin.length != rank)
throw new IllegalArgumentException("Rank Mismatch");
int [] shp = null;
if(shape == null)
shp = getLengths();
else if(shape.length == rank)
shp = (int []) shape.clone();
else
throw new IllegalArgumentException("Rank Mismatch");
final int [] pducts = new int[shp.length];
final int product = MultiArrayImpl.numberOfElements(shp,
pducts);
dst = MultiArrayImpl.fixDest(dst, product, componentType);
int ji = rank -1;
int src_pos = origin[ji];
if(ji == 0)
{
// rank == 1
// No loop required
System.arraycopy(jla, src_pos,
dst, 0, product);
}
else
{
ji--;
final int contig = pducts[ji];
final OffsetIndexIterator odo =
new OffsetIndexIterator(truncCopy(origin),
getTruncLengths());
for(int dst_pos = 0; dst_pos < product;
dst_pos += contig)
{
System.arraycopy(getLeaf(odo.value()),
src_pos,
dst, dst_pos, contig);
odo.incr();
}
}
return dst;
}
/* End Accessor */
static int []
truncCopy(int [] src)
{
final int len = src.length -1;
int [] dst = new int [len];
System.arraycopy(src, 0, dst, 0, len);
return dst;
}
/**
* Peel the array by fixing the leftmost index value
* to the argument. Reduces rank by 1.
* If the result would be of primitive type,
* it is appropriately wrapped.
* @return Object value at <code>index</code>
*/
public Object
get(int index)
{
if(rank == 1)
return Array.get(jla, index);
// else
return new ArrayMultiArray(Array.get(jla, index),
rank -1,
componentType);
}
/**
* Get the leaf array at Index.
*/
public Object
getLeaf(int [] index)
{
final int end = rank -2;
if(index.length <= end)
throw new IllegalArgumentException();
Object oo = jla;
for(int ii = 0 ; ii < end; ii++)
oo = Array.get(oo, index[ii]);
return Array.get(oo, index[end]);
}
/**
* @return int array whose length is the rank of this minus one
* MultiArray and whose elements represent the
* length of each of it's leading dimensions
*/
private int []
getTruncLengths() {
final int containRank = rank - 1;
int [] lengths = new int[containRank];
Object oo = jla;
for(int ii = 0; ii < containRank; ii++) {
lengths[ii] = Array.getLength(oo);
oo = Array.get(oo, 0);
}
return lengths;
}
/**
* The java language array which this adapts.
*/
public final Object jla;
private final int rank;
private final Class componentType;
/* Begin Test */
public static void
main(String[] args)
{
System.out.println(">> " + System.currentTimeMillis());
final int [] shape = {48, 64};
MultiArrayImpl init =
new MultiArrayImpl(Integer.TYPE, shape);
{
final int size = MultiArrayImpl.numberOfElements(shape);
for(int ii = 0; ii < size; ii++)
java.lang.reflect.Array.setInt(init.storage,
ii, ii);
}
ArrayMultiArray src = (ArrayMultiArray) null;
try {
src = new ArrayMultiArray(init);
}
catch (java.io.IOException ee) {}
int [] clip = new int[] {32, 64};
int [] origin = new int[] {8, 0};
MultiArray ma = src.copyout(origin, clip);
try {
System.out.println("Rank " + ma.getRank());
int [] lengths = ma.getLengths();
System.out.println("Shape { " + lengths[0] + ", "
+ lengths[1] + " }");
System.out.println(ma.getInt(new int[] {0, 0}));
System.out.println(ma.getInt(new int[] {1, 0}));
System.out.println(ma.getInt(new int[] {lengths[0] -1, lengths[1] -1}));
}
catch (java.io.IOException ee) {}
clip = new int[] {48, 48};
origin = new int[] {0, 8};
ma = src.copyout(origin, clip);
try {
System.out.println("Rank " + ma.getRank());
int [] lengths = ma.getLengths();
System.out.println("Shape { " + lengths[0] + ", "
+ lengths[1] + " }");
System.out.println(ma.getInt(new int[] {0, 0}));
System.out.println(ma.getInt(new int[] {1, 0}));
System.out.println(ma.getInt(new int[] {lengths[0] -1, lengths[1] -1}));
}
catch (java.io.IOException ee) {}
ArrayMultiArray dest =
new ArrayMultiArray(Integer.TYPE, shape);
try {
dest.copyin(origin, ma);
System.out.println("***Rank " + dest.getRank());
int [] lengths = dest.getLengths();
System.out.println("Shape { " + lengths[0] + ", "
+ lengths[1] + " }");
System.out.println(dest.getInt(new int[] {0, 0}));
System.out.println(dest.getInt(new int[] {0, 7}));
System.out.println(dest.getInt(new int[] {0, 8}));
System.out.println(dest.getInt(new int[] {47, 55}));
System.out.println(dest.getInt(new int[] {47, 56}));
System.out.println(dest.getInt(new int[] {47, 63}));
}
catch (java.io.IOException ee) {}
}
/* End Test */
}