diff --git a/jme3-core/src/main/java/com/jme3/util/SafeArrayList.java b/jme3-core/src/main/java/com/jme3/util/SafeArrayList.java
index 27f129f2f..a0657c753 100644
--- a/jme3-core/src/main/java/com/jme3/util/SafeArrayList.java
+++ b/jme3-core/src/main/java/com/jme3/util/SafeArrayList.java
@@ -43,7 +43,7 @@ import java.util.*;
* the list is changing.
*
* All modifications, including set() operations will cause a copy of the
- * data to be created that replaces the old version. Because this list is
+ * data to be created that replaces the old version. Because this list is
* not designed for threading concurrency it further optimizes the "many modifications"
* case by buffering them as a normal ArrayList until the next time the contents
* are accessed.
@@ -63,16 +63,16 @@ import java.util.*;
* Even after ListIterator.remove() or Iterator.remove() is called, this change
* is not reflected in the iterator instance as it is still refering to its
* original snapshot.
- *
+ *
*
* @version $Revision$
* @author Paul Speed
*/
-public class SafeArrayList implements List {
-
+public class SafeArrayList implements List, Cloneable {
+
// Implementing List directly to avoid accidentally acquiring
// incorrect or non-optimal behavior from AbstractList. For
- // example, the default iterator() method will not work for
+ // example, the default iterator() method will not work for
// this list.
// Note: given the particular use-cases this was intended,
@@ -81,30 +81,48 @@ public class SafeArrayList implements List {
// SafeArrayList-specific methods could then be exposed
// for the classes like Node and Spatial to use to manage
// the list. This was the callers couldn't remove a child
- // without it being detached properly, for example.
+ // without it being detached properly, for example.
- private Class elementType;
+ private Class elementType;
private List buffer;
private E[] backingArray;
private int size = 0;
-
+
public SafeArrayList(Class elementType) {
- this.elementType = elementType;
+ this.elementType = elementType;
}
-
+
public SafeArrayList(Class elementType, Collection extends E> c) {
- this.elementType = elementType;
+ this.elementType = elementType;
addAll(c);
}
+ public SafeArrayList clone() {
+ try {
+ SafeArrayList clone = (SafeArrayList)super.clone();
+
+ // Clone whichever backing store is currently active
+ if( backingArray != null ) {
+ clone.backingArray = backingArray.clone();
+ }
+ if( buffer != null ) {
+ clone.buffer = (List)((ArrayList)buffer).clone();
+ }
+
+ return clone;
+ } catch( CloneNotSupportedException e ) {
+ throw new AssertionError();
+ }
+ }
+
protected final T[] createArray(Class type, int size) {
- return (T[])java.lang.reflect.Array.newInstance(type, size);
+ return (T[])java.lang.reflect.Array.newInstance(type, size);
}
-
+
protected final E[] createArray(int size) {
- return createArray(elementType, size);
+ return createArray(elementType, size);
}
-
+
/**
* Returns a current snapshot of this List's backing array that
* is guaranteed not to change through further List manipulation.
@@ -114,10 +132,10 @@ public class SafeArrayList implements List {
public final E[] getArray() {
if( backingArray != null )
return backingArray;
-
+
if( buffer == null ) {
backingArray = createArray(0);
- } else {
+ } else {
// Only keep the array or the buffer but never both at
// the same time. 1) it saves space, 2) it keeps the rest
// of the code safer.
@@ -126,35 +144,35 @@ public class SafeArrayList implements List {
}
return backingArray;
}
-
+
protected final List getBuffer() {
if( buffer != null )
return buffer;
-
+
if( backingArray == null ) {
buffer = new ArrayList();
- } else {
+ } else {
// Only keep the array or the buffer but never both at
// the same time. 1) it saves space, 2) it keeps the rest
- // of the code safer.
+ // of the code safer.
buffer = new ArrayList( Arrays.asList(backingArray) );
backingArray = null;
}
return buffer;
}
-
+
public final int size() {
- return size;
+ return size;
}
-
+
public final boolean isEmpty() {
return size == 0;
}
-
+
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
-
+
public Iterator iterator() {
return listIterator();
}
@@ -162,70 +180,70 @@ public class SafeArrayList implements List {
public Object[] toArray() {
return getArray();
}
-
+
public T[] toArray(T[] a) {
-
+
E[] array = getArray();
if (a.length < array.length) {
return (T[])Arrays.copyOf(array, array.length, a.getClass());
- }
-
+ }
+
System.arraycopy( array, 0, a, 0, array.length );
-
+
if (a.length > array.length) {
a[array.length] = null;
}
-
+
return a;
}
-
+
public boolean add(E e) {
boolean result = getBuffer().add(e);
size = getBuffer().size();
return result;
}
-
+
public boolean remove(Object o) {
boolean result = getBuffer().remove(o);
size = getBuffer().size();
return result;
}
-
+
public boolean containsAll(Collection> c) {
return Arrays.asList(getArray()).containsAll(c);
}
-
+
public boolean addAll(Collection extends E> c) {
boolean result = getBuffer().addAll(c);
size = getBuffer().size();
return result;
}
-
+
public boolean addAll(int index, Collection extends E> c) {
boolean result = getBuffer().addAll(index, c);
size = getBuffer().size();
return result;
}
-
+
public boolean removeAll(Collection> c) {
boolean result = getBuffer().removeAll(c);
size = getBuffer().size();
return result;
}
-
+
public boolean retainAll(Collection> c) {
boolean result = getBuffer().retainAll(c);
size = getBuffer().size();
return result;
}
-
+
public void clear() {
getBuffer().clear();
size = 0;
}
-
+
public boolean equals(Object o) {
- if( o == this )
+ if( o == this )
return true;
if( !(o instanceof List) ) //covers null too
return false;
@@ -240,9 +258,9 @@ public class SafeArrayList implements List {
if( o1 == null || !o1.equals(o2) )
return false;
}
- return !(i1.hasNext() || !i2.hasNext());
+ return !(i1.hasNext() || !i2.hasNext());
}
-
+
public int hashCode() {
// Exactly the hash code described in the List interface, basically
E[] array = getArray();
@@ -252,30 +270,30 @@ public class SafeArrayList implements List {
}
return result;
}
-
+
public final E get(int index) {
if( backingArray != null )
return backingArray[index];
if( buffer != null )
return buffer.get(index);
- throw new IndexOutOfBoundsException( "Index:" + index + ", Size:0" );
+ throw new IndexOutOfBoundsException( "Index:" + index + ", Size:0" );
}
-
+
public E set(int index, E element) {
return getBuffer().set(index, element);
}
-
+
public void add(int index, E element) {
getBuffer().add(index, element);
size = getBuffer().size();
}
-
+
public E remove(int index) {
E result = getBuffer().remove(index);
size = getBuffer().size();
return result;
}
-
+
public int indexOf(Object o) {
E[] array = getArray();
for( int i = 0; i < array.length; i++ ) {
@@ -289,7 +307,7 @@ public class SafeArrayList implements List {
}
return -1;
}
-
+
public int lastIndexOf(Object o) {
E[] array = getArray();
for( int i = array.length - 1; i >= 0; i-- ) {
@@ -303,29 +321,29 @@ public class SafeArrayList implements List {
}
return -1;
}
-
+
public ListIterator listIterator() {
return new ArrayIterator(getArray(), 0);
}
-
+
public ListIterator listIterator(int index) {
return new ArrayIterator(getArray(), index);
}
-
+
public List subList(int fromIndex, int toIndex) {
-
+
// So far JME doesn't use subList that I can see so I'm nerfing it.
List raw = Arrays.asList(getArray()).subList(fromIndex, toIndex);
return Collections.unmodifiableList(raw);
}
-
+
public String toString() {
-
+
E[] array = getArray();
if( array.length == 0 ) {
return "[]";
}
-
+
StringBuilder sb = new StringBuilder();
sb.append('[');
for( int i = 0; i < array.length; i++ ) {
@@ -337,63 +355,63 @@ public class SafeArrayList implements List {
sb.append(']');
return sb.toString();
}
-
+
protected class ArrayIterator implements ListIterator {
private E[] array;
private int next;
private int lastReturned;
-
+
protected ArrayIterator( E[] array, int index ) {
this.array = array;
this.next = index;
this.lastReturned = -1;
}
-
+
public boolean hasNext() {
return next != array.length;
}
-
+
public E next() {
if( !hasNext() )
throw new NoSuchElementException();
lastReturned = next++;
return array[lastReturned];
}
-
+
public boolean hasPrevious() {
- return next != 0;
- }
-
+ return next != 0;
+ }
+
public E previous() {
if( !hasPrevious() )
throw new NoSuchElementException();
lastReturned = --next;
return array[lastReturned];
}
-
+
public int nextIndex() {
- return next;
+ return next;
}
-
+
public int previousIndex() {
return next - 1;
}
-
+
public void remove() {
// This operation is not so easy to do but we will fake it.
// The issue is that the backing list could be completely
// different than the one this iterator is a snapshot of.
- // We'll just remove(element) which in most cases will be
+ // We'll just remove(element) which in most cases will be
// correct. If the list had earlier .equals() equivalent
// elements then we'll remove one of those instead. Either
// way, none of those changes are reflected in this iterator.
SafeArrayList.this.remove( array[lastReturned] );
}
-
+
public void set(E e) {
throw new UnsupportedOperationException();
}
-
+
public void add(E e) {
throw new UnsupportedOperationException();
}