// $Id: ScalarMultiArray.java,v 1.3 2003-02-03 20:09:07 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; import java.lang.reflect.Method; import java.lang.reflect.InvocationTargetException; /** * MultiArray implementation which can only contain single values, * aka scalars. * If you have a single object and want to wrap it * in a MultiArray interface, use this class. * Rank of these is always zero. * The index argument to the set, setXXX, get, and getXXX is ignored. * <p> * When the component type is primitive, this class is an adapter for * the appropriate java.lang primitive wrapper (Double, Float, and so on). * One of the purposes of this class is to substitute for * the wrappers in the MultiArray context, providing continuity of access * method signature between arrays and scalars. Contrast this with the the * discontinuity between java.util.reflect.Array.getDouble() * and java.lang.Number.doubleValue(). * * @see MultiArray * @see ArrayMultiArray * * @author $Author: donm $ * @version $Revision: 1.3 $ $Date: 2003-02-03 20:09:07 $ */ public class ScalarMultiArray implements MultiArray { /** * Construct a new ScalarMultiArray with the specified component * type. This form of constructor would typically be used for * primitive component types such as java.lang.Double.TYPE. * @param theComponentType the Class object representing * the component type of the new MultiArray */ public ScalarMultiArray(Class theComponentType) { componentType = theComponentType; } /** * Construct a new ScalarMultiArray with the specified component * type and initialize it to the value given. * This form of constructor would typically be used for * primitive component types such as java.lang.Double.TYPE, * value would be a wrapped primitive of compatible class. * @param theComponentType the Class object representing * the component type of the new MultiArray * @param value the initial value */ public ScalarMultiArray(Class theComponentType, Object value) { componentType = theComponentType; this.set((int [])null, value); } /** * Construct a new ScalarMultiArray with component * type value.getClass() and initialize it to the value given. * @param value the initial value */ public ScalarMultiArray(Object value) { componentType = value.getClass(); obj = value; } /* Begin MultiArray Inquiry methods from MultiArrayInfo */ /** * @see MultiArrayInfo#getComponentType */ public Class getComponentType() { return componentType; } /** * Always returns zero for members of this class. * @see MultiArrayInfo#getRank * @return int 0 */ public int getRank() { return 0;} /** * Always returns empty array for members of this class. * @see MultiArrayInfo#getLengths * @return int array of length zero. */ public int [] getLengths() { int [] lengths = new int[0]; return lengths; } /** * Always returns <code>false</code> for members of this class. * @see MultiArrayInfo#isUnlimited * @return boolean <code>false</code> */ public boolean isUnlimited() { return false; } /** * Alway <code>true</code> for members of this class. * @see MultiArrayInfo#isUnlimited * @return boolean <code>true</code> */ public boolean isScalar() { return true; } /* End MultiArrayInfo */ /* Begin MultiArray Access methods from Accessor */ /** * Retrieve the object in this container. * @see Accessor#get * @param index ignored * @return the Object contained herein */ public Object get(int [] index) { return obj; } /** * As if <code>(((Character)this.get(index)).charValue();</code> * were called. * @see Accessor#getChar * @see #get * @see java.lang.Character#charValue() */ public char getChar(int[] index) { return ((Character)obj).charValue(); } /** * As if <code>(((Boolean)this.get(index)).booleanValue();</code> * were called. * @see Accessor#getBoolean * @see #get * @see java.lang.Boolean#booleanValue() */ public boolean getBoolean(int[] index) { return ((Boolean)obj).booleanValue(); } /** * As if <code>(((Number)this.get(index)).byteValue();</code> * were called. * @see Accessor#getByte * @see #get * @see java.lang.Number#byteValue */ public byte getByte(int[] index) { return ((Number)obj).byteValue(); } /** * As if <code>(((Number)this.get(index)).shortValue();</code> * were called. * @see Accessor#getShort * @see #get * @see java.lang.Number#shortValue */ public short getShort(int[] index) { return ((Number)obj).shortValue(); } /** * As if <code>(((Number)this.get(index)).intValue();</code> * were called. * @see Accessor#getInt * @see #get * @see java.lang.Number#intValue */ public int getInt(int[] index) { return ((Number)obj).intValue(); } /** * As if <code>(((Number)this.get(index)).longValue();</code> * were called. * @see Accessor#getLong * @see #get * @see java.lang.Number#longValue */ public long getLong(int[] index) { return ((Number)obj).longValue(); } /** * As if <code>(((Number)this.get(index)).floatValue();</code> * were called. * @see Accessor#getFloat * @see #get * @see java.lang.Number#floatValue */ public float getFloat(int[] index) { return ((Number)obj).floatValue(); } /** * As if <code>(((Number)this.get(index)).doubleValue();</code> * were called. * @see Accessor#getDouble * @see #get * @see java.lang.Number#doubleValue */ public double getDouble(int[] index) { return ((Number)obj).doubleValue(); } /* TODO: ArrayStoreException vs IllegalArgumentException */ /** * Set the object contained here to value. * The index argument is ignored. * @see Accessor#set * @param index ignored * @param value the replacement contents */ public void set(int [] index, Object value) { final Class xcls = value.getClass(); if(componentType.isPrimitive()) { try { if(componentType == (Class) xcls.getDeclaredField("TYPE"). get(value)) { // value is a wrapper for componentType obj = value; return; } } catch (NoSuchFieldException ee) { // continue } catch (IllegalAccessException ee) { // continue } // Value is not the specific wrapper. // Maybe it is assignable... Method tValueMethod; try { tValueMethod = xcls.getMethod( componentType.getName()+"Value", new Class[0]); } catch (NoSuchMethodException nsme) { // Can't convert throw new IllegalArgumentException(); } // else try { obj = tValueMethod.invoke(value, new Object[0]); return; } catch (IllegalAccessException iae) { // assert(wrapper.xxxValue() is accessable); throw new Error(); } catch (InvocationTargetException ite) { throw (RuntimeException) ite.getTargetException(); } } // else if(!componentType.isAssignableFrom(xcls)) { // Can't convert throw new IllegalArgumentException(); } // else obj = value; } /** * Set the object contained here to a boolean value. * The index argument is ignored. * @see Accessor#setBoolean * @param index ignored * @param value the new value */ public void setBoolean(int [] index, boolean value) { this.set(index, new Boolean(value)); } /** * Set the object contained here to a char value. * The index argument is ignored. * @see Accessor#setChar * @param index ignored * @param value the new value */ public void setChar(int [] index, char value) { this.set(index, new Character(value)); } /** * Set the object contained here to a byte value. * The index argument is ignored. * @see Accessor#setByte * @param index ignored * @param value the new value */ public void setByte(int [] index, byte value) { this.set(index, new Byte(value)); } /** * Set the object contained here to a short value. * The index argument is ignored. * @see Accessor#setShort * @param index ignored * @param value the new value */ public void setShort(int [] index, short value) { this.set(index, new Short(value)); } /** * Set the object contained here to a int value. * The index argument is ignored. * @see Accessor#setInt * @param index ignored * @param value the new value */ public void setInt(int [] index, int value) { this.set(index, new Integer(value)); } /** * Set the object contained here to a long value. * The index argument is ignored. * @see Accessor#setLong * @param index ignored * @param value the new value */ public void setLong(int [] index, long value) { this.set(index, new Long(value)); } /** * Set the object contained here to a float value. * The index argument is ignored. * @see Accessor#setFloat * @param index ignored * @param value the new value */ public void setFloat(int [] index, float value) { this.set(index, new Float(value)); } /** * Set the object contained here to a double value. * The index argument is ignored. * @see Accessor#setDouble * @param index ignored * @param value the new value */ public void setDouble(int[] index, double value) { this.set(index, new Double(value)); } /** * @see Accessor#copyout */ public MultiArray copyout(int [] origin, int [] shape) { if(origin != null && origin.length != 0 || shape != null && shape.length != 0) throw new IllegalArgumentException("Rank Mismatch"); try { return new MultiArrayImpl(this); } catch (IOException ie) { // Can't happen: reading this won't generate i/o throw new Error(); } } /** * @see Accessor#copyin */ public void copyin(int [] origin, MultiArray src) throws IOException { if(origin != null && origin.length != 0 || src.getRank() != 0) throw new IllegalArgumentException("Rank Mismatch"); // We know src isScalar, but we don't know if it ignores // the index arg... final int [] nonarg = new int[] {}; set(nonarg, src.get(nonarg)); } /** * TODO: fishy semantics. * @see Accessor#toArray */ public Object toArray() { return obj; } /** * TODO: fishy semantics. * @see Accessor#toArray */ public Object getStorage() { return obj; } /** * TODO: fishy semantics. * @see Accessor#toArray */ public Object toArray(Object oo, int [] origin, int [] shape) { if(oo.getClass().isAssignableFrom(componentType)) { return obj; } // TODO, numeric promotion // else, Can't convert throw new IllegalArgumentException(); } /* End Accessor */ private final Class componentType; private Object obj; }