Package tripleplay.util

Source Code of tripleplay.util.DestroyableList

//
// Triple Play - utilities for use in PlayN-based games
// Copyright (c) 2011-2014, Three Rings Design, Inc. - All rights reserved.
// http://github.com/threerings/tripleplay/blob/master/LICENSE

package tripleplay.util;

import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.NoSuchElementException;

/**
* Maintains a list of {@link Destroyable}s. When an object is removed from the list or the list is
* cleared, it is {@link Destroyable#destroy}ed.
*
* <p> Note that this is not a proper {@code java.util.List} because that interface exposes a ton
* of different ways to manipulate the list, all of which make it very hard to reason about when or
* whether your destroyables are destroyed. This list supports addition, removal, iteration and
* random access. That's about it.
*/
public class DestroyableList<E extends Destroyable> implements Iterable<E>
{
    /**
     * Constructs an empty list with an initial capacity of eight.
     */
    public static <E extends Destroyable> DestroyableList<E> create () {
        return new DestroyableList<E>(8);
    }

    /**
     * Constructs an empty list with the specified initial capacity.
     */
    public static <E extends Destroyable> DestroyableList<E> createWithCapacity (int initCap) {
        return new DestroyableList<E>(initCap);
    }

    protected DestroyableList (int initCap) {
        if (initCap < 0) throw new IllegalArgumentException("Illegal Capacity: "+ initCap);
        _data = new Object[initCap];
    }

    /** Returns the size of the list. */
    public int size() {
        return _size;
    }

    /** Returns true if the list is empty, false if it contains elements. */
    public boolean isEmpty () {
        return _size == 0;
    }

    /** Returns the element at {@code index}. */
    public E get (int index) {
        if (index >= _size) throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
        @SuppressWarnings("unchecked") E elem = (E) _data[index];
        return elem;
    }

    /** Adds (non-null) {@code elem} to the end of the list.
     * @return {@code elem} for convenience. */
    public E add (E elem) {
        if (elem == null) throw new NullPointerException();
        ensureCapacity(_size + 1);
        _data[_size++] = elem;
        return elem;
    }

    /** Inserts (non-null) {@code elem} into the list at {@code index}.
     * @return {@code elem} for convenience.  */
    public E add (int index, E elem) {
        if (index > _size || index < 0) throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
        if (elem == null) throw new NullPointerException();
        ensureCapacity(_size+1);
        System.arraycopy(_data, index, _data, index+1, _size-index);
        _data[index] = elem;
        _size++;
        return elem;
    }

    /** Removes and destroys the element at {@code index}.
     * @return the removed and destroyed element. */
    public E remove (int index) {
        E oldValue = get(index);
        _modCount++;
        int numMoved = _size - index - 1;
        if (numMoved > 0) System.arraycopy(_data, index+1, _data, index, numMoved);
        _data[--_size] = null;
        oldValue.destroy();
        return oldValue;
    }

    /** Removes and destroys (non-null) {@code elem}.
     * @return true if the element was found and destroyed, false otherwise. */
    public boolean remove (E elem) {
        if (elem == null) throw new NullPointerException();
        Object[] data = _data;
        for (int ii = 0, ll = _size; ii < ll; ii++) {
            if (elem.equals(data[ii])) {
                remove(ii);
                return true;
            }
        }
        return false;
    }

    /** Removes and destroys all elements in this list. */
    public void clear () {
        _modCount++;
        Object[] data = _data;
        for (int ii = 0, ll = _size; ii < ll; ii++) {
            @SuppressWarnings("unchecked") E elem = (E)data[ii];
            elem.destroy();
            data[ii] = null;
        }
        _size = 0;
    }

    @Override public Iterator<E> iterator () {
        return new Iterator<E>() {
            @Override public boolean hasNext () {
                return _cursor != _size;
            }

            @Override public E next () {
                checkForComodification();
                int ii = _cursor;
                if (ii >= _size) throw new NoSuchElementException();
                Object[] data = _data;
                if (ii >= data.length) throw new ConcurrentModificationException();
                _cursor = ii + 1;
                @SuppressWarnings("unchecked") E elem = (E) data[_lastRet = ii];
                return elem;
            }

            @Override public void remove () {
                if (_lastRet < 0) throw new IllegalStateException();
                checkForComodification();
                try {
                    DestroyableList.this.remove(_lastRet);
                    _cursor = _lastRet;
                    _lastRet = -1;
                    _exModCount = _modCount;
                } catch (IndexOutOfBoundsException ex) {
                    throw new ConcurrentModificationException();
                }
            }

            final void checkForComodification() {
                if (_modCount != _exModCount) throw new ConcurrentModificationException();
            }

            protected int _cursor;       // index of next element to return
            protected int _lastRet = -1; // index of last element returned; -1 if no such
            protected int _exModCount = _modCount;
        };
    }

    protected final void ensureCapacity (int minCapacity) {
        _modCount++;
        int oldCapacity = _data.length;
        if (minCapacity > oldCapacity) {
            int newCapacity = (oldCapacity * 3)/2 + 1;
            if (newCapacity < minCapacity) newCapacity = minCapacity;
            // minCapacity is usually close to size, so this is a win:
            Object[] newData = new Object[newCapacity];
            System.arraycopy(_data, 0, newData, 0, oldCapacity);
            _data = newData;
        }
    }

    protected String outOfBoundsMsg(int index) {
        return "Index: " + index + ", Size: " + _size;
    }

    protected transient Object[] _data;
    protected int _size;
    protected int _modCount;
}
TOP

Related Classes of tripleplay.util.DestroyableList

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.