Added a clone() method and implement Cloneable.

Removed whitespace from the ends of lines.
cleanup_build_scripts
Paul Speed 9 years ago
parent 7b29c58fe0
commit c6aac78f42
  1. 164
      jme3-core/src/main/java/com/jme3/util/SafeArrayList.java

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

Loading…
Cancel
Save