Package gnu.trove

Source Code of gnu.trove.TLinkedList$IteratorImpl

/**
*
* @author Peter Karich, peat_hal 'at' users 'dot' sourceforge 'dot' net
*/
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2001, Eric D. Friedman All Rights Reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library 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 for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
///////////////////////////////////////////////////////////////////////////////
package gnu.trove;

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.AbstractSequentialList;
import java.util.Iterator;
import java.util.ListIterator;
import java.util.NoSuchElementException;

/**
* A LinkedList implementation which holds instances of type
* <tt>TLinkable</tt>.
*
* <p>Using this implementation allows you to get java.util.LinkedList
* behavior (a doubly linked list, with Iterators that support insert
* and delete operations) without incurring the overhead of creating
* <tt>Node</tt> wrapper objects for every element in your list.</p>
*
* <p>The requirement to achieve this time/space gain is that the
* Objects stored in the List implement the <tt>TLinkable</tt>
* interface.</p>
*
* <p>The limitations are that you cannot put the same object into
* more than one list or more than once in the same list.  You must
* also ensure that you only remove objects that are actually in the
* list.  That is, if you have an object A and lists l1 and l2, you
* must ensure that you invoke List.remove(A) on the correct list.  It
* is also forbidden to invoke List.remove() with an unaffiliated
* TLinkable (one that belongs to no list): this will destroy the list
* you invoke it on.</p>
*
* <p>
* Created: Sat Nov 10 15:25:10 2001
* </p>
*
* @author Eric D. Friedman
* @version $Id: TLinkedList.java,v 1.15 2009/03/31 19:43:14 robeden Exp $
* @see gnu.trove.TLinkable
*/
public class TLinkedList<T extends TLinkable> extends AbstractSequentialList<T>
        implements Externalizable {

    static final long serialVersionUID = 1L;
    /** the head of the list */
    protected T _firstElement;
    /** the tail of the list */
    protected T _lastElement;
    /** the number of elements in the list */
    protected int _size = 0;

    /**
     * Creates a new <code>TLinkedList</code> instance.
     *
     */
    public TLinkedList() {
        super();
    }

    /**
     * Returns an iterator positioned at <tt>index</tt>.  Assuming
     * that the list has a value at that index, calling next() will
     * retrieve and advance the iterator.  Assuming that there is a
     * value before <tt>index</tt> in the list, calling previous()
     * will retrieve it (the value at index - 1) and move the iterator
     * to that position.  So, iterating from front to back starts at
     * 0; iterating from back to front starts at <tt>size()</tt>.
     *
     * @param index an <code>int</code> value
     * @return a <code>ListIterator</code> value
     */
    public ListIterator<T> listIterator(int index) {
        return new IteratorImpl(index);
    }
   
    public TLinkedList<T> inverse() {
        TLinkedList<T> ll = new TLinkedList<T>();
        ll._firstElement = _lastElement;
        ll._lastElement = _firstElement;
        ll._size = _size;
        return ll;
    }
    private transient SimpleIterator iter;

    /**
     * Iterates over elements which are returned from TLinkable.get()
     * @return
     */
    public Iterator elementIterator() {
        if (iter == null)
            iter = new SimpleIterator();
        return iter;
    }

    /**
     * Simple iterator for ascending order
     */
    protected class SimpleIterator implements Iterator {

        private TLinkable _next = _firstElement;

        @Override
        public boolean hasNext() {
            return _next.getNext() != _lastElement;
        }

        @Override
        public Object next() {
            _next = _next.getNext();
            return _next.get();
        }

        @Override
        public void remove() {
            if (_next == null)
                throw new IllegalStateException("must invoke next before invoking remove");

            TLinkedList.this.remove(_next);
        }
    }

    /**
     * Returns the number of elements in the list.
     *
     * @return an <code>int</code> value
     */
    public int size() {
        return _size;
    }

    /**
     * Inserts <tt>linkable</tt> at index <tt>index</tt> in the list.
     * All values > index are shifted over one position to accommodate
     * the new addition.
     *
     * @param index an <code>int</code> value
     * @param linkable an object of type TLinkable
     */
    public void add(int index, T linkable) {
        if (index < 0 || index > size()) {
            throw new IndexOutOfBoundsException("index:" + index);
        }
        insert(index, linkable);
    }

    /**
     * Appends <tt>linkable</tt> to the end of the list.
     *
     * @param linkable an object of type TLinkable
     * @return always true
     */
    public boolean add(T linkable) {
        insert(_size, linkable);
        return true;
    }

    /**
     * Inserts <tt>linkable</tt> at the head of the list.
     *
     * @param linkable an object of type TLinkable
     */
    public void addFirst(T linkable) {
        insert(0, linkable);
    }

    /**
     * Adds <tt>linkable</tt> to the end of the list.
     *
     * @param linkable an object of type TLinkable
     */
    public void addLast(T linkable) {
        insert(size(), linkable);
    }

    /**
     * Empties the list.
     *
     */
    public void clear() {
        if (null != _firstElement) {
            for (TLinkable link = _firstElement.getNext();
                    link != null;
                    link = link.getNext()) {
                TLinkable prev = link.getPrevious();
                prev.setNext(null);
                link.setPrevious(null);
            }
            _firstElement = _lastElement = null;
        }
        _size = 0;
    }

    /**
     * Copies the list's contents into a native array.  This will be a
     * shallow copy: the Tlinkable instances in the Object[] array
     * have links to one another: changing those will put this list
     * into an unpredictable state.  Holding a reference to one
     * element in the list will prevent the others from being garbage
     * collected unless you clear the next/previous links.  <b>Caveat
     * programmer!</b>
     *
     * @return an <code>Object[]</code> value
     */
    public Object[] toArray() {
        Object[] o = new Object[_size];
        int i = 0;
        for (TLinkable link = _firstElement; link != null; link = link.getNext()) {
            o[i++] = link;
        }
        return o;
    }

    /**
     * Copies the list to a native array, destroying the next/previous
     * links as the copy is made.  This list will be emptied after the
     * copy (as if clear() had been invoked).  The Object[] array
     * returned will contain TLinkables that do <b>not</b> hold
     * references to one another and so are less likely to be the
     * cause of memory leaks.
     *
     * @return an <code>Object[]</code> value
     */
    public Object[] toUnlinkedArray() {
        Object[] o = new Object[_size];
        int i = 0;
        for (T link = _firstElement, tmp = null; link != null; i++) {
            o[i] = link;
            tmp = link;
            link = (T) link.getNext();
            tmp.setNext(null); // clear the links
            tmp.setPrevious(null);
        }
        _size = 0;              // clear the list
        _firstElement = _lastElement = null;
        return o;
    }

    /**
     * A linear search for <tt>o</tt> in the list.
     *
     * @param o an <code>Object</code> value
     * @return a <code>boolean</code> value
     */
    public boolean contains(Object o) {
        for (TLinkable link = _firstElement; link != null; link = link.getNext()) {
            if (o.equals(link)) {
                return true;
            }
        }
        return false;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public T get(int index) {
        // Blow out for bogus values
        if (index < 0 || index >= _size) {
            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + _size);
        }

        // Determine if it's better to get there from the front or the back
        if (index > (_size >> 1)) {
            int position = _size - 1;
            T node = _lastElement;

            while (position > index) {
                node = (T) node.getPrevious();
                position--;
            }

            return node;
        } else {
            int position = 0;
            T node = _firstElement;

            while (position < index) {
                node = (T) node.getNext();
                position++;
            }

            return node;
        }
    }

    /**
     * Returns the head of the list
     *
     * @return an <code>Object</code> value
     */
    public T getFirst() {
        return _firstElement;
    }

    /**
     * Returns the tail of the list.
     *
     * @return an <code>Object</code> value
     */
    public T getLast() {
        return _lastElement;
    }

    /**
     * Return the node following the given node. This method exists for two reasons:
     * <ol>
     *   <li>It's really not recommended that the methods implemented by TLinkable be
     *       called directly since they're used internally by this class.</li>
     *   <li>This solves problems arising from generics when working with the linked
     *       objects directly.</li>
     * </ol>
     * <p>
     * NOTE: this should only be used with nodes contained in the list. The results are
     * undefined with anything else.
     */
    public T getNext(T current) {
        return (T) current.getNext();
    }

    /**
     * Return the node preceding the given node. This method exists for two reasons:
     * <ol>
     *   <li>It's really not recommended that the methods implemented by TLinkable be
     *       called directly since they're used internally by this class.</li>
     *   <li>This solves problems arising from generics when working with the linked
     *       objects directly.</li>
     * </ol>
     * <p>
     * NOTE: this should only be used with nodes contained in the list. The results are
     * undefined with anything else.
     */
    public T getPrevious(T current) {
        return (T) current.getPrevious();
    }

    /**
     * Remove and return the first element in the list.
     *
     * @return an <code>Object</code> value
     */
    public T removeFirst() {
        T o = _firstElement;

        if (o == null)
            return null;

        T n = (T) o.getNext();
        o.setNext(null);

        if (null != n) {
            n.setPrevious(null);
        }

        _firstElement = n;
        if (--_size == 0) {
            _lastElement = null;
        }
        return o;
    }

    /**
     * Remove and return the last element in the list.
     *
     * @return an <code>Object</code> value
     */
    public T removeLast() {
        T o = _lastElement;

        if (o == null)
            return null;

        T prev = (T) o.getPrevious();
        o.setPrevious(null);

        if (null != prev) {
            prev.setNext(null);
        }
        _lastElement = prev;
        if (--_size == 0) {
            _firstElement = null;
        }
        return o;
    }

    /**
     * Implementation of index-based list insertions.
     *
     * @param index an <code>int</code> value
     * @param linkable an object of type TLinkable
     */
    protected void insert(int index, T linkable) {
        T newLink = linkable;

        if (_size == 0) {
            _firstElement = _lastElement = newLink; // first insertion
        } else if (index == 0) {
            newLink.setNext(_firstElement); // insert at front
            _firstElement.setPrevious(newLink);
            _firstElement = newLink;
        } else if (index == _size) { // insert at back
            _lastElement.setNext(newLink);
            newLink.setPrevious(_lastElement);
            _lastElement = newLink;
        } else {
            T node = get(index);

            T before = (T) node.getPrevious();
            if (before != null)
                before.setNext(linkable);

            linkable.setPrevious(before);
            linkable.setNext(node);
            node.setPrevious(linkable);
        }
        _size++;
    }

    /**
     * Removes the specified element from the list.  Note that
     * it is the caller's responsibility to ensure that the
     * element does, in fact, belong to this list and not another
     * instance of TLinkedList.
     *
     * @param o a TLinkable element already inserted in this list.
     * @return true if the element was a TLinkable and removed
     */
    public boolean remove(Object o) {
        if (o instanceof TLinkable) {
            T p, n;
            TLinkable link = (TLinkable) o;

            p = (T) link.getPrevious();
            n = (T) link.getNext();

            if (n == null && p == null) { // emptying the list
                // It's possible this object is not something that's in the list. So,
                // make sure it's the head if it doesn't point to anything. This solves
                // problems caused by removing something multiple times.
                if (o != _firstElement)
                    return false;

                _firstElement = _lastElement = null;
            } else if (n == null) { // this is the tail
                // make previous the new tail
                link.setPrevious(null);
                p.setNext(null);
                _lastElement = p;
            } else if (p == null) { // this is the head
                // make next the new head
                link.setNext(null);
                n.setPrevious(null);
                _firstElement = n;
            } else {            // somewhere in the middle
                p.setNext(n);
                n.setPrevious(p);
                link.setNext(null);
                link.setPrevious(null);
            }

            _size--;            // reduce size of list
            return true;
        } else {
            return false;
        }
    }

    /**
     * Inserts newElement into the list immediately before current.
     * All elements to the right of and including current are shifted
     * over.
     *
     * @param current a <code>TLinkable</code> value currently in the list.
     * @param newElement a <code>TLinkable</code> value to be added to
     * the list.
     */
    public void addBefore(T current, T newElement) {
        if (current == _firstElement) {
            addFirst(newElement);
        } else if (current == null) {
            addLast(newElement);
        } else {
            TLinkable p = current.getPrevious();
            newElement.setNext(current);
            p.setNext(newElement);
            newElement.setPrevious(p);
            current.setPrevious(newElement);
            _size++;
        }
    }

    /**
     * Inserts newElement into the list immediately after current.
     * All elements to the left of and including current are shifted
     * over.
     *
     * @param current a <code>TLinkable</code> value currently in the list.
     * @param newElement a <code>TLinkable</code> value to be added to
     * the list.
     */
    public void addAfter(T current, T newElement) {
        if (current == _lastElement) {
            addLast(newElement);
        } else if (current == null) {
            addFirst(newElement);
        } else {
            TLinkable n = current.getNext();
            newElement.setPrevious(current);
            newElement.setNext(n);
            current.setNext(newElement);
            n.setPrevious(newElement);
            _size++;
        }
    }

    public void writeExternal(ObjectOutput out) throws IOException {
        // VERSION
        out.writeByte(0);

        // NUMBER OF ENTRIES
        out.writeInt(_size);

        // HEAD
        out.writeObject(_firstElement);

        // TAIL
        out.writeObject(_lastElement);
    }

    public void readExternal(ObjectInput in)
            throws IOException, ClassNotFoundException {

        // VERSION
        in.readByte();

        // NUMBER OF ENTRIED
        _size = in.readInt();

        // HEAD
        _firstElement = (T) in.readObject();

        // TAIL
        _lastElement = (T) in.readObject();
    }

    /**
     * A ListIterator that supports additions and deletions.
     */
    protected final class IteratorImpl implements ListIterator<T> {

        private int _nextIndex = 0;
        private T _next;
        private T _lastReturned;

        /**
         * Creates a new <code>Iterator</code> instance positioned at
         * <tt>index</tt>.
         *
         * @param position an <code>int</code> value
         */
        IteratorImpl(int position) {
            if (position < 0 || position > _size) {
                throw new IndexOutOfBoundsException();
            }

            _nextIndex = position;
            if (position == 0) {
                _next = _firstElement;
            } else if (position == _size) {
                _next = null;
            } else if (position < (_size >> 1)) {
                int pos = 0;
                for (_next = _firstElement; pos < position; pos++) {
                    _next = (T) _next.getNext();
                }
            } else {
                int pos = _size - 1;
                for (_next = _lastElement; pos > position; pos--) {
                    _next = (T) _next.getPrevious();
                }
            }
        }

        /**
         * Insert <tt>linkable</tt> at the current position of the iterator.
         * Calling next() after add() will return the added object.
         *
         * @param linkable an object of type TLinkable
         */
        public final void add(T linkable) {
            _lastReturned = null;
            _nextIndex++;

            if (_size == 0) {
                TLinkedList.this.add(linkable);
            } else {
                TLinkedList.this.addBefore(_next, linkable);
            }
        }

        /**
         * True if a call to next() will return an object.
         *
         * @return a <code>boolean</code> value
         */
        public final boolean hasNext() {
            return _nextIndex != _size;
        }

        /**
         * True if a call to previous() will return a value.
         *
         * @return a <code>boolean</code> value
         */
        public final boolean hasPrevious() {
            return _nextIndex != 0;
        }

        /**
         * Returns the value at the Iterator's index and advances the
         * iterator.
         *
         * @return an <code>Object</code> value
         * @exception NoSuchElementException if there is no next element
         */
        public final T next() {
            if (_nextIndex == _size) {
                throw new NoSuchElementException();
            }

            _lastReturned = _next;
            _next = (T) _next.getNext();
            _nextIndex++;
            return _lastReturned;
        }

        /**
         * returns the index of the next node in the list (the
         * one that would be returned by a call to next()).
         *
         * @return an <code>int</code> value
         */
        public final int nextIndex() {
            return _nextIndex;
        }

        /**
         * Returns the value before the Iterator's index and moves the
         * iterator back one index.
         *
         * @return an <code>Object</code> value
         * @exception NoSuchElementException if there is no previous element.
         */
        public final T previous() {
            if (_nextIndex == 0) {
                throw new NoSuchElementException();
            }

            if (_nextIndex == _size) {
                _lastReturned = _next = _lastElement;
            } else {
                _lastReturned = _next = (T) _next.getPrevious();
            }

            _nextIndex--;
            return _lastReturned;
        }

        /**
         * Returns the previous element's index.
         *
         * @return an <code>int</code> value
         */
        public final int previousIndex() {
            return _nextIndex - 1;
        }

        /**
         * Removes the current element in the list and shrinks its
         * size accordingly.
         *
         * @exception IllegalStateException neither next nor previous
         * have been invoked, or remove or add have been invoked after
         * the last invocation of next or previous.
         */
        public final void remove() {
            if (_lastReturned == null) {
                throw new IllegalStateException("must invoke next or previous before invoking remove");
            }

            if (_lastReturned != _next) {
                _nextIndex--;
            }
            _next = (T) _lastReturned.getNext();
            TLinkedList.this.remove(_lastReturned);
            _lastReturned = null;
        }

        /**
         * Replaces the current element in the list with
         * <tt>linkable</tt>
         *
         * @param linkable an object of type TLinkable
         */
        public final void set(T linkable) {
            if (_lastReturned == null) {
                throw new IllegalStateException();
            }
            T l = linkable;

            // need to check both, since this could be the only
            // element in the list.
            if (_lastReturned == _firstElement) {
                _firstElement = l;
            }

            if (_lastReturned == _lastElement) {
                _lastElement = l;
            }

            swap(_lastReturned, l);
            _lastReturned = l;
        }

        /**
         * Replace from with to in the list.
         *
         * @param from a <code>TLinkable</code> value
         * @param to a <code>TLinkable</code> value
         */
        private void swap(T from, T to) {
            T p = (T) from.getPrevious();
            T n = (T) from.getNext();

            if (null != p) {
                to.setPrevious(p);
                p.setNext(to);
            }
            if (null != n) {
                to.setNext(n);
                n.setPrevious(to);
            }
            from.setNext(null);
            from.setPrevious(null);
        }
    }
} // TLinkedList
TOP

Related Classes of gnu.trove.TLinkedList$IteratorImpl

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.