/* * `gnu.iou' * Copyright (C) 2006 John Pritchard. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program 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 * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * 02111-1307 USA */ package gnu.iou ; /** * <p> Hash array structure maintains input order for indeces, * enumerations and arrays. </p> * * <h3>Not Synchronized</h3> * * <p> This class is not multi- thread safe, it is intended for use by * a single thread- user. External thread safety must be applied in * multi- threaded applications. </p> * * <h3>Multiple key instances</h3> * * <p> The key array may contain multiple identical keys. Dictionary * usage implies one key, array usage may imply additional * instances. </p> * * @author John Pritchard */ public class objmap extends hasharray implements frame { /** * <p> The keys and vals arrays are initialized by this * constructor, and are maintained internally as (parallel) * optimistically allocated buffers.</p> * * <p> Beware that the "keys" array is particularly sensitive as * index data. Don't modify its values directly!</p> */ protected Object[] keys ; /** * <p> The keys and vals arrays are initialized by this * constructor, and are maintained internally as (parallel) * optimistically allocated buffers.</p> * * <p> The length of keys and vals are always identical, and they * are maintained in parallel: the index into one corresponds with * the index into the other for a matching key- value pair. </p> */ protected Object[] vals ; protected objmap frame_parent; public objmap(int initial, float load){ super(initial,load); this.keys = new Object[this.table.grow]; this.vals = new Object[this.table.grow]; } public objmap(int initial){ super(initial); this.keys = new Object[this.table.grow]; this.vals = new Object[this.table.grow]; } public objmap(){ super(); this.keys = new Object[this.table.grow]; this.vals = new Object[this.table.grow]; } public void destroy(){ this.frame_parent = null; super.destroy(); } public final objmap frameGet(){ /* * (obfmap frameInit) depends on this method being final: that * the value returned here is identical to this.frame_parent */ return this.frame_parent; } public boolean frameStale(){ if (null != this.frame_parent) throw new java.lang.IllegalStateException("class use bug"); else return false;/*(no frame,- not stale) */ } public final boolean frameExists(){ return (null != this.frame_parent); } public final boolean frameExistsNot(){ return (null == this.frame_parent); } public frame frameParentGet(){ return this.frame_parent; } public boolean frameParentSet(objmap pf){ if (null == pf){ this.frame_parent = null; return true; } else if (null == this.frame_parent){ if (this == pf) throw new java.lang.IllegalStateException("cyclic frame reference identical"); else { this.frame_parent = pf; return true; } } else return false; } public void frameParentReset(objmap pf){ if (null == pf) this.frame_parent = null; else { if (this == pf) throw new java.lang.IllegalStateException("cyclic frame reference identical"); else this.frame_parent = pf; } } public Object[] keyary(){ return this._keyary(); } protected final Object[] _keyary(){ int many = this.count; if ( 0 < many){ Object[] keys = this.keys; Object[] ret = new Object[many]; System.arraycopy(keys,0,ret,0,many); return ret; } else return null; } public Object[] keyary(Class arycla){ return this._keyary(arycla); } protected final Object[] _keyary(Class arycla){ if (null == arycla) return this._keyary(); else { int many = this.count; if ( 0 < many){ Object[] keys = this.keys; Object[] ret = (Object[])java.lang.reflect.Array.newInstance(arycla,many); System.arraycopy(keys,0,ret,0,many); return ret; } else return null; } } public Object[] keyary_filter(Class arycla){ return this._keyary_filter(arycla); } protected final Object[] _keyary_filter(Class arycla){ if (null == arycla) return this._keyary(); else { int many = this.count; if ( 0 < many){ Object keys[] = this.keys, key; Object[] ret = (Object[])java.lang.reflect.Array.newInstance(arycla,many); int rc = 0; for (int cc = 0; cc < many; cc++){ key = keys[cc]; if (null != key && arycla.isAssignableFrom(key.getClass())) ret[rc++] = key; } if (1 > rc) return null; else { if (many != rc){ Object[] trunc = (Object[])java.lang.reflect.Array.newInstance(arycla,rc); System.arraycopy(ret,0,trunc,0,rc); return trunc; } else return ret; } } else return null; } } public Object[] valary(){ return this._valary(); } protected final Object[] _valary(){ int many = this.count; if ( 0 < many){ Object[] vals = this.vals; Object[] ret = new Object[many]; System.arraycopy(vals,0,ret,0,many); return ret; } else return null; } public Object[] valary(Class arycla){ return this._valary(arycla); } protected final Object[] _valary(Class arycla){ if (null == arycla) return this._valary(); else { int many = this.count; if ( 0 < many){ Object[] vals = this.vals; Object[] ret = (Object[])java.lang.reflect.Array.newInstance(arycla,many); System.arraycopy(vals,0,ret,0,many); return ret; } else return null; } } public Object[] valary_filter(Class arycla){ return this._valary_filter(arycla); } protected final Object[] _valary_filter(Class arycla){ if (null == arycla) return this._valary(); else { int many = this.count; if ( 0 < many){ Object vals[] = this.vals, val; Object[] ret = (Object[])java.lang.reflect.Array.newInstance(arycla,many); int rc = 0; for (int cc = 0; cc < many; cc++){ val = vals[cc]; if (null != val && arycla.isAssignableFrom(val.getClass())) ret[rc++] = val; } if (1 > rc) return null; else { if (many != rc){ Object[] trunc = (Object[])java.lang.reflect.Array.newInstance(arycla,rc); System.arraycopy(ret,0,trunc,0,rc); return trunc; } else return ret; } } else return null; } } public Object lastKey(){ return this._lastKey(); } protected final Object _lastKey(){ int idx = (this.count-1); if (-1 < idx) return this.keys[idx]; else return null; } public Object lastValue(){ return this._lastValue(); } protected final Object _lastValue(){ int idx = (this.count-1); if (-1 < idx) return this.vals[idx]; else return null; } public void lastValue( Object val){ this._lastValue(val); } protected final void _lastValue( Object val){ int idx = (this.count-1); if (-1 < idx) this.vals[idx] = val; } /** * Return an ordered enumeration of keys. */ public java.util.Enumeration keys(){ return this._keys(); } protected final java.util.Enumeration _keys(){ return new Enumerator1(this.keys, this.count); } public java.util.Enumeration elements(){ return this._elements(); } protected final java.util.Enumeration _elements(){ return new Enumerator1(this.vals, this.count); } public boolean containsValue(Object value){ return this._contains(value); } public boolean _containsValue(Object value){ return this._contains(value); } public boolean contains(Object value){ return this._contains(value); } protected final boolean _contains(Object value){ if (value == null) return false; else { Object sval, vals[] = this.vals; for (int ti = (this.count-1) ; 0 <= ti; ti--){ sval = vals[ti]; if (null != sval && (value == sval || sval.equals(value))){ return true; } } return false; } } public boolean containsKey(Object key){ return this._containsKey(key); } protected final boolean _containsKey(Object key){ return (null != this._lookup(key)); } public int indexOf(Object key){ return this._indexOf(key); } public int[] indexOfList(Object key){ return this._indexOfList(key); } protected final int _indexOf(Object key){ Index.Entry e = this._lookup(key); if (null == e) return -1; else return e.aryix; } protected final int[] _indexOfList(Object key){ Index.Entry[] list = this._lookup_list(key); if (null == list) return null; else { int len = list.length; int[] re = new int[len]; for (int idx = 0; idx < len; idx++) re[idx] = list[idx].aryix; return re; } } public int indexOf( Object key, int fromIdx){ return this._indexOf(key,fromIdx); } protected final int _indexOf( Object key, int fromIdx){ if (null == key) return -1; else { int[] list = this._indexOfList(key); if (null == list) return -1; else { int len = list.length; for (int idx = 0, re; idx < len; idx++){ re = list[idx]; if (fromIdx <= re) return re; } return -1; } } } public int lastIndexOf( Object key){ return this._lastIndexOf(key); } protected final int _lastIndexOf( Object key){ if (null == key) return -1; else return this._lastIndexOf(key,(this.count-1)); } public int lastIndexOf( Object key, int fromIdx){ return this._lastIndexOf(key,fromIdx); } protected final int _lastIndexOf( Object key, int fromIdx){ if (null == key) return -1; else { int[] list = this._indexOfList(key); if (null == list) return -1; else { int len = list.length; for (int idx = (len-1), re; -1 < idx; idx--){ re = list[idx]; if (fromIdx >= re) return re; } return -1; } } } public int indexOfValue( Object val){ return this._indexOfValue(val,0); } public int indexOfValue( Object val, int fromIdx){ return this._indexOfValue(val,fromIdx); } protected final int _indexOfValue( Object val, int fromIdx){ if (null == val) return -1; else { int many = this.count; Object vals[] = this.vals; if (-1 < fromIdx && fromIdx < many){ for ( int idx = fromIdx; idx < many; idx++){ if (val == vals[idx]) return idx; } return -1; } else return -1; } } public int lastIndexOfValue( Object val){ return this._lastIndexOfValue(val,(this.count-1)); } public int lastIndexOfValue( Object val, int fromIdx){ return this._lastIndexOfValue(val,fromIdx); } protected final int _lastIndexOfValue( Object val, int fromIdx){ if (null == val) return -1; else { int many = this.count; Object vals[] = this.vals; if (-1 < fromIdx && fromIdx < many){ for ( int idx = fromIdx; -1 < idx; idx--){ if (val == vals[idx]) return idx; } return -1; } else return -1; } } public int indexOfValueClass( Class sup){ return this._indexOfValueClass(sup,-1); } public int indexOfValueClass( Class sup, int from){ return this._indexOfValueClass(sup,from); } protected final int _indexOfValueClass( Class sup, int from){ int count = this.count; Object vals[] = this.vals, val; if (null != sup && from < count){ if (0 > from) from = 0; for (int idx = from; idx < count; idx++){ val = vals[idx]; if (null != val && sup.isAssignableFrom(val.getClass())) return idx; } } return -1; } public int lastIndexOfValueClass( Class sup){ return this._lastIndexOfValueClass(sup,Integer.MAX_VALUE); } public int lastIndexOfValueClass( Class sup, int from){ return this._lastIndexOfValueClass(sup,from); } protected final int _lastIndexOfValueClass( Class sup, int from){ int count = this.count; Object vals[] = this.vals, val; if (null != sup && -1 < from){ if (from >= count) from = (count-1); for (int idx = from; -1 < idx; idx--){ val = vals[idx]; if (null != val && sup.isAssignableFrom(val.getClass())) return idx; } } return -1; } public Object get(Object key){ return this._get(key); } protected final Object _get(Object key){ int idx = this._indexOf(key); if (-1 < idx && idx < this.count) return this.vals[idx]; else return null; } public Object[] list(Object key){ return this._list(key,null); } public Object[] list(Object key, Class comp){ return this._list(key,comp); } protected Object[] _list(Object key, Class comp){ int[] idxl = this._indexOfList(key); if (null == idxl) return null; else { int len = idxl.length; Object[] list; if (null == comp) list = new Object[len]; else list = (Object[])java.lang.reflect.Array.newInstance(comp,len); for (int lidx = 0, vidx; lidx < len; lidx++){ vidx = idxl[lidx]; list[lidx] = this.vals[vidx]; } return list; } } public Object keyO(int idx){ return this._key(idx); } public Object key(int idx){ return this._key(idx); } protected final Object _key(int idx){ if (-1 < idx && idx < this.count) return this.keys[idx]; else return null; } public long keyL(int idx){ throw new java.lang.UnsupportedOperationException(); } public Object value(int idx){ return this._value(idx); } protected final Object _value(int idx){ if (-1 < idx && idx < this.count) return this.vals[idx]; else return null; } /** * @param idx Key- value input- order index * @param value Replace existing value with this value * @return Replaced argument value, or null for bad index. (Of * course, a null argument produces a null return value). */ public Object value(int idx, Object value){ return this._value(idx,value); } protected final Object _value(int idx, Object value){ if (-1 < idx && idx < this.count) return (this.vals[idx] = value); else return null; } /** * Replace the keyed value */ public Object put(Object key, Object value){ return this._put(key,value); } protected final Object _put(Object key, Object value){ Index.Entry ent = this.table.store(this,key); int aryix = ent.aryix; if (Index.Entry.XINIT == aryix){ ent.aryix = this._vadd_(key,value); return null;/*(new)*/ } else { Object old = this.vals[aryix]; this.vals[aryix] = value; return old; } } /** * Add a potentially duplicate key. It enters the index (get- put * "key" interface) when it is unique, or as a duplicate when the * key (former) is removed. */ public int add( Object key, Object val){ return this._add(key,val); } protected final int _add( Object key, Object val){ if (null == key) return -1; else { Index.Entry ent = this.table.add(this,key); int aryix = ent.aryix; if (Index.Entry.XINIT == aryix){ ent.aryix = this._vadd_(key,val); return ent.aryix; } else { Object old = this.vals[aryix]; this.vals[aryix] = val; return aryix; } } } /** * <p> Insert the argument pair. If the key has been indexed * before, the new key is inserted into the index before it.</p> */ public int insert( int idx, Object key, Object val){ return this._insert(idx,key,val); } protected final int _insert( int idx, Object key, Object val){ if (null == key || null == val) return -1; else if (0 > idx) return this.add(key,val); else { Object[] keys = this.keys; Object[] vals = this.vals; int len = keys.length; Object[] kcopier = new Object[len+1];// simple aglo: always grow by one Object[] vcopier = new Object[len+1];// if ( 0 == idx){ System.arraycopy(keys,0,kcopier,1,len); System.arraycopy(vals,0,vcopier,1,len); kcopier[idx] = key; vcopier[idx] = val; } else if (idx == (len-1)){ System.arraycopy(keys,0,kcopier,0,len); System.arraycopy(vals,0,vcopier,0,len); kcopier[idx] = key; vcopier[idx] = val; } else { System.arraycopy(keys,0,kcopier,0,idx); System.arraycopy(vals,0,vcopier,0,idx); System.arraycopy(keys,idx,kcopier,idx+1,(len-idx));//copied (many=idx) above System.arraycopy(vals,idx,vcopier,idx+1,(len-idx)); kcopier[idx] = key; vcopier[idx] = val; } this.keys = kcopier; this.vals = vcopier; this.count += 1; Index.Entry ent = this.table.insert(this,idx,key); if (Index.Entry.XINIT == ent.aryix){ ent.aryix = idx; return idx; } else throw new IllegalStateException("BBBUGGGG"); } } /** * <p> Replace the key- value pair at key- value index 'idx' with * the argument pair.</p> */ public int replace( int idx, Object nkey, Object nval){ return this._replace(idx,nkey,nval); } protected final int _replace( int idx, Object nkey, Object nval){ if (null == nkey || null == nval) return -1; else if (0 > idx || idx >= this.count) return this.add(nkey,nval); else { Object okey = this.keys[idx]; if (okey.equals(nkey)){ this.vals[idx] = nval; return idx; } else { Index.Entry ent = this.table.replace(this,idx,nkey,okey); ent.aryix = idx; this.keys[idx] = nkey; this.vals[idx] = nval; return idx; } } } /** * <p> Append new key- value pair. If the key has been indexed * before, the new key is appended into the index after it. </p> */ public int append( Object nkey, Object nval){ return this._append(nkey,nval); } protected final int _append( Object nkey, Object nval){ if (null == nkey || null == nval) return -1; else { int idx = this._indexOf(nkey); if (0 > idx) return this.add(nkey,nval); else { idx = this._vadd_(nkey,nval); // Index.Entry ent = this.table.append(this,nkey); ent.aryix = idx; return idx; } } } /** * Add to data vectors, no index activity. Manage optimistic * vectors. */ protected final int _vadd_ ( Object key, Object val){ int idx = this.count, len = this.keys.length; if ( idx >= (len-1)){ // grow rate int grow = (len/3); if (this.table.grow > grow) grow = this.table.grow; // int nlen = len+(grow); // grow keys Object[] k_copier = new Object[nlen]; System.arraycopy(keys,0,k_copier,0,len); keys = k_copier; // grow vals Object[] v_copier = new Object[nlen]; System.arraycopy(vals,0,v_copier,0,len); vals = v_copier; } this.keys[idx] = key; this.vals[idx] = val; this.count += 1; return idx; } /** * Remove element with known index. */ public Object remove( int idx){ return this._remove(idx); } protected final Object _remove( int idx){ if (0 > idx) return null; else { Object key = this.keys[idx]; int kidx = this._indexOf(key); if ( kidx == idx){ /* * (this.keys[idx]) is the first indexed key */ return this._remove(key); } else { if (-1 < kidx) /* * (this.keys[idx]) is not the first indexed key */ this.table.remove(this,idx); Object old = this.vals[idx]; shift(this.keys,idx); shift(this.vals,idx); this.count--; return old; } } } /** * Remove key and value, index any latter identical key, truncate * data arrays (keys and vals), scan index table and decrement * pointer indeces for truncated data arrays. */ public Object remove( Object key){ return this._remove(key); } protected final Object _remove( Object key){ if (null == key) return null; else { Index.Entry dropped = this.table.remove(this,key); if (null != dropped){ int aryix = dropped.aryix; if (-1 < aryix){ Object keys[] = this.keys; Object vals[] = this.vals; Object ret = vals[aryix]; keys[aryix] = null; vals[aryix] = null; shift(keys,aryix); shift(vals,aryix); this.count--; return ret; } } return null; } } public void clear(){ this._clear(); } protected final void _clear(){ this.table.clear(this); Object[] keys = this.keys, vals = this.vals; for (int index = 0, count = this.count; index < count; index++){ keys[index] = null; vals[index] = null; } this.count = 0; } public final objmap cloneObjmap(){ objmap t = (objmap)super.cloneHasharray(); t.keys = (Object[])this.keys.clone(); t.vals = (Object[])this.vals.clone(); return t; } }