159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta/*
259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Copyright (c) 2009-2011 jMonkeyEngine
359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * All rights reserved.
459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *
559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Redistribution and use in source and binary forms, with or without
659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * modification, are permitted provided that the following conditions are
759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * met:
859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *
959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * * Redistributions of source code must retain the above copyright
1059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *   notice, this list of conditions and the following disclaimer.
1159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *
1259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * * Redistributions in binary form must reproduce the above copyright
1359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *   notice, this list of conditions and the following disclaimer in the
1459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *   documentation and/or other materials provided with the distribution.
1559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *
1659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
1759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *   may be used to endorse or promote products derived from this software
1859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *   without specific prior written permission.
1959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *
2059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
2459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
2559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
2659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
2759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
2859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
2959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
3059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */
3259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
3359b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartapackage com.jme3.util;
3459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
3559b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.*;
3659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
3759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta/**
3859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *  <p>Provides a list with similar modification semantics to java.util.concurrent's
3959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *  CopyOnWriteArrayList except that it is not concurrent and also provides
4059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *  direct access to the current array.  This List allows modification of the
4159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *  contents while iterating as any iterators will be looking at a snapshot of
4259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *  the list at the time they were created.  Similarly, access the raw internal
4359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *  array is only presenting a snap shot and so can be safely iterated while
4459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *  the list is changing.</p>
4559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *
4659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *  <p>All modifications, including set() operations will cause a copy of the
4759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *  data to be created that replaces the old version.  Because this list is
4859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *  not designed for threading concurrency it further optimizes the "many modifications"
4959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *  case by buffering them as a normal ArrayList until the next time the contents
5059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *  are accessed.</p>
5159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *
5259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *  <p>Normal list modification performance should be equal to ArrayList in a
5359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *  many situations and always better than CopyOnWriteArrayList.  Optimum usage
5459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *  is when modifications are done infrequently or in batches... as is often the
5559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *  case in a scene graph.  Read operations perform superior to all other methods
5659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *  as the array can be accessed directly.</p>
5759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *
5859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *  <p>Important caveats over normal java.util.Lists:</p>
5959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *  <ul>
6059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *  <li>Even though this class supports modifying the list, the subList() method
6159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *  returns a read-only list.  This technically breaks the List contract.</li>
6259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *  <li>The ListIterators returned by this class only support the remove()
6359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *  modification method.  add() and set() are not supported on the iterator.
6459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *  Even after ListIterator.remove() or Iterator.remove() is called, this change
6559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *  is not reflected in the iterator instance as it is still refering to its
6659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *  original snapshot.
6759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *  </ul>
6859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *
6959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *  @version   $Revision: 8940 $
7059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *  @author    Paul Speed
7159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */
7259b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartapublic class SafeArrayList<E> implements List<E> {
7359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
7459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    // Implementing List directly to avoid accidentally acquiring
7559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    // incorrect or non-optimal behavior from AbstractList.  For
7659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    // example, the default iterator() method will not work for
7759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    // this list.
7859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
7959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    // Note: given the particular use-cases this was intended,
8059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    //       it would make sense to nerf the public mutators and
8159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    //       make this publicly act like a read-only list.
8259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    //       SafeArrayList-specific methods could then be exposed
8359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    //       for the classes like Node and Spatial to use to manage
8459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    //       the list.  This was the callers couldn't remove a child
8559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    //       without it being detached properly, for example.
8659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
8759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    private Class<E> elementType;
8859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    private List<E> buffer;
8959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    private E[] backingArray;
9059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    private int size = 0;
9159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
9259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public SafeArrayList(Class<E> elementType) {
9359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        this.elementType = elementType;
9459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
9559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
9659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public SafeArrayList(Class<E> elementType, Collection<? extends E> c) {
9759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        this.elementType = elementType;
9859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        addAll(c);
9959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
10059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
10159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected final <T> T[] createArray(Class<T> type, int size) {
10259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return (T[])java.lang.reflect.Array.newInstance(type, size);
10359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
10459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
10559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected final E[] createArray(int size) {
10659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return createArray(elementType, size);
10759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
10859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
10959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    /**
11059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     *  Returns a current snapshot of this List's backing array that
11159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     *  is guaranteed not to change through further List manipulation.
11259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     *  Changes to this array may or may not be reflected in the list and
11359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     *  should be avoided.
11459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta     */
11559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public final E[] getArray() {
11659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if( backingArray != null )
11759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            return backingArray;
11859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
11959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if( buffer == null ) {
12059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            backingArray = createArray(0);
12159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        } else {
12259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            // Only keep the array or the buffer but never both at
12359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            // the same time.  1) it saves space, 2) it keeps the rest
12459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            // of the code safer.
12559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            backingArray = buffer.toArray( createArray(buffer.size()) );
12659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            buffer = null;
12759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
12859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return backingArray;
12959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
13059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
13159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected final List<E> getBuffer() {
13259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if( buffer != null )
13359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            return buffer;
13459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
13559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if( backingArray == null ) {
13659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            buffer = new ArrayList();
13759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        } else {
13859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            // Only keep the array or the buffer but never both at
13959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            // the same time.  1) it saves space, 2) it keeps the rest
14059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            // of the code safer.
14159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            buffer = new ArrayList( Arrays.asList(backingArray) );
14259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            backingArray = null;
14359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
14459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return buffer;
14559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
14659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
14759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public final int size() {
14859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return size;
14959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
15059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
15159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public final boolean isEmpty() {
15259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return size == 0;
15359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
15459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
15559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public boolean contains(Object o) {
15659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return indexOf(o) >= 0;
15759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
15859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
15959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public Iterator<E> iterator() {
16059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return listIterator();
16159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
16259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
16359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public Object[] toArray() {
16459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return getArray();
16559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
16659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
16759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public <T> T[] toArray(T[] a) {
16859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
16959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        E[] array = getArray();
17059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (a.length < array.length) {
17159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            return (T[])Arrays.copyOf(array, array.length, a.getClass());
17259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
17359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
17459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        System.arraycopy( array, 0, a, 0, array.length );
17559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
17659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (a.length > array.length) {
17759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            a[array.length] = null;
17859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
17959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
18059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return a;
18159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
18259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
18359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public boolean add(E e) {
18459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        boolean result = getBuffer().add(e);
18559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        size = getBuffer().size();
18659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return result;
18759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
18859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
18959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public boolean remove(Object o) {
19059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        boolean result = getBuffer().remove(o);
19159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        size = getBuffer().size();
19259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return result;
19359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
19459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
19559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public boolean containsAll(Collection<?> c) {
19659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return Arrays.asList(getArray()).containsAll(c);
19759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
19859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
19959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public boolean addAll(Collection<? extends E> c) {
20059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        boolean result = getBuffer().addAll(c);
20159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        size = getBuffer().size();
20259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return result;
20359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
20459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
20559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public boolean addAll(int index, Collection<? extends E> c) {
20659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        boolean result = getBuffer().addAll(index, c);
20759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        size = getBuffer().size();
20859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return result;
20959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
21059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
21159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public boolean removeAll(Collection<?> c) {
21259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        boolean result = getBuffer().removeAll(c);
21359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        size = getBuffer().size();
21459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return result;
21559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
21659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
21759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public boolean retainAll(Collection<?> c) {
21859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        boolean result = getBuffer().retainAll(c);
21959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        size = getBuffer().size();
22059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return result;
22159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
22259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
22359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public void clear() {
22459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        getBuffer().clear();
22559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        size = 0;
22659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
22759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
22859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public boolean equals(Object o) {
22959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if( o == this )
23059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            return true;
23159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if( !(o instanceof List) ) //covers null too
23259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            return false;
23359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        List other = (List)o;
23459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        Iterator i1 = iterator();
23559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        Iterator i2 = other.iterator();
23659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        while( i1.hasNext() && i2.hasNext() ) {
23759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            Object o1 = i1.next();
23859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            Object o2 = i2.next();
23959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            if( o1 == o2 )
24059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                continue;
24159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            if( o1 == null || !o1.equals(o2) )
24259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                return false;
24359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
24459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return !(i1.hasNext() || !i2.hasNext());
24559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
24659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
24759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public int hashCode() {
24859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        // Exactly the hash code described in the List interface, basically
24959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        E[] array = getArray();
25059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        int result = 1;
25159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        for( E e : array ) {
25259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            result = 31 * result + (e == null ? 0 : e.hashCode());
25359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
25459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return result;
25559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
25659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
25759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public final E get(int index) {
25859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if( backingArray != null )
25959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            return backingArray[index];
26059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if( buffer != null )
26159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            return buffer.get(index);
26259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        throw new IndexOutOfBoundsException( "Index:" + index + ", Size:0" );
26359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
26459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
26559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public E set(int index, E element) {
26659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return getBuffer().set(index, element);
26759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
26859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
26959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public void add(int index, E element) {
27059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        getBuffer().add(index, element);
27159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        size = getBuffer().size();
27259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
27359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
27459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public E remove(int index) {
27559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        E result = getBuffer().remove(index);
27659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        size = getBuffer().size();
27759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return result;
27859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
27959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
28059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public int indexOf(Object o) {
28159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        E[] array = getArray();
28259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        for( int i = 0; i < array.length; i++ ) {
28359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            E element = array[i];
28459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            if( element == o ) {
28559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                return i;
28659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            }
28759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            if( element != null && element.equals(o) ) {
28859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                return i;
28959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            }
29059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
29159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return -1;
29259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
29359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
29459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public int lastIndexOf(Object o) {
29559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        E[] array = getArray();
29659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        for( int i = array.length - 1; i >= 0; i-- ) {
29759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            E element = array[i];
29859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            if( element == o ) {
29959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                return i;
30059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            }
30159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            if( element != null && element.equals(o) ) {
30259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                return i;
30359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            }
30459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
30559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return -1;
30659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
30759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
30859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public ListIterator<E> listIterator() {
30959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return new ArrayIterator<E>(getArray(), 0);
31059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
31159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
31259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public ListIterator<E> listIterator(int index) {
31359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return new ArrayIterator<E>(getArray(), index);
31459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
31559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
31659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public List<E> subList(int fromIndex, int toIndex) {
31759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
31859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        // So far JME doesn't use subList that I can see so I'm nerfing it.
31959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        List<E> raw =  Arrays.asList(getArray()).subList(fromIndex, toIndex);
32059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return Collections.unmodifiableList(raw);
32159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
32259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
32359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public String toString() {
32459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
32559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        E[] array = getArray();
32659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if( array.length == 0 ) {
32759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            return "[]";
32859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
32959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
33059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        StringBuilder sb = new StringBuilder();
33159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        sb.append('[');
33259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        for( int i = 0; i < array.length; i++ ) {
33359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            if( i > 0 )
33459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                sb.append( ", " );
33559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            E e = array[i];
33659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            sb.append( e == this ? "(this Collection)" : e );
33759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
33859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        sb.append(']');
33959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return sb.toString();
34059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
34159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
34259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected class ArrayIterator<E> implements ListIterator<E> {
34359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        private E[] array;
34459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        private int next;
34559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        private int lastReturned;
34659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
34759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        protected ArrayIterator( E[] array, int index ) {
34859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            this.array = array;
34959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            this.next = index;
35059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            this.lastReturned = -1;
35159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
35259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
35359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        public boolean hasNext() {
35459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            return next != array.length;
35559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
35659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
35759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        public E next() {
35859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            if( !hasNext() )
35959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                throw new NoSuchElementException();
36059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            lastReturned = next++;
36159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            return array[lastReturned];
36259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
36359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
36459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        public boolean hasPrevious() {
36559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            return next != 0;
36659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
36759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
36859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        public E previous() {
36959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            if( !hasPrevious() )
37059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                throw new NoSuchElementException();
37159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            lastReturned = --next;
37259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            return array[lastReturned];
37359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
37459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
37559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        public int nextIndex() {
37659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            return next;
37759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
37859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
37959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        public int previousIndex() {
38059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            return next - 1;
38159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
38259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
38359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        public void remove() {
38459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            // This operation is not so easy to do but we will fake it.
38559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            // The issue is that the backing list could be completely
38659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            // different than the one this iterator is a snapshot of.
38759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            // We'll just remove(element) which in most cases will be
38859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            // correct.  If the list had earlier .equals() equivalent
38959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            // elements then we'll remove one of those instead.  Either
39059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            // way, none of those changes are reflected in this iterator.
39159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            SafeArrayList.this.remove( array[lastReturned] );
39259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
39359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
39459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        public void set(E e) {
39559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            throw new UnsupportedOperationException();
39659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
39759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
39859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        public void add(E e) {
39959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            throw new UnsupportedOperationException();
40059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
40159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
40259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta}
403