aboutsummaryrefslogtreecommitdiff
path: root/libjava/java/util/LinkedList.java
diff options
context:
space:
mode:
Diffstat (limited to 'libjava/java/util/LinkedList.java')
-rw-r--r--libjava/java/util/LinkedList.java584
1 files changed, 584 insertions, 0 deletions
diff --git a/libjava/java/util/LinkedList.java b/libjava/java/util/LinkedList.java
new file mode 100644
index 0000000..41f1ab4
--- /dev/null
+++ b/libjava/java/util/LinkedList.java
@@ -0,0 +1,584 @@
+/* LinkedList.java -- Linked list implementation of the List interface
+ Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+As a special exception, if you link this library with other files to
+produce an executable, this library does not by itself cause the
+resulting executable to be covered by the GNU General Public License.
+This exception does not however invalidate any other reasons why the
+executable file might be covered by the GNU General Public License. */
+
+
+package java.util;
+import java.io.Serializable;
+import java.io.ObjectOutputStream;
+import java.io.ObjectInputStream;
+import java.io.IOException;
+
+// TO DO:
+// ~ Doc comment for the class.
+// ~ Doc comments for the non-list methods.
+// ~ Some commenting on the Backing API and other general implementation notes.
+
+/**
+ * Linked list implementation of the List interface.
+ */
+public class LinkedList extends AbstractSequentialList
+ implements Serializable, Cloneable
+{
+ static final long serialVersionUID = 876323262645176354L;
+
+ /**
+ * An Entry containing the head (in the next field) and the tail (in the
+ * previous field) of the list. The data field is null. If the list is empty,
+ * both the head and the tail point to ends itself.
+ */
+ transient Entry ends = new Entry();
+
+ /**
+ * The current length of the list.
+ */
+ transient int size = 0;
+
+ /**
+ * Class to represent an entry in the list. Holds a single element.
+ */
+ private static class Entry {
+
+ /**
+ * The list element.
+ */
+ Object data = null;
+
+ /**
+ * The next entry in the list. If this is the last entry in the list, the
+ * ends field of the list is held here.
+ */
+ Entry next;
+
+ /**
+ * The previous entry in the list. If this is the first entry in the list,
+ * the ends field of the list is held here.
+ */
+ Entry previous;
+
+ /**
+ * Create an entry with given data and linkage.
+ */
+ Entry(Object d, Entry n, Entry p) {
+ data = d;
+ next = n;
+ previous = p;
+ }
+
+ /**
+ * Create an entry with no data and linking to itself, for use as the ends
+ * field of the list.
+ */
+ Entry() {
+ next = previous = this;
+ }
+
+ /**
+ * Remove this entry.
+ */
+ Object remove() {
+ previous.next = next;
+ next.previous = previous;
+ return data;
+ }
+ }
+
+ private static interface Backing {
+ void checkMod(int known);
+ void upMod();
+ void incSize(int by);
+ void decSize(int by);
+ }
+
+ private final Backing back = new Backing() {
+ public void checkMod(int known) {
+ if (known != modCount) {
+ throw new ConcurrentModificationException();
+ }
+ }
+ public void upMod() {
+ modCount++;
+ }
+ public void incSize(int by) {
+ size += by;
+ }
+ public void decSize(int by) {
+ size -= by;
+ }
+ };
+
+ /** A ListIterator over the list. This class keeps track of its
+ * position in the list, the size of the list, and the two list
+ * entries it is between. This enables it to be used identically
+ * for both the list itself and a sublist of the list.
+ */
+ private static class Iter implements ListIterator {
+
+ /**
+ * The index of the element that will be returned by next().
+ */
+ int pos;
+
+ /**
+ * The size of the backing list.
+ */
+ int size;
+
+ /**
+ * The entry containing the element that will be returned by next().
+ */
+ Entry next;
+
+ /**
+ * The entry containing the element that will be returned by previous().
+ */
+ Entry previous;
+
+ /**
+ * The entry that will be affected by remove() or set().
+ */
+ Entry recent;
+
+ /**
+ * The known value of the modCount of the backing list.
+ */
+ int knownMod;
+
+ private final Backing b;
+
+ /**
+ * Create a new Iter starting at a given Entry within the list, at a given
+ * position, in a list of given size.
+ *
+ * @param index the index to begin iteration.
+ * @exception IndexOutOfBoundsException if index < 0 || index > size.
+ */
+ Iter(Backing backing, Entry n, int index, int s, int modCount) {
+ b = backing;
+ pos = index;
+ size = s;
+ next = n;
+ previous = n.previous;
+ knownMod = modCount;
+ }
+
+ public int nextIndex() {
+ b.checkMod(knownMod);
+ return pos;
+ }
+
+ public int previousIndex() {
+ b.checkMod(knownMod);
+ return pos - 1;
+ }
+
+ public boolean hasNext() {
+ b.checkMod(knownMod);
+ return pos < size;
+ }
+
+ public boolean hasPrevious() {
+ b.checkMod(knownMod);
+ return pos > 0;
+ }
+
+ public Object next() {
+ b.checkMod(knownMod);
+ if (pos >= size) {
+ throw new NoSuchElementException();
+ } else {
+ pos++;
+ recent = previous = next;
+ next = recent.next;
+ return recent.data;
+ }
+ }
+
+ public Object previous() {
+ b.checkMod(knownMod);
+ if (pos <= 0) {
+ throw new NoSuchElementException();
+ } else {
+ pos--;
+ recent = next = previous;
+ previous = recent.previous;
+ return recent.data;
+ }
+ }
+
+ public void remove() {
+ b.checkMod(knownMod);
+ if (recent == null) {
+ throw new IllegalStateException();
+ }
+
+ // Adjust the position to before the removed element
+ if (recent == previous) pos--;
+
+ // Could use recent.remove() but this way is quicker, and also correctly
+ // fixes next and previous.
+ next = recent.previous.next = recent.next;
+ previous = recent.next.previous = recent.previous;
+ size--;
+ b.decSize(1);
+ knownMod++;
+ b.upMod();
+ recent = null;
+ }
+
+ public void add(Object o) {
+ b.checkMod(knownMod);
+ previous.next = next.previous = new Entry(o, next, previous);
+
+ // New for 1.2RC1 - the semantics changed so that the iterator is
+ // positioned *after* the new element.
+ previous = previous.next;
+ pos++;
+
+ size++;
+ b.incSize(1);
+ knownMod++;
+ b.upMod();
+ recent = null;
+ }
+
+ public void set(Object o) {
+ b.checkMod(knownMod);
+ if (recent == null) {
+ throw new IllegalStateException();
+ }
+ recent.data = o;
+ }
+ }
+
+ /**
+ * Obtain the Entry at a given position in a list. This method of course
+ * takes linear time, but it is intelligent enough to take the shorter of the
+ * paths to get to the Entry required. This implies that the first or last
+ * entry in the list is obtained in constant time, which is a very desirable
+ * property.
+ * For speed and flexibility in which ranges are valid, range checking is not
+ * done in this method, and if n is outside the range -1 <= n <= size, the
+ * result will be wrong (but no exception will be thrown).
+ * Note that you *can* obtain entries at position -1 and size, which are
+ * equal to prehead and posttail respectively.
+ * This method is static so that it can also be used in subList.
+ *
+ * @param n the number of the entry to get.
+ * @param size the size of the list to get the entry in.
+ * @param head the entry before the first element of the list (usually ends).
+ * @param tail the entry after the last element of the list (usually ends).
+ */
+ static Entry getEntry(int n, int size, Entry head, Entry tail) {
+
+ // n less than size/2, iterate from start
+ if (n < size >> 1) {
+ while (n-- >= 0) {
+ head = head.next;
+ }
+ return head;
+
+ // n greater than size/2, iterate from end
+ } else {
+ while (++n <= size) {
+ tail = tail.previous;
+ }
+ return tail;
+ }
+ }
+
+ /**
+ * Create an empty linked list.
+ */
+ public LinkedList() {
+ super();
+ }
+
+ /**
+ * Create a linked list containing the elements, in order, of a given
+ * collection.
+ *
+ * @param c the collection to populate this list from.
+ */
+ public LinkedList(Collection c) {
+ super();
+ // Note: addAll could be made slightly faster, but not enough so to justify
+ // re-implementing it from scratch. It is just a matter of a relatively
+ // small constant factor.
+ addAll(c);
+ }
+
+ public Object getFirst() {
+ if (size == 0) {
+ throw new NoSuchElementException();
+ }
+ return ends.next.data;
+ }
+
+ public Object getLast() {
+ if (size == 0) {
+ throw new NoSuchElementException();
+ }
+ return ends.previous.data;
+ }
+
+ public Object removeFirst() {
+ if (size == 0) {
+ throw new NoSuchElementException();
+ }
+ size--;
+ modCount++;
+ return ends.next.remove();
+ }
+
+ public Object removeLast() {
+ if (size == 0) {
+ throw new NoSuchElementException();
+ }
+ size--;
+ modCount++;
+ return ends.previous.remove();
+ }
+
+ public void addFirst(Object o) {
+ ends.next.previous = ends.next = new Entry(o, ends.next, ends);
+ size++;
+ modCount++;
+ }
+
+ public void addLast(Object o) {
+ ends.previous.next = ends.previous = new Entry(o, ends, ends.previous);
+ size++;
+ modCount++;
+ }
+
+ /**
+ * Obtain the number of elements currently in this list.
+ *
+ * @returns the number of elements currently in this list.
+ */
+ public int size() {
+ return size;
+ }
+
+ /**
+ * Remove a range of elements from this list.
+ *
+ * @param fromIndex the index, inclusive, to remove from.
+ * @param toIndex the index, exclusive, to remove to.
+ * @exception IndexOutOfBoundsException if fromIndex > toIndex || fromIndex <
+ * 0 || toIndex > size().
+ */
+ // Note: normally removeRange is provided to allow efficient ways to
+ // implement clear() on subLists. However, in this case clear on subLists
+ // works anyway, so this implementation is included just for completeness
+ // and because subclasses might try to use it.
+ protected void removeRange(int fromIndex, int toIndex) {
+ subList(fromIndex, toIndex).clear();
+ }
+
+ /**
+ * Clear the list.
+ */
+ public void clear() {
+ ends.next = ends.previous = ends;
+ modCount++;
+ size = 0;
+ }
+
+ /**
+ * Obtain a ListIterator over this list, starting at a given index. The
+ * ListIterator returned by this method supports the add, remove and set
+ * methods.
+ *
+ * @param index the index of the element to be returned by the first call to
+ * next(), or size() to be initially positioned at the end of the list.
+ * @exception IndexOutOfBoundsException if index < 0 || index > size().
+ */
+ public ListIterator listIterator(int index) {
+
+ // Check bounds
+ if (index < 0 || index > size) {
+ throw new IndexOutOfBoundsException();
+ }
+
+ return new Iter(back, getEntry(index, size, ends, ends),
+ index, size, modCount);
+ }
+
+ /**
+ * Obtain a List view of a subsection of this list, from fromIndex
+ * (inclusive) to toIndex (exclusive). The returned list is modifiable in
+ * every respect. Changes to the returned list are reflected in this list. If
+ * this list is structurally modified is any way other than through the
+ * returned list, any subsequent operations on the returned list will result
+ * in a ConcurrentModificationException (that is, the returned list is
+ * fail-fast).
+ *
+ * @param fromIndex the index that the returned list should start from
+ * (inclusive).
+ * @param toIndex the index that the returned list should go to (exclusive).
+ * @returns a List backed by a subsection of this list.
+ * @exception IndexOutOfBoundsException if fromIndex < 0 || toIndex > size()
+ * || fromIndex > toIndex.
+ */
+ public List subList(int fromIndex, int toIndex) {
+
+ // Check bounds
+ if (fromIndex > toIndex || fromIndex < 0 || toIndex > size) {
+ throw new IndexOutOfBoundsException();
+ }
+
+ return new SubLinkedList(back, modCount,
+ getEntry(fromIndex - 1, size, ends, ends),
+ getEntry(toIndex, size, ends, ends),
+ toIndex - fromIndex);
+ }
+
+ private static class SubLinkedList extends AbstractSequentialList {
+
+ Entry head; // entry before the beginning
+ Entry tail; // entry after the end
+ int size;
+ private final Backing b;
+
+ private final Backing back = new Backing() {
+ public void checkMod(int known) {
+ if (known != modCount) {
+ throw new ConcurrentModificationException();
+ }
+ }
+ public void upMod() {
+ modCount++;
+ }
+ public void incSize(int by) {
+ size += by;
+ }
+ public void decSize(int by) {
+ size -= by;
+ }
+ };
+
+ SubLinkedList(Backing backing, int knownMod, Entry h, Entry t, int s) {
+ this.modCount = knownMod;
+ b = backing;
+ head = h;
+ tail = t;
+ size = s;
+ }
+
+ public int size() {
+ b.checkMod(this.modCount);
+ return size;
+ }
+
+ public ListIterator listIterator(int index) {
+ b.checkMod(this.modCount);
+
+ // Check bounds
+ if (index < 0 || index > size) {
+ throw new IndexOutOfBoundsException();
+ }
+
+ return new Iter(back, getEntry(index, size, head, tail),
+ index, size, modCount);
+ }
+
+ public void clear() {
+ b.checkMod(this.modCount);
+ head.next = tail;
+ tail.previous = head;
+ size = 0;
+ b.decSize(size);
+ modCount++;
+ b.upMod();
+ }
+
+ // No removeRange because this class cannot be publically subclassed.
+
+ public List subList(int fromIndex, int toIndex) {
+ b.checkMod(this.modCount);
+
+ // Check bounds
+ if (fromIndex > toIndex || fromIndex < 0 || toIndex > size) {
+ throw new IndexOutOfBoundsException();
+ }
+
+ return new SubLinkedList(back, this.modCount,
+ getEntry(fromIndex - 1, size, head, tail),
+ getEntry(toIndex, size, head, tail),
+ toIndex - fromIndex);
+ }
+ }
+
+ /**
+ * Create a shallow copy of this LinkedList.
+ * @return an object of the same class as this object, containing the
+ * same elements in the same order.
+ */
+ public Object clone()
+ {
+ LinkedList copy;
+ try
+ {
+ copy = (LinkedList) super.clone();
+ }
+ catch (CloneNotSupportedException ex)
+ {
+ throw new InternalError(ex.getMessage());
+ }
+ copy.size = 0;
+ copy.ends = new Entry();
+ copy.addAll(this);
+ return copy;
+ }
+
+ /**
+ * Serialize an object to a stream.
+ * @serialdata the size of the list (int), followed by all the elements
+ * (Object) in proper order.
+ */
+ private void writeObject(ObjectOutputStream s)
+ throws IOException
+ {
+ s.writeInt(size);
+ for (Iterator i = iterator(); i.hasNext(); )
+ s.writeObject(i.next());
+ }
+
+ /**
+ * Deserialize an object from a stream.
+ * @serialdata the size of the list (int), followed by all the elements
+ * (Object) in proper order.
+ */
+ private void readObject(ObjectInputStream s)
+ throws IOException, ClassNotFoundException
+ {
+ int serialSize = s.readInt();
+ ends = new Entry();
+ for (int i=0; i< serialSize; i++)
+ addLast(s.readObject());
+ }
+}