// $Id: ConcreteIndexMap.java,v 1.3 2002-05-29 20:32:38 steve 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; // used by ZZMap /** * Base class which provides framework for implementations of * IndexMap. This class contains two instances of the inner class ZZMap, * which are used to implement the two transformations required by IndexMap. * <p> * This class also supports a functional composition framework via * the link() initializer. * <p> * All methods except contructors are final. * Specialization in subclasses occurs by subclassing * the ZZMap inner class. * Subclasses provide different ZZMaps during construction. * <p> * This specialization strategy results in an implementation oddity. * When instances of a subclass of this are being constructed, * this class's constructor (as super(...)) must complete before * instances of the subclass inner class may be created. * "Can't reference this before the superclass constructor * has been called." So, rather that initializing the ZZMap * members contained by this in the constructors, we provide * init() and link() members functions. One or the other of * these should be called by every subclass constructor. * * @author $Author: steve $ * @version $Revision: 1.3 $ $Date: 2002-05-29 20:32:38 $ */ public class ConcreteIndexMap implements IndexMap { /** * An Map of int by int key. (Z is the math symbol for integers). * A Map maps keys to values. * A Map cannot contain duplicate keys; * each key can map to at most one value. * For this implementation, the keys are restricted to non-negative * integers, and we only use non-negative integers as values. * <p> * A ZZMap is like a readonly 1-d array of int. * The <code>size()</code> method returns the array length. * The <code>get(int ii)</code> method returns the int stored at * position <code>ii</code>; * <p> * This class also supports a functional composition framework via * the setPrev() method. The implementation of get(int) and size() * provided here is simply the identity composed with whatever. * Subclasses will override this functionality. * */ protected class ZZMap { /** */ protected ZZMap() { rebind((int []) null); } /** * Construct a ZZMap form the functional composition * of the new Map with another. * rebind(int [] range) calls prev.rebind(range), * get(int key) is composed as get(prev.get(key)) * @param prev ZZMap this is composed with. */ protected ZZMap(ZZMap prev) { setPrev(prev); } /** * Returns the value to which this Map maps the specified key. * If you think of this as a 1-d array of int, then * ia.get(ii) is like ia[ii]. * @param key int * @return int value */ synchronized int get(int key) { if(prev_ instanceof ZZMap) return ((ZZMap)prev_).get(key); // else try { return Array.getInt(prev_, key); } catch (RuntimeException ex) { /* * rebind() was not called (ex isa NullPointerException) * or called with a value which doesn't make sense for * the key (ex isa ArrayIndexOutOfBoundsException) */ throw new IllegalArgumentException("Improper Binding"); } } /** * Rebind (redefine) the range of get(int) * @param range int array which defines the get(int) * member. */ synchronized final void rebind(int [] range) { if(prev_ instanceof ZZMap) { ((ZZMap)prev_).rebind(range); return; } // else prev_ = range; } /** * Returns the number of key-value mappings in this Map. * If you think of this as a 1-d array of int, then * ia.size() is like ia.length. * @return int size */ synchronized int size() { if(prev_ instanceof ZZMap) return ((ZZMap)prev_).size(); // else try { return Array.getLength(prev_); } catch (NullPointerException npe) { return 0; } } /** * Form the functional composition * of this Map with another. * rebind(int [] range) calls prev.rebind(range), * get(int key) is composed as get(prev.get(key)) * @param prev ZZMap this is composed with. */ synchronized final void setPrev(ZZMap prev) { if(prev_ instanceof ZZMap) { ((ZZMap)prev_).setPrev(prev); return; } // else prev_ = prev; } /** * The range of the get(int) function. * Either an array of ints or another ZZMap. */ private Object prev_; public String toString() { StringBuffer buf = new StringBuffer( super.toString() ); final int sz = size(); buf.append(" ["); buf.append(sz); buf.append("]"); buf.append(" {"); final int last = sz -1; for(int ii = 0; ii < sz ; ii++) { buf.append(get(ii)); if(ii == last) break; // normal loop exit buf.append(", "); } buf.append("}"); return buf.toString(); } } /* End Inner Class ZZMap */ /** * Only constructor is protected. * This is a base class, clients only * create instances of the subclasses. */ protected ConcreteIndexMap() {} /** * Called by subclass constructors to initialize. * Used for standalone or "leaf" instances. * See "implementation oddity" above. * @param iMap ZZMap defining the forward transform. * @param lengthsMap ZZMap defining the reverse transform. */ protected final void init(ZZMap iMap, ZZMap lengthsMap) { iMap_ = iMap; lengthsMap_ = lengthsMap; } /** * Called by subclass constructors to initialize. * Used for standalone or "leaf" instances when * the reverse transformation (lengthsMap) is the * identity. * See "implementation oddity" above. * @param iMap ZZMap defining the forward transform. */ protected final void init(ZZMap iMap) { init(iMap, new ZZMap()); } /** * Called by subclass constructors to initialize. * Used when nested constructors are used to form * functional composition of IndexMaps. * See "implementation oddity" above. * @param prev ConcreteIndexMap this is composed with. * @param iMap ZZMap defining the forward transform. * @param lengthsMap ZZMap defining the reverse transform. */ protected final void link(ConcreteIndexMap prev, ZZMap iMap, ZZMap lengthsMap) { iMap_ = prev.iMap_; lengthsMap_ = lengthsMap; iMap_.setPrev(iMap); lengthsMap_.setPrev(prev.lengthsMap_); } /** * Called by subclass constructors to initialize. * Used when nested constructors are used to form * functional composition of IndexMaps. * This form is used when the reverse transform (lengthsMap) * is the identity * See "implementation oddity" above. * @param prev ConcreteIndexMap this is composed with. * @param iMap ZZMap defining the forward transform. */ protected final void link(ConcreteIndexMap prev, ZZMap iMap) { link(prev, iMap, new ZZMap()); // TODO: can we use prev.lengthsMap_? } /* Begin IndexMap impl */ public final synchronized int getOutputLength() { return iMap_.size(); } public final synchronized void setInput(int [] input) { iMap_.rebind(input); } public final synchronized int [] getTransformed(int [] output) { final int sz = getOutputLength(); for(int ii = 0; ii < sz; ii++) output[ii] = iMap_.get(ii); return output; } public final synchronized int [] transform(int [] output, int [] input) { setInput(input); return getTransformed(output); } public final synchronized int getRank() { return lengthsMap_.size(); } public final synchronized void setLengths(int [] lengths) { lengthsMap_.rebind(lengths); if(getRank() < 0) throw new IllegalArgumentException("rank < 0"); } public final synchronized int [] getLengths(int [] output) { final int sz = lengthsMap_.size(); for(int ii = 0; ii < sz; ii++) output[ii] = lengthsMap_.get(ii); return output; } /* End IndexMap Impl */ public String toString() { StringBuffer buf = new StringBuffer( super.toString() + "\n\t" ); buf.append(iMap_.toString() + "\n\t"); buf.append(lengthsMap_.toString()); return buf.toString(); } /* * Implementation note. See "implementation oddity" above. * "Can't reference this before the superclass constructor * has been called." * ==> Can't be final. */ /** * Supports the forward tranform. */ protected /* final */ ZZMap iMap_; /** * Supports the reverse tranform. */ protected /* final */ ZZMap lengthsMap_; /* Begin Test */ private static void testZZMap() { System.out.println("Testing Inner Class ZZMap"); ConcreteIndexMap im = new ConcreteIndexMap(); System.out.println("Unbound:"); ZZMap zm = im. new ZZMap(); System.out.println("\t" + zm); ZZMap next = im. new ZZMap(zm); System.out.println("\t" + next); System.out.println("Bernoulli"); int [] ia = {1, 1, 2, 3, 5, 8, 13}; zm.rebind(ia); System.out.println("\t" + zm); System.out.println("\t" + next); System.out.println("Rebound"); int [] ia2 = {1, 2, 4, 8}; next.rebind(ia2); System.out.println("\t" + zm); System.out.println("\t" + next); System.out.println("End ZZMap Test"); } private static void testInit() { System.out.println("Testing init() and link() "); ConcreteIndexMap im = new ConcreteIndexMap(); im.init(im. new ZZMap(), im. new ZZMap()); System.out.println("Unbound: " + im); ConcreteIndexMap next = new ConcreteIndexMap(); next.link(im, next. new ZZMap(), next .new ZZMap()); System.out.println("Next Unbound: " + next); int [] ia = {1, 1, 2, 3, 5, 8, 13}; int [] ia2 = {1, 2, 4, 8}; next.setInput(ia); next.setLengths(ia2); System.out.println("forward : " + im); System.out.println("Next forward : " + next); next.setInput(ia2); next.setLengths(ia); System.out.println("reversed: " + im); System.out.println("Next reversed: " + next); System.out.println("End init(), link() test"); } public static void main(String[] args) { testZZMap(); testInit(); // TODO more complete } /* Test output java ucar.multiarray.ConcreteIndexMap Testing Inner Class ZZMap Unbound: ucar.multiarray.ConcreteIndexMap$ZZMap@8ce7bc [0] {} ucar.multiarray.ConcreteIndexMap$ZZMap@8ce7ec [0] {} Bernoulli ucar.multiarray.ConcreteIndexMap$ZZMap@8ce7bc [7] {1, 1, 2, 3, 5, 8, 13} ucar.multiarray.ConcreteIndexMap$ZZMap@8ce7ec [7] {1, 1, 2, 3, 5, 8, 13} Rebound ucar.multiarray.ConcreteIndexMap$ZZMap@8ce7bc [4] {1, 2, 4, 8} ucar.multiarray.ConcreteIndexMap$ZZMap@8ce7ec [4] {1, 2, 4, 8} End ZZMap Test Testing init() and link() Unbound: ucar.multiarray.ConcreteIndexMap@8ce890 ucar.multiarray.ConcreteIndexMap$ZZMap@8ce88f [0] {} ucar.multiarray.ConcreteIndexMap$ZZMap@8ce88e [0] {} Next Unbound: ucar.multiarray.ConcreteIndexMap@8ce8ac ucar.multiarray.ConcreteIndexMap$ZZMap@8ce88f [0] {} ucar.multiarray.ConcreteIndexMap$ZZMap@8ce8aa [0] {} forward : ucar.multiarray.ConcreteIndexMap@8ce890 ucar.multiarray.ConcreteIndexMap$ZZMap@8ce88f [7] {1, 1, 2, 3, 5, 8, 13} ucar.multiarray.ConcreteIndexMap$ZZMap@8ce88e [4] {1, 2, 4, 8} Next forward : ucar.multiarray.ConcreteIndexMap@8ce8ac ucar.multiarray.ConcreteIndexMap$ZZMap@8ce88f [7] {1, 1, 2, 3, 5, 8, 13} ucar.multiarray.ConcreteIndexMap$ZZMap@8ce8aa [4] {1, 2, 4, 8} reversed: ucar.multiarray.ConcreteIndexMap@8ce890 ucar.multiarray.ConcreteIndexMap$ZZMap@8ce88f [4] {1, 2, 4, 8} ucar.multiarray.ConcreteIndexMap$ZZMap@8ce88e [7] {1, 1, 2, 3, 5, 8, 13} Next reversed: ucar.multiarray.ConcreteIndexMap@8ce8ac ucar.multiarray.ConcreteIndexMap$ZZMap@8ce88f [4] {1, 2, 4, 8} ucar.multiarray.ConcreteIndexMap$ZZMap@8ce8aa [7] {1, 1, 2, 3, 5, 8, 13} End init(), link() test */ /* End Test */ }