// // Tuple.java // /* VisAD system for interactive analysis and visualization of numerical data. Copyright (C) 1996 - 2017 Bill Hibbard, Curtis Rueden, Tom Rink, Dave Glowacki, Steve Emmerson, Tom Whittaker, Don Murray, and Tommy Jasmin. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 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 Library General Public License for more details. You should have received a copy of the GNU Library 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 visad; import java.rmi.RemoteException; import java.util.Vector; /** <P>Tuple is the general VisAD data class for vectors. Tuple objects are immutable in the sense that the sequence of {@link Data} objects cannot be modified; Tuple objects are mutable, however, in the sense that a contained {@link Data} object might be mutable (e.g. it might be a {@link Field} with modifiable range values).</P> */ public class Tuple extends DataImpl implements TupleIface { Data[] tupleComponents; // might be null (see Tuple(TupleType)) /** * Construct a Tuple object with missing value * @param type the TupleType */ public Tuple(TupleType type) { super(type); if (type instanceof RealTupleType && !(this instanceof RealTuple)) { throw new VisADError("must construct as RealTuple"); } } /** * Construct a Tuple object from a type and an array of Data objects * @param type the TupleType * @param datums the Data components */ public Tuple(TupleType type, Data[] datums) throws VisADException, RemoteException { this(type, datums, true); } /** * Construct a Tuple object from a type and an array of Data objects * @param type the TupleType * @param datums the Data components * @param copy if true, copy the data objects */ public Tuple(TupleType type, Data[] datums, boolean copy) throws VisADException, RemoteException { this(type, datums, copy, true); } /** * Construct a Tuple object from a type and an array of Data objects * @param type the TupleType * @param datums the Data components * @param copy if true, copy the data objects * @param checkType if true, make sure the type matches the datum types. */ public Tuple(TupleType type, Data[] datums, boolean copy, boolean checkType) throws VisADException, RemoteException { super(type); if (checkType && !checkTupleType(type, datums)) { throw new TypeException("Tuple: type does not match data"); } if (type instanceof RealTupleType && !(this instanceof RealTuple)) { throw new TypeException("must construct as RealTuple"); } int n = datums.length; tupleComponents = new Data[n]; for (int i=0; i<n; i++) { if (copy) { tupleComponents[i] = (Data) datums[i].dataClone(); } else { tupleComponents[i] = datums[i]; } if (tupleComponents[i] instanceof DataImpl) { ((DataImpl) tupleComponents[i]).setParent(this); } } } /** * Construct a Tuple object from an array of Data objects; * this constructs its MathType from the MathTypes of the * data array * * @param datums the Data components * @param copy if true, copy the data objects */ public Tuple(Data[] datums, boolean copy) throws VisADException, RemoteException { this(buildTupleType(datums), datums, copy, false); } /** * Construct a Tuple object from an array of Data objects; * this constructs its MathType from the MathTypes of the * data array * * @param datums the Data components */ public Tuple(Data[] datums) throws VisADException, RemoteException { this(buildTupleType(datums), datums, true, false); } /** * Create a Tuple from an array of Data objects. * @return a Tuple. */ public static Tuple makeTuple(Data[] datums) throws VisADException, RemoteException { return new Tuple(datums); } /** Check a TupleType for an array of Data */ static boolean checkTupleType(TupleType type, Data[] datums) throws VisADException, RemoteException { if (datums == null || type == null) return false; int n = datums.length; if (n != type.getDimension()) return false; for (int i=0; i<n; i++) { if (!type.getComponent(i).equals(datums[i].getType())) return false; } return true; } /** * Make a TupleType for an array of Data * @param datums array of Data objects */ public static TupleType buildTupleType(Data[] datums) throws VisADException, RemoteException { if (datums == null) { throw new TypeException("Tuple: # components must be > 0"); } int n = datums.length; if (n < 1) { throw new TypeException("Tuple: # components must be > 0"); } MathType[] types = new MathType[n]; boolean allReal = true; for (int i=0; i<n; i++) { types[i] = datums[i].getType(); if (!(types[i] instanceof RealType)) allReal = false; } if (allReal) { RealType[] real_types = new RealType[n]; for (int i=0; i<n; i++) real_types[i] = (RealType) types[i]; return new RealTupleType(real_types); } else { return new TupleType(types); } } /** * Get all the Real components from this Tuple. * @return an array of Real-s */ public Real[] getRealComponents() throws VisADException, RemoteException { if (getComponents(false) == null) return null; Vector reals = new Vector(); for (int i=0; i<getDimension(); i++) { Data comp = getComponent(i); if (comp instanceof Real) { reals.addElement(comp); } else if (comp instanceof RealTuple) { RealTuple rt = (RealTuple) comp; for (int j=0; j<rt.getDimension(); j++) { reals.addElement(rt.getComponent(j)); } } } if (reals.size() == 0) return null; Real[] realComponents = new Real[reals.size()]; for (int i=0; i<reals.size(); i++) { realComponents[i] = (Real) reals.elementAt(i); } return realComponents; } /** * Returns the components that constitute this instance. If this instance * has no components, then <code>null</code> is returned. A returned array * may be modified without affecting the behavior of this instance. * * @return The components of this instance or <code> * null</code>. */ public final Data[] getComponents() { return getComponents(true); } public static int cloneCnt = 0; /** * Returns the components that constitute this instance. If this instance * has no components, then <code>null</code> is returned. IF copy==true a returned array * may be modified without affecting the behavior of this instance. Else, the returned array is the * actual component array * @param copy if true then return a copy of the tuple array. Else return the actual array * * @return The components of this instance or <code> * null</code>. */ public Data[] getComponents(boolean copy) { if(!copy) return tupleComponents; else if(tupleComponents == null) return null; else { cloneCnt++; return (Data[])tupleComponents.clone(); } } /** * Check if there is no Data in this Tuple. * @return true if there is no data. */ public boolean isMissing() { //jeffmc: 11-25-09: This method used to just call getComponents()==null which resulted in a clone //of the tuple array every time. // return (getComponents()== null); //Instead pass in copy==false return (getComponents(false)== null); } /** * Return number of components in this Tuple. * @return the number of components. */ public int getDimension() { if (tupleComponents != null) { return tupleComponents.length; } else { return ((TupleType) getType()).getDimension(); } } /** * Returns a component of this instance. If this instance has no components, * then an object of the appropriate {@link MathType} is created that has * no data and is returned. A returned component is the actual component of * this instance and is not a copy or clone. * * @param i The zero-based index of the coponent to * return. * @return The <code>i</code>-th component of this * instance. * @throws VisADException if this instance has no components and * couldn't create one with no data. * @throws RemoteException if a Java RMI failure occurs. * @throws TypeException if the index is less than zero or greater than * <code>getDimension()-1</code>. */ public Data getComponent(int i) throws VisADException, RemoteException { if (isMissing()) { return ((TupleType) Type).getComponent(i).missingData(); } else if (0 <= i && i < getDimension()) { return (Data) tupleComponents[i]; } else { throw new TypeException("Tuple: component index out of range: " + i); } } /*- TDR May 1998 public Data binary(Data data, int op, int sampling_mode, int error_mode) throws VisADException, RemoteException { */ public Data binary(Data data, int op, MathType new_type, int sampling_mode, int error_mode ) throws VisADException, RemoteException { /* BINARY - TDR May 28, 1998 */ if ( new_type == null ) { throw new TypeException("binary: new_type may not be null" ); } MathType m_type; /* BINARY - end */ if (data instanceof RealTuple) { throw new TypeException("Tuple.binary: types don't match"); } else if (data instanceof Tuple) { if (!Type.equalsExceptName(data.getType())) { throw new TypeException("Tuple.binary: types don't match"); } /* BINARY - TDR May 28, 1998 */ if ( !Type.equalsExceptName(new_type) ) { throw new TypeException(); } /* BINARY - end */ if (isMissing() || data.isMissing()) { return new Tuple((TupleType) new_type); } int dim = getDimension(); Data[] datums = new Data[dim]; for (int j=0; j<dim; j++) { /* BINARY - TDR June 2, 1998 */ m_type = ((TupleType)new_type).getComponent(j); //System.out.println("m_type = " + m_type); /* end */ datums[j] = getComponent(j).binary(((Tuple) data).getComponent(j), op, m_type, sampling_mode, error_mode); } return new Tuple(datums); } else if (data instanceof Real) { /* BINARY - TDR May 28, 1998 */ if ( !Type.equalsExceptName(new_type) ) { throw new TypeException(); } /* BINARY - end */ if (isMissing() || data.isMissing()) { return new Tuple((TupleType) new_type); } int dim = getDimension(); Data[] datums = new Data[getDimension()]; for (int j=0; j<dim; j++) { /* BINARY - TDR June 2, 1998 */ m_type = ((TupleType)new_type).getComponent(j); /* end */ datums[j] = getComponent(j).binary(data, op, m_type, sampling_mode, error_mode); } return new Tuple(datums); } else if (data instanceof Text) { throw new TypeException("Tuple.binary: types don't match"); } else if (data instanceof Field) { /* BINARY - TDR May 28, 1998 return data.binary(this, invertOp(op), sampling_mode, error_mode); */ /* BINARY - TDR June 3, 1998 */ if ( !(data.getType()).equalsExceptName(new_type) ) { throw new TypeException(); } return data.binary(this, invertOp(op), new_type, sampling_mode, error_mode); /* BINARY - end */ } else { throw new TypeException("Tuple.binary"); } } /*- TDR July 1998 public Data unary(int op, int sampling_mode, int error_mode) throws VisADException, RemoteException { */ public Data unary(int op, MathType new_type, int sampling_mode, int error_mode) throws VisADException, RemoteException { if ( new_type == null ) { throw new TypeException("unary: new_type may not be null"); } if ( !Type.equalsExceptName( new_type )) { throw new TypeException("unary: new_type doesn't match return type"); } TupleType T_type = (TupleType)new_type; if (isMissing()) return new Tuple((TupleType) new_type); int dim = getDimension(); Data[] datums = new Data[dim]; for (int j=0; j<dim; j++) { datums[j] = getComponent(j).unary(op, T_type.getComponent(j), sampling_mode, error_mode); } return new Tuple(datums); } public DataShadow computeRanges(ShadowType type, DataShadow shadow) throws VisADException, RemoteException { if (isMissing()) return shadow; for (int i=0; i<getDimension(); i++) { shadow = getComponent(i).computeRanges(((ShadowTupleType) type).getComponent(i), shadow); } return shadow; } /** return a Tuple that clones this, except its ErrorEstimate-s are adjusted for sampling errors in error */ public Data adjustSamplingError(Data error, int error_mode) throws VisADException, RemoteException { if (isMissing() || error == null || error.isMissing()) return this; int n = getDimension(); Data[] newComponents = new Data[n]; for (int i=0; i<n; i++) { Data errorComponent = ((Tuple) error).getComponent(i); newComponents[i] = getComponent(i).adjustSamplingError(errorComponent, error_mode); } return new Tuple(newComponents); } /** * A wrapper around {@link #getComponent(int) getComponent} for JPython. * * @return The requested Data object. */ public Data __getitem__(int index) throws VisADException, RemoteException { return getComponent(index); } /** * A wrapper around {@link #getLength() getLength} for JPython. * * @return The number of components of the Tuple */ public int __len__() { return getDimension(); } /** * Return the number of components of the Tuple * * @return Number of components. */ public int getLength() { return getDimension(); } /** * <p>Clones this instance. The <code>clone()</code> method of each * component is invoked.</p> * * <p>This implementation throws {@link CloneNotSupportedException} if and * only if one of the components throws it.</p> * * @return A clone of this instance. * @throws CloneNotSupportedException if cloning isn't supported. */ public Object clone() throws CloneNotSupportedException { Tuple clone = (Tuple)super.clone(); if (clone.tupleComponents != null) { clone.tupleComponents = new Data[tupleComponents.length]; for (int i = 0; i < tupleComponents.length; i++) { Data comp = tupleComponents[i]; if (comp == null) { clone.tupleComponents[i] = null; } else { try { /* * Data.dataClone() is invoked because Data.clone() doesn't and * can't exist. */ clone.tupleComponents[i] = (Data)tupleComponents[i].dataClone(); } catch (RemoteException ex) { throw new RuntimeException(ex.toString()); } } } } return clone; } public String longString(String pre) throws VisADException, RemoteException { String s = pre + "Tuple\n" + pre + " Type: " + Type.toString() + "\n"; if (isMissing()) return s + " missing\n"; for (int i=0; i<getDimension(); i++) { s = s + pre + " Tuple Component " + i + ":\n" + getComponent(i).longString(pre + " "); } return s; } /** * Indicates if this Tuple is identical to an object. * * @param obj The object. * @return <code>true</code> if and only if the object is * a Tuple and both Tuple-s have identical component * sequences. */ public boolean equals(Object obj) { boolean equals; if (!(obj instanceof Tuple)) { equals = false; } else { Tuple that = (Tuple)obj; if (this == that) { equals = true; } else if (tupleComponents == null || that.tupleComponents == null) { equals = tupleComponents == that.tupleComponents; } else if (tupleComponents.length != that.tupleComponents.length) { equals = false; } else { equals = true; for (int i = 0; i < tupleComponents.length; ++i) if (!(tupleComponents[i].equals(that.tupleComponents[i]))) { equals = false; break; } } } return equals; } /** * Returns the hash code of this object. * @return The hash code of this object. */ public int hashCode() { int hashCode = 0; if (tupleComponents != null) for (int i = 0; i < tupleComponents.length; ++i) hashCode ^= tupleComponents[i].hashCode(); return hashCode; } }