javax.media.j3d.IndexedUnorderSet Maven / Gradle / Ivy
/*
* Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
package javax.media.j3d;
/**
* A strongly type indexed unorder set.
* All operations remove(IndexedObject, ListType), add(IndexedObject, ListType),
* contains(IndexedObject, ListType) etc. take O(1) time.
* The class is designed to optimize speed. So many reductance
* procedures call and range check as found in ArrayList are
* removed.
*
*
* Use the following code to iterate through an array.
*
*
* IndexedUnorderSet IUset =
* new IndexedUnorderSet(YourClass.class, listType);
* // add element here
*
* YourClass[] arr = (YourClass []) IUset.toArray();
* int size = IUset.arraySize();
* for (int i=0; i < size; i++) {
* YourClass obj = arr[i];
* ....
* }
*
*
*
* Note:
*
* 1) The array return is a copied of internal array.
* 2) Don't use arr.length , use IUset.arraySize();
* 3) IndexedObject contains an array of listIndex, the number of
* array elements depends on the number of different types of
* IndexedUnorderSet that use it.
* 4) No need to do casting for individual element as in ArrayList.
* 5) IndexedUnorderSet is thread safe.
* 6) Object implement this interface MUST initialize the index to -1.
*
*
*
* Limitation:
*
* 1) Order of IndexedObject in list is not important
* 2) Can't modify the clone() copy.
* 3) IndexedObject can't be null
*
*/
class IndexedUnorderSet implements Cloneable, java.io.Serializable {
// XXXX: set to false when release
final static boolean debug = false;
/**
* The array buffer into which the elements of the ArrayList are stored.
* The capacity of the ArrayList is the length of this array buffer.
*
* It is non-private to enable compiler do inlining for get(),
* set(), remove() when -O flag turn on.
*/
transient IndexedObject elementData[];
/**
* Clone copy of elementData return by toArray(true);
*/
transient Object cloneData[];
// size of the above clone objec.
transient int cloneSize;
transient boolean isDirty = true;
/**
* Component Type of individual array element entry
*/
Class componentType;
/**
* The size of the ArrayList (the number of elements it contains).
*
* We make it non-private to enable compiler do inlining for
* getSize() when -O flag turn on.
*/
int size;
int listType;
// Current VirtualUniverse using this structure
VirtualUniverse univ;
/**
* Constructs an empty list with the specified initial capacity.
* and the class data Type
*
* @param initialCapacity the initial capacity of the list.
* @param componentType class type of element in the list.
*/
IndexedUnorderSet(int initialCapacity, Class componentType,
int listType, VirtualUniverse univ) {
this.componentType = componentType;
this.elementData = (IndexedObject[])java.lang.reflect.Array.newInstance(
componentType, initialCapacity);
this.listType = listType;
this.univ = univ;
}
/**
* Constructs an empty list.
* @param componentType class type of element in the list.
*/
IndexedUnorderSet(Class componentType, int listType,
VirtualUniverse univ) {
this(10, componentType, listType, univ);
}
/**
* Constructs an empty list with the specified initial capacity.
*
* @param initialCapacity the initial capacity of the list.
*/
IndexedUnorderSet(int initialCapacity, int listType,
VirtualUniverse univ) {
this(initialCapacity, IndexedObject.class, listType, univ);
}
/**
* Constructs an empty list.
* @param listType default to Object.
*/
IndexedUnorderSet(int listType, VirtualUniverse univ) {
this(10, IndexedObject.class, listType, univ);
}
/**
* Initialize all indexes to -1
*/
final static void init(IndexedObject obj, int len) {
obj.listIdx = new int[3][];
obj.listIdx[0] = new int[len];
obj.listIdx[1] = new int[len];
obj.listIdx[2] = new int[1];
for (int i=0; i < len; i++) {
obj.listIdx[0][i] = -1;
obj.listIdx[1][i] = -1;
}
// Just want to set both RenderMolecule idx
// and BehaviorRetained idx to 0 by default
// It is OK without the following lines
if (obj instanceof SceneGraphObjectRetained) {
// setlive() will change this back to 0
obj.listIdx[2][0] = 1;
} else {
obj.listIdx[2][0] = 0;
}
}
/**
* Returns the number of elements in this list.
*
* @return the number of elements in this list.
*/
final int size() {
return size;
}
/**
* Returns the size of entry use in toArray() number of elements
* in this list.
*
* @return the number of elements in this list.
*/
final int arraySize() {
return cloneSize;
}
/**
* Tests if this list has no elements.
*
* @return true if this list has no elements;
* false otherwise.
*/
final boolean isEmpty() {
return size == 0;
}
/**
* Returns true if this list contains the specified element.
*
* @param o element whose presence in this List is to be tested.
*/
synchronized final boolean contains(IndexedObject o) {
return (o.listIdx[o.getIdxUsed(univ)][listType] >= 0);
}
/**
* Searches for the last occurence of the given argument, testing
* for equality using the equals method.
*
* @param o an object.
* @return the index of the first occurrence of the argument in this
* list; returns -1 if the object is not found.
* @see Object#equals(Object)
*/
synchronized final int indexOf(IndexedObject o) {
return o.listIdx[o.getIdxUsed(univ)][listType];
}
/**
* Returns a shallow copy of this ArrayList instance. (The
* elements themselves are not copied.)
*
* @return a clone of this ArrayList instance.
*/
@Override
synchronized protected final Object clone() {
try {
IndexedUnorderSet v = (IndexedUnorderSet)super.clone();
v.elementData = (IndexedObject[])java.lang.reflect.Array.newInstance(
componentType, size);
System.arraycopy(elementData, 0, v.elementData, 0, size);
isDirty = true; // can't use the old cloneData reference
return v;
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError();
}
}
/**
* Returns an array containing all of the elements in this list.
* The size of the array may longer than the actual size. Use
* arraySize() to retrieve the size.
* The array return is a copied of internal array. if copy
* is true.
*
* @return an array containing all of the elements in this list
*/
synchronized final Object[] toArray(boolean copy) {
if (copy) {
if (isDirty) {
if ((cloneData == null) || cloneData.length < size) {
cloneData = (Object[])java.lang.reflect.Array.newInstance(
componentType, size);
}
System.arraycopy(elementData, 0, cloneData, 0, size);
cloneSize = size;
isDirty = false;
}
return cloneData;
} else {
cloneSize = size;
return elementData;
}
}
/**
* Returns an array containing all of the elements in this list.
* The size of the array may longer than the actual size. Use
* arraySize() to retrieve the size.
* The array return is a copied of internal array. So another
* thread can continue add/delete the current list. However,
* it should be noticed that two call to toArray() may return
* the same copy.
*
* @return an array containing all of the elements in this list
*/
synchronized final Object[] toArray() {
return toArray(true);
}
/**
* Returns an array containing elements starting from startElement
* all of the elements in this list. A new array of exact size
* is always allocated.
*
* @param startElement starting element to copy
*
* @return an array containing elements starting from
* startElement, null if element not found.
*
*/
synchronized final Object[] toArray(IndexedObject startElement) {
int idx = indexOf(startElement);
if (idx < 0) {
return (Object[])java.lang.reflect.Array.newInstance(componentType, 0);
}
int s = size - idx;
Object data[] = (Object[])java.lang.reflect.Array.newInstance(componentType, s);
System.arraycopy(elementData, idx, data, 0, s);
return data;
}
/**
* Trims the capacity of this ArrayList instance to be the
* list's current size. An application can use this operation to minimize
* the storage of an ArrayList instance.
*/
synchronized final void trimToSize() {
if (elementData.length > size) {
Object oldData[] = elementData;
elementData = (IndexedObject[])java.lang.reflect.Array.newInstance(
componentType,
size);
System.arraycopy(oldData, 0, elementData, 0, size);
}
}
// Positional Access Operations
/**
* Returns the element at the specified position in this list.
*
* @param index index of element to return.
* @return the element at the specified position in this list.
* @throws IndexOutOfBoundsException if index is out of range (index
* < 0 || index >= size()).
*/
synchronized final Object get(int index) {
return elementData[index];
}
/**
* Replaces the element at the specified position in this list with
* the specified element.
*
* @param index index of element to replace.
* @param o element to be stored at the specified position.
* @return the element previously at the specified position.
* @throws IndexOutOfBoundsException if index out of range
* (index < 0 || index >= size()).
*/
synchronized final void set(int index, IndexedObject o) {
IndexedObject oldElm = elementData[index];
if (oldElm != null) {
oldElm.listIdx[oldElm.getIdxUsed(univ)][listType] = -1;
}
elementData[index] = o;
int univIdx = o.getIdxUsed(univ);
if (debug) {
if (o.listIdx[univIdx][listType] != -1) {
System.err.println("Illegal use of UnorderIndexedList idx in set " +
o.listIdx[univIdx][listType]);
Thread.dumpStack();
}
}
o.listIdx[univIdx][listType] = index;
isDirty = true;
}
/**
* Appends the specified element to the end of this list.
* It is the user responsible to ensure that the element add is of
* the same type as array componentType.
*
* @param o element to be appended to this list.
*/
synchronized final void add(IndexedObject o) {
if (elementData.length == size) {
IndexedObject oldData[] = elementData;
elementData = (IndexedObject[])java.lang.reflect.Array.newInstance(
componentType,
(size << 1));
System.arraycopy(oldData, 0, elementData, 0, size);
}
int univIdx = o.getIdxUsed(univ);
if (debug) {
int idx = o.listIdx[univIdx][listType];
if (idx >= 0) {
if (elementData[idx] != o) {
System.err.println("Illegal use of UnorderIndexedList idx in add " + idx);
Thread.dumpStack();
}
}
}
int idx = size++;
elementData[idx] = o;
o.listIdx[univIdx][listType] = idx;
isDirty = true;
}
/**
* Removes the element at the specified position in this list.
* Replace the removed element by the last one.
*
* @param index the index of the element to removed.
* @throws IndexOutOfBoundsException if index out of range (index
* < 0 || index >= size()).
*/
synchronized final void remove(int index) {
IndexedObject elm = elementData[index];
int univIdx = elm.getIdxUsed(univ);
if (debug) {
if (elm.listIdx[univIdx][listType] != index) {
System.err.println("Inconsistent idx in remove, expect " + index + " actual " + elm.listIdx[univIdx][listType]);
Thread.dumpStack();
}
}
elm.listIdx[univIdx][listType] = -1;
size--;
if (index != size) {
elm = elementData[size];
elm.listIdx[univIdx][listType] = index;
elementData[index] = elm;
}
elementData[size] = null;
isDirty = true;
/*
if ((cloneData != null) && (index < cloneData.length)) {
cloneData[index] = null; // for gc
}
*/
}
/**
* Removes the element at the last position in this list.
* @return The element remove
* @throws IndexOutOfBoundsException if array is empty
*/
synchronized final Object removeLastElement() {
IndexedObject elm = elementData[--size];
elementData[size] = null;
elm.listIdx[elm.getIdxUsed(univ)][listType] = -1;
isDirty = true;
/*
if ((cloneData != null) && (size < cloneData.length)) {
cloneData[size] = null; // for gc
}
*/
return elm;
}
/**
* Removes the specified element in this list.
* Replace the removed element by the last one.
*
* @param o the element to removed.
* @return true if object remove
* @throws IndexOutOfBoundsException if index out of range (index
* < 0 || index >= size()).
*/
synchronized final boolean remove(IndexedObject o) {
int univIdx = o.getIdxUsed(univ);
int idx = o.listIdx[univIdx][listType];
if (idx >= 0) {
if (debug) {
if (o != elementData[idx]) {
System.err.println(this + " Illegal use of UnorderIndexedList in remove expect " + o + " actual " + elementData[idx] + " idx = " + idx);
Thread.dumpStack();
}
}
// Object in the container
size--;
if (idx != size) {
IndexedObject elm = elementData[size];
elementData[idx] = elm;
elm.listIdx[elm.getIdxUsed(univ)][listType] = idx;
}
elementData[size] = null;
o.listIdx[univIdx][listType] = -1;
isDirty = true;
return true;
}
return false;
}
/**
* Removes all of the elements from this list. The list will
* be empty after this call returns.
*/
synchronized final void clear() {
IndexedObject o;
for (int i = size-1; i >= 0; i--) {
o = elementData[i];
o.listIdx[o.getIdxUsed(univ)][listType] = -1;
elementData[i] = null; // Let gc do its work
}
size = 0;
isDirty = true;
}
synchronized final void clearMirror() {
if (cloneData != null) {
for (int i = cloneData.length-1; i >= 0; i--) {
// don't set index to -1 since the original
// copy is using this.
cloneData[i] = null; // Let gc do its work
}
}
cloneSize = 0;
isDirty = true;
}
final Class getComponentType() {
return componentType;
}
/*
synchronized public String toString() {
StringBuffer sb = new StringBuffer("Size = " + size + "\n[");
int len = size-1;
Object obj;
for (int i=0; i < size; i++) {
obj = elementData[i];
if (obj != null) {
sb.append(elementData[i].toString());
} else {
sb.append("NULL");
}
if (i != len) {
sb.append(", ");
}
}
sb.append("]\n");
return sb.toString();
}
*/
/**
* Save the state of the ArrayList instance to a stream (that
* is, serialize it).
*
* @serialData The length of the array backing the ArrayList
* instance is emitted (int), followed by all of its elements
* (each an Object) in the proper order.
*/
private synchronized void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException{
// Write out element count, and any hidden stuff
s.defaultWriteObject();
// Write out array length
s.writeInt(elementData.length);
// Write out all elements in the proper order.
for (int i=0; iArrayList instance from a stream (that is,
* deserialize it).
*/
private synchronized void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
// Read in size, and any hidden stuff
s.defaultReadObject();
// Read in array length and allocate array
int arrayLength = s.readInt();
elementData = (IndexedObject[])java.lang.reflect.Array.newInstance(
componentType, arrayLength);
// Read in all elements in the proper order.
for (int i=0; i