Refactors LinkedList to not use circular list.

The new implementation is using double pivot instead of
single.

This is to make LinkedList safer when preconditions are
not enabled and iterator is not used properly.
For example, with a circular list, if you keep calling
next/remove you might never hit an NPE because it will
eventually come back to beginning and start iterating
again.

This might be a little bit on the paranoid side but given
the new implementation is no more complex, it is a good
trade-off.

Change-Id: I4915d5c7b3a6a0e48b96c14be4ce0d64bf3b0de2
Review-Link: https://gwt-review.googlesource.com/#/c/9363/
diff --git a/user/super/com/google/gwt/emul/java/util/LinkedList.java b/user/super/com/google/gwt/emul/java/util/LinkedList.java
index ae82156..a276656 100644
--- a/user/super/com/google/gwt/emul/java/util/LinkedList.java
+++ b/user/super/com/google/gwt/emul/java/util/LinkedList.java
@@ -15,8 +15,9 @@
  */
 package java.util;
 
-import static com.google.gwt.core.shared.impl.GwtPreconditions.checkCriticalElement;
+import static com.google.gwt.core.shared.impl.GwtPreconditions.checkElement;
 import static com.google.gwt.core.shared.impl.GwtPreconditions.checkPositionIndex;
+import static com.google.gwt.core.shared.impl.GwtPreconditions.checkState;
 
 import java.io.Serializable;
 
@@ -30,13 +31,13 @@
 public class LinkedList<E> extends AbstractSequentialList<E> implements
     Cloneable, List<E>, Deque<E>, Serializable {
   /*
-   * This implementation uses a doubly-linked circular list with a header node.
+   * This implementation uses a doubly-linked list with a header/tail node.
    * 
    * TODO(jat): add more efficient subList implementation.
    */
 
   private final class DescendingIteratorImpl implements Iterator<E> {
-    private final ListIterator<E> itr = new ListIteratorImpl(size, header);
+    private final ListIterator<E> itr = new ListIteratorImpl(size, tail);
 
     @Override
     public boolean hasNext() {
@@ -84,70 +85,73 @@
       currentIndex = index;
     }
 
+    @Override
     public void add(E o) {
-      addBefore(o, currentNode);
+      addNode(o, currentNode.prev, currentNode);
       ++currentIndex;
       lastNode = null;
     }
 
+    @Override
     public boolean hasNext() {
-      return currentNode != header;
+      return currentNode != tail;
     }
 
+    @Override
     public boolean hasPrevious() {
       return currentNode.prev != header;
     }
 
+    @Override
     public E next() {
-      if (!hasNext()) {
-        throw new NoSuchElementException();
-      }
+      checkElement(hasNext());
+
       lastNode = currentNode;
       currentNode = currentNode.next;
       ++currentIndex;
       return lastNode.value;
     }
 
+    @Override
     public int nextIndex() {
       return currentIndex;
     }
 
+    @Override
     public E previous() {
-      if (!hasPrevious()) {
-        throw new NoSuchElementException();
-      }
+      checkElement(hasPrevious());
+
       lastNode = currentNode = currentNode.prev;
       --currentIndex;
       return lastNode.value;
     }
 
+    @Override
     public int previousIndex() {
       return currentIndex - 1;
     }
 
+    @Override
     public void remove() {
-      verifyCurrentElement();
+      checkState(lastNode != null);
+
+      Node<E> nextNode = lastNode.next;
+      removeNode(lastNode);
       if (currentNode == lastNode) {
         // We just did a previous().
-        currentNode = lastNode.next;
+        currentNode = nextNode;
       } else {
         // We just did a next().
         --currentIndex;
       }
-      lastNode.remove();
       lastNode = null;
-      --size;
     }
 
+    @Override
     public void set(E o) {
-      verifyCurrentElement();
-      lastNode.value = o;
-    }
+      checkState(lastNode != null);
 
-    protected void verifyCurrentElement() {
-      if (lastNode == null) {
-        throw new IllegalStateException();
-      }
+      lastNode.value = o;
     }
   }
 
@@ -160,38 +164,6 @@
     public Node<E> next;
     public Node<E> prev;
     public E value;
-
-    public Node() {
-      next = prev = this;
-    }
-
-    public Node(E value) {
-      this.value = value;
-    }
-
-    /**
-     * Construct a node containing a value and add it before the specified node.
-     * 
-     * @param value
-     * @param nextNode
-     */
-    public Node(E value, Node<E> nextNode) {
-      this(value);
-      this.next = nextNode;
-      this.prev = nextNode.prev;
-      nextNode.prev.next = this;
-      nextNode.prev = this;
-    }
-
-    /**
-     * Remove this node from any list it is in, leaving it with circular
-     * references to itself.
-     */
-    public void remove() {
-      this.next.prev = this.prev;
-      this.prev.next = this.next;
-      this.next = this.prev = this;
-    }
   }
 
   /**
@@ -202,11 +174,14 @@
   private E exposeElement;
 
   /**
-   * Header node - header.next is the first element of the list, and header.prev
-   * is the last element of the list. If the list is empty, the header node will
-   * point to itself.
+   * Header node - header.next is the first element of the list.
    */
-  private Node<E> header;
+  private final Node<E> header = new Node<E>();
+
+  /**
+   * Tail node - tail.prev is the last element of the list.
+   */
+  private final Node<E> tail = new Node<E>();
 
   /**
    * Number of nodes currently present in the list.
@@ -214,11 +189,11 @@
   private int size;
 
   public LinkedList() {
-    clear();
+    reset();
   }
 
   public LinkedList(Collection<? extends E> c) {
-    this();
+    reset();
     addAll(c);
   }
 
@@ -228,19 +203,25 @@
     return true;
   }
 
+  @Override
   public void addFirst(E o) {
-    new Node<E>(o, header.next);
-    ++size;
+    addNode(o, header, header.next);
   }
 
+  @Override
   public void addLast(E o) {
-    new Node<E>(o, header);
-    ++size;
+    addNode(o, tail.prev, tail);
   }
 
   @Override
   public void clear() {
-    header = new Node<E>();
+    reset();
+  }
+
+  private void reset() {
+    header.next = tail;
+    tail.prev = header;
+    header.prev = tail.next = null;
     size = 0;
   }
 
@@ -253,20 +234,23 @@
     return new DescendingIteratorImpl();
   }
 
+  @Override
   public E element() {
     return getFirst();
   }
 
+  @Override
   public E getFirst() {
-    checkCriticalElement(size != 0);
+    checkElement(size != 0);
 
     return header.next.value;
   }
 
+  @Override
   public E getLast() {
-    checkCriticalElement(size != 0);
+    checkElement(size != 0);
 
-    return header.prev.value;
+    return tail.prev.value;
   }
 
   @Override
@@ -276,7 +260,7 @@
     Node<E> node;
     // start from the nearest end of the list
     if (index >= size >> 1) {
-      node = header;
+      node = tail;
       for (int i = size; i > index; --i) {
         node = node.prev;
       }
@@ -290,6 +274,7 @@
     return new ListIteratorImpl(index, node);
   }
 
+  @Override
   public boolean offer(E o) {
     return offerLast(o);
   }
@@ -306,48 +291,34 @@
     return true;
   }
 
+  @Override
   public E peek() {
     return peekFirst();
   }
 
   @Override
   public E peekFirst() {
-    if (size == 0) {
-      return null;
-    } else {
-      return getFirst();
-    }
+    return size == 0 ? null : getFirst();
   }
 
   @Override
   public E peekLast() {
-    if (size == 0) {
-      return null;
-    } else {
-      return getLast();
-    }
+    return size == 0 ? null : getLast();
   }
 
+  @Override
   public E poll() {
     return pollFirst();
   }
 
   @Override
   public E pollFirst() {
-    if (size == 0) {
-      return null;
-    } else {
-      return removeFirst();
-    }
+    return size == 0 ? null : removeFirst();
   }
 
   @Override
   public E pollLast() {
-    if (size == 0) {
-      return null;
-    } else {
-      return removeLast();
-    }
+    return size == 0 ? null : removeLast();
   }
 
   @Override
@@ -360,13 +331,16 @@
     addFirst(e);
   }
 
+  @Override
   public E remove() {
     return removeFirst();
   }
 
+  @Override
   public E removeFirst() {
-    Node<E> node = removeNode(header.next);
-    return node.value;
+    checkElement(size != 0);
+
+    return removeNode(header.next);
   }
 
   @Override
@@ -374,14 +348,16 @@
     return remove(o);
   }
 
+  @Override
   public E removeLast() {
-    Node<E> node = removeNode(header.prev);
-    return node.value;
+    checkElement(size != 0);
+
+    return removeNode(tail.prev);
   }
 
   @Override
   public boolean removeLastOccurrence(Object o) {
-    for (Node<E> e = header.prev; e != header; e = e.prev) {
+    for (Node<E> e = tail.prev; e != header; e = e.prev) {
       if (Objects.equals(e.value, o)) {
         removeNode(e);
         return true;
@@ -395,16 +371,22 @@
     return size;
   }
 
-  private void addBefore(E o, Node<E> target) {
-    new Node<E>(o, target);
+  private void addNode(E o, Node<E> prev, Node<E> next) {
+    Node<E> node = new Node<E>();
+    node.value = o;
+    node.prev = prev;
+    node.next = next;
+    next.prev = prev.next = node;
     ++size;
   }
 
-  private Node<E> removeNode(Node<E> node) {
-    checkCriticalElement(size != 0);
-
+  private E removeNode(Node<E> node) {
+    E oldValue = node.value;
+    node.next.prev = node.prev;
+    node.prev.next = node.next;
+    node.next = node.prev = null;
+    node.value = null;
     --size;
-    node.remove();
-    return node;
+    return oldValue;
   }
 }