| /* |
| * |
| * Copyright 2012-2015 Viant. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| * use this file except in compliance with the License. You may obtain a copy of |
| * the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations under |
| * the License. |
| * |
| */ |
| |
| package org.apache.aries.component.dsl.internal; |
| |
| |
| /* |
| * Written by Doug Lea with assistance from members of JCP JSR-166 |
| * Expert Group and released to the public domain, as explained at |
| * http://creativecommons.org/licenses/publicdomain |
| */ |
| |
| import java.util.AbstractCollection; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.ConcurrentModificationException; |
| import java.util.Deque; |
| import java.util.Iterator; |
| import java.util.NoSuchElementException; |
| import java.util.concurrent.atomic.AtomicReference; |
| |
| /** |
| * A concurrent linked-list implementation of a {@link Deque} (double-ended |
| * queue). Concurrent insertion, removal, and access operations execute safely |
| * across multiple threads. Iterators are <i>weakly consistent</i>, returning |
| * elements reflecting the state of the deque at some point at or since the |
| * creation of the iterator. They do <em>not</em> throw {@link |
| * ConcurrentModificationException}, and may proceed concurrently with other |
| * operations. |
| * |
| * <p> |
| * This class and its iterators implement all of the <em>optional</em> methods |
| * of the {@link Collection} and {@link Iterator} interfaces. Like most other |
| * concurrent collection implementations, this class does not permit the use of |
| * <tt>null</tt> elements. because some null arguments and return values |
| * cannot be reliably distinguished from the absence of elements. Arbitrarily, |
| * the {@link Collection#remove} method is mapped to |
| * <tt>removeFirstOccurrence</tt>, and {@link Collection#add} is mapped to |
| * <tt>addLast</tt>. |
| * |
| * <p> |
| * Beware that, unlike in most collections, the <tt>size</tt> method is |
| * <em>NOT</em> a constant-time operation. Because of the asynchronous nature |
| * of these deques, determining the current number of elements requires a |
| * traversal of the elements. |
| * |
| * <p> |
| * This class is <tt>Serializable</tt>, but relies on default serialization |
| * mechanisms. Usually, it is a better idea for any serializable class using a |
| * <tt>ConcurrentLinkedDeque</tt> to instead serialize a snapshot of the |
| * elements obtained by method <tt>toArray</tt>. |
| * |
| * @author Doug Lea |
| * @param <E> |
| * the type of elements held in this collection |
| */ |
| |
| public class ConcurrentDoublyLinkedList<E> extends AbstractCollection<E> |
| implements java.io.Serializable { |
| |
| /* |
| * This is an adaptation of an algorithm described in Paul Martin's "A |
| * Practical Lock-Free Doubly-Linked List". Sun Labs Tech report. The basic |
| * idea is to primarily rely on next-pointers to ensure consistency. |
| * Prev-pointers are in part optimistic, reconstructed using forward |
| * pointers as needed. The main forward list uses a variant of HM-list |
| * algorithm similar to the one used in ConcurrentSkipListMap class, but a |
| * little simpler. It is also basically similar to the approach in Edya |
| * Ladan-Mozes and Nir Shavit "An Optimistic Approach to Lock-Free FIFO |
| * Queues" in DISC04. |
| * |
| * Quoting a summary in Paul Martin's tech report: |
| * |
| * All cleanups work to maintain these invariants: (1) forward pointers are |
| * the ground truth. (2) forward pointers to dead nodes can be improved by |
| * swinging them further forward around the dead node. (2.1) forward |
| * pointers are still correct when pointing to dead nodes, and forward |
| * pointers from dead nodes are left as they were when the node was deleted. |
| * (2.2) multiple dead nodes may point forward to the same node. (3) |
| * backward pointers were correct when they were installed (3.1) backward |
| * pointers are correct when pointing to any node which points forward to |
| * them, but since more than one forward pointer may point to them, the live |
| * one is best. (4) backward pointers that are out of date due to deletion |
| * point to a deleted node, and need to point further back until they point |
| * to the live node that points to their source. (5) backward pointers that |
| * are out of date due to insertion point too far backwards, so shortening |
| * their scope (by searching forward) fixes them. (6) backward pointers from |
| * a dead node cannot be "improved" since there may be no live node pointing |
| * forward to their origin. (However, it does no harm to try to improve them |
| * while racing with a deletion.) |
| * |
| * |
| * Notation guide for local variables n, b, f : a node, its predecessor, and |
| * successor s : some other successor |
| */ |
| |
| // Minor convenience utilities |
| |
| /** |
| * Returns true if given reference is non-null and isn't a header, trailer, |
| * or marker. |
| * |
| * @param n |
| * (possibly null) node |
| * @return true if n exists as a user node |
| */ |
| private static boolean usable(NodeImpl<?> n) { |
| return n != null && !n.isSpecial(); |
| } |
| |
| /** |
| * Throws NullPointerException if argument is null |
| * |
| * @param v |
| * the element |
| */ |
| private static void checkNullArg(Object v) { |
| if (v == null) |
| throw new NullPointerException(); |
| } |
| |
| /** |
| * Returns element unless it is null, in which case throws |
| * NoSuchElementException. |
| * |
| * @param v |
| * the element |
| * @return the element |
| */ |
| private E screenNullResult(E v) { |
| if (v == null) |
| throw new NoSuchElementException(); |
| return v; |
| } |
| |
| /** |
| * Creates an array list and fills it with elements of this list. Used by |
| * toArray. |
| * |
| * @return the arrayList |
| */ |
| private ArrayList<E> toArrayList() { |
| ArrayList<E> c = new ArrayList<E>(); |
| for (NodeImpl<E> n = header.forward(); n != null; n = n.forward()) |
| c.add(n.element); |
| return c; |
| } |
| |
| // Fields and constructors |
| |
| private static final long serialVersionUID = 876323262645176354L; |
| |
| /** |
| * List header. First usable node is at header.forward(). |
| */ |
| private final NodeImpl<E> header; |
| |
| /** |
| * List trailer. Last usable node is at trailer.back(). |
| */ |
| private final NodeImpl<E> trailer; |
| |
| /** |
| * Constructs an empty deque. |
| */ |
| public ConcurrentDoublyLinkedList() { |
| NodeImpl h = new NodeImpl(null, null, null); |
| NodeImpl t = new NodeImpl(null, null, h); |
| h.setNext(t); |
| header = h; |
| trailer = t; |
| } |
| |
| /** |
| * Constructs a deque containing the elements of the specified collection, |
| * in the order they are returned by the collection's iterator. |
| * |
| * @param c |
| * the collection whose elements are to be placed into this |
| * deque. |
| * @throws NullPointerException |
| * if <tt>c</tt> or any element within it is <tt>null</tt> |
| */ |
| public ConcurrentDoublyLinkedList(Collection<? extends E> c) { |
| this(); |
| addAll(c); |
| } |
| |
| /** |
| * Prepends the given element at the beginning of this deque. |
| * |
| * @param o |
| * the element to be inserted at the beginning of this deque. |
| * @throws NullPointerException |
| * if the specified element is <tt>null</tt> |
| */ |
| public Node addFirst(E o) { |
| checkNullArg(o); |
| NodeImpl<E> append; |
| while ((append = header.append(o)) == null) |
| ; |
| |
| return append; |
| } |
| |
| /** |
| * Appends the given element to the end of this deque. This is identical in |
| * function to the <tt>add</tt> method. |
| * |
| * @param o |
| * the element to be inserted at the end of this deque. |
| * @throws NullPointerException |
| * if the specified element is <tt>null</tt> |
| */ |
| public Node addLast(E o) { |
| checkNullArg(o); |
| NodeImpl<E> append; |
| while ((append = trailer.prepend(o)) == null) |
| ; |
| |
| return append; |
| } |
| |
| /** |
| * Prepends the given element at the beginning of this deque. |
| * |
| * @param o |
| * the element to be inserted at the beginning of this deque. |
| * @return <tt>true</tt> always |
| * @throws NullPointerException |
| * if the specified element is <tt>null</tt> |
| */ |
| public boolean offerFirst(E o) { |
| addFirst(o); |
| return true; |
| } |
| |
| /** |
| * Appends the given element to the end of this deque. (Identical in |
| * function to the <tt>add</tt> method; included only for consistency.) |
| * |
| * @param o |
| * the element to be inserted at the end of this deque. |
| * @return <tt>true</tt> always |
| * @throws NullPointerException |
| * if the specified element is <tt>null</tt> |
| */ |
| public boolean offerLast(E o) { |
| addLast(o); |
| return true; |
| } |
| |
| /** |
| * Retrieves, but does not remove, the first element of this deque, or |
| * returns null if this deque is empty. |
| * |
| * @return the first element of this queue, or <tt>null</tt> if empty. |
| */ |
| public E peekFirst() { |
| NodeImpl<E> n = header.successor(); |
| return (n == null) ? null : n.element; |
| } |
| |
| /** |
| * Retrieves, but does not remove, the last element of this deque, or |
| * returns null if this deque is empty. |
| * |
| * @return the last element of this deque, or <tt>null</tt> if empty. |
| */ |
| public E peekLast() { |
| NodeImpl<E> n = trailer.predecessor(); |
| return (n == null) ? null : n.element; |
| } |
| |
| /** |
| * Returns the first element in this deque. |
| * |
| * @return the first element in this deque. |
| * @throws NoSuchElementException |
| * if this deque is empty. |
| */ |
| public E getFirst() { |
| return screenNullResult(peekFirst()); |
| } |
| |
| /** |
| * Returns the last element in this deque. |
| * |
| * @return the last element in this deque. |
| * @throws NoSuchElementException |
| * if this deque is empty. |
| */ |
| public E getLast() { |
| return screenNullResult(peekLast()); |
| } |
| |
| /** |
| * Retrieves and removes the first element of this deque, or returns null if |
| * this deque is empty. |
| * |
| * @return the first element of this deque, or <tt>null</tt> if empty. |
| */ |
| public E pollFirst() { |
| for (;;) { |
| NodeImpl<E> n = header.successor(); |
| if (!usable(n)) |
| return null; |
| if (n.delete()) |
| return n.element; |
| } |
| } |
| |
| /** |
| * Retrieves and removes the last element of this deque, or returns null if |
| * this deque is empty. |
| * |
| * @return the last element of this deque, or <tt>null</tt> if empty. |
| */ |
| public E pollLast() { |
| for (;;) { |
| NodeImpl<E> n = trailer.predecessor(); |
| if (!usable(n)) |
| return null; |
| if (n.delete()) |
| return n.element; |
| } |
| } |
| |
| /** |
| * Removes and returns the first element from this deque. |
| * |
| * @return the first element from this deque. |
| * @throws NoSuchElementException |
| * if this deque is empty. |
| */ |
| public E removeFirst() { |
| return screenNullResult(pollFirst()); |
| } |
| |
| /** |
| * Removes and returns the last element from this deque. |
| * |
| * @return the last element from this deque. |
| * @throws NoSuchElementException |
| * if this deque is empty. |
| */ |
| public E removeLast() { |
| return screenNullResult(pollLast()); |
| } |
| |
| // *** Queue and stack methods *** |
| public boolean offer(E e) { |
| return offerLast(e); |
| } |
| |
| public boolean add(E e) { |
| return offerLast(e); |
| } |
| |
| public E poll() { |
| return pollFirst(); |
| } |
| |
| public E remove() { |
| return removeFirst(); |
| } |
| |
| public E peek() { |
| return peekFirst(); |
| } |
| |
| public E element() { |
| return getFirst(); |
| } |
| |
| public void push(E e) { |
| addFirst(e); |
| } |
| |
| public E pop() { |
| return removeFirst(); |
| } |
| |
| /** |
| * Removes the first element <tt>e</tt> such that <tt>o.equals(e)</tt>, |
| * if such an element exists in this deque. If the deque does not contain |
| * the element, it is unchanged. |
| * |
| * @param o |
| * element to be removed from this deque, if present. |
| * @return <tt>true</tt> if the deque contained the specified element. |
| * @throws NullPointerException |
| * if the specified element is <tt>null</tt> |
| */ |
| public boolean removeFirstOccurrence(Object o) { |
| checkNullArg(o); |
| for (;;) { |
| NodeImpl<E> n = header.forward(); |
| for (;;) { |
| if (n == null) |
| return false; |
| if (o.equals(n.element)) { |
| if (n.delete()) |
| return true; |
| else |
| break; // restart if interference |
| } |
| n = n.forward(); |
| } |
| } |
| } |
| |
| /** |
| * Removes the last element <tt>e</tt> such that <tt>o.equals(e)</tt>, |
| * if such an element exists in this deque. If the deque does not contain |
| * the element, it is unchanged. |
| * |
| * @param o |
| * element to be removed from this deque, if present. |
| * @return <tt>true</tt> if the deque contained the specified element. |
| * @throws NullPointerException |
| * if the specified element is <tt>null</tt> |
| */ |
| public boolean removeLastOccurrence(Object o) { |
| checkNullArg(o); |
| for (;;) { |
| NodeImpl<E> s = trailer; |
| for (;;) { |
| NodeImpl<E> n = s.back(); |
| if (s.isDeleted() || (n != null && n.successor() != s)) |
| break; // restart if pred link is suspect. |
| if (n == null) |
| return false; |
| if (o.equals(n.element)) { |
| if (n.delete()) |
| return true; |
| else |
| break; // restart if interference |
| } |
| s = n; |
| } |
| } |
| } |
| |
| /** |
| * Returns <tt>true</tt> if this deque contains at least one element |
| * <tt>e</tt> such that <tt>o.equals(e)</tt>. |
| * |
| * @param o |
| * element whose presence in this deque is to be tested. |
| * @return <tt>true</tt> if this deque contains the specified element. |
| */ |
| public boolean contains(Object o) { |
| if (o == null) |
| return false; |
| for (NodeImpl<E> n = header.forward(); n != null; n = n.forward()) |
| if (o.equals(n.element)) |
| return true; |
| return false; |
| } |
| |
| /** |
| * Returns <tt>true</tt> if this collection contains no elements. |
| * <p> |
| * |
| * @return <tt>true</tt> if this collection contains no elements. |
| */ |
| public boolean isEmpty() { |
| return !usable(header.successor()); |
| } |
| |
| /** |
| * Returns the number of elements in this deque. If this deque contains more |
| * than <tt>Integer.MAX_VALUE</tt> elements, it returns |
| * <tt>Integer.MAX_VALUE</tt>. |
| * |
| * <p> |
| * Beware that, unlike in most collections, this method is <em>NOT</em> a |
| * constant-time operation. Because of the asynchronous nature of these |
| * deques, determining the current number of elements requires traversing |
| * them all to count them. Additionally, it is possible for the size to |
| * change during execution of this method, in which case the returned result |
| * will be inaccurate. Thus, this method is typically not very useful in |
| * concurrent applications. |
| * |
| * @return the number of elements in this deque. |
| */ |
| public int size() { |
| long count = 0; |
| for (NodeImpl<E> n = header.forward(); n != null; n = n.forward()) |
| ++count; |
| return (count >= Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int) count; |
| } |
| |
| /** |
| * Removes the first element <tt>e</tt> such that <tt>o.equals(e)</tt>, |
| * if such an element exists in this deque. If the deque does not contain |
| * the element, it is unchanged. |
| * |
| * @param o |
| * element to be removed from this deque, if present. |
| * @return <tt>true</tt> if the deque contained the specified element. |
| * @throws NullPointerException |
| * if the specified element is <tt>null</tt> |
| */ |
| public boolean remove(Object o) { |
| return removeFirstOccurrence(o); |
| } |
| |
| /** |
| * Appends all of the elements in the specified collection to the end of |
| * this deque, in the order that they are returned by the specified |
| * collection's iterator. The behavior of this operation is undefined if the |
| * specified collection is modified while the operation is in progress. |
| * (This implies that the behavior of this call is undefined if the |
| * specified Collection is this deque, and this deque is nonempty.) |
| * |
| * @param c |
| * the elements to be inserted into this deque. |
| * @return <tt>true</tt> if this deque changed as a result of the call. |
| * @throws NullPointerException |
| * if <tt>c</tt> or any element within it is <tt>null</tt> |
| */ |
| public boolean addAll(Collection<? extends E> c) { |
| Iterator<? extends E> it = c.iterator(); |
| if (!it.hasNext()) |
| return false; |
| do { |
| addLast(it.next()); |
| } while (it.hasNext()); |
| return true; |
| } |
| |
| /** |
| * Removes all of the elements from this deque. |
| */ |
| public void clear() { |
| while (pollFirst() != null) |
| ; |
| } |
| |
| /** |
| * Returns an array containing all of the elements in this deque in the |
| * correct order. |
| * |
| * @return an array containing all of the elements in this deque in the |
| * correct order. |
| */ |
| public Object[] toArray() { |
| return toArrayList().toArray(); |
| } |
| |
| /** |
| * Returns an array containing all of the elements in this deque in the |
| * correct order; the runtime type of the returned array is that of the |
| * specified array. If the deque fits in the specified array, it is returned |
| * therein. Otherwise, a new array is allocated with the runtime type of the |
| * specified array and the size of this deque. |
| * <p> |
| * |
| * If the deque fits in the specified array with room to spare (i.e., the |
| * array has more elements than the deque), the element in the array |
| * immediately following the end of the collection is set to null. This is |
| * useful in determining the length of the deque <i>only</i> if the caller |
| * knows that the deque does not contain any null elements. |
| * |
| * @param a |
| * the array into which the elements of the deque are to be |
| * stored, if it is big enough; otherwise, a new array of the |
| * same runtime type is allocated for this purpose. |
| * @return an array containing the elements of the deque. |
| * @throws ArrayStoreException |
| * if the runtime type of a is not a supertype of the runtime |
| * type of every element in this deque. |
| * @throws NullPointerException |
| * if the specified array is null. |
| */ |
| public <T> T[] toArray(T[] a) { |
| return toArrayList().toArray(a); |
| } |
| |
| /** |
| * Returns a weakly consistent iterator over the elements in this deque, in |
| * first-to-last order. The <tt>next</tt> method returns elements |
| * reflecting the state of the deque at some point at or since the creation |
| * of the iterator. The method does <em>not</em> throw |
| * {@link ConcurrentModificationException}, and may proceed concurrently |
| * with other operations. |
| * |
| * @return an iterator over the elements in this deque |
| */ |
| public Iterator<E> iterator() { |
| return new CLDIterator(); |
| } |
| |
| final class CLDIterator implements Iterator<E> { |
| NodeImpl<E> last; |
| |
| NodeImpl<E> next = header.forward(); |
| |
| public boolean hasNext() { |
| return next != null; |
| } |
| |
| public E next() { |
| NodeImpl<E> l = last = next; |
| if (l == null) |
| throw new NoSuchElementException(); |
| next = next.forward(); |
| return l.element; |
| } |
| |
| public void remove() { |
| NodeImpl<E> l = last; |
| if (l == null) |
| throw new IllegalStateException(); |
| while (!l.delete() && !l.isDeleted()) |
| ; |
| } |
| } |
| |
| public interface Node { |
| public boolean remove(); |
| } |
| |
| } |
| |
| |
| |
| /** |
| * Linked Nodes. As a minor efficiency hack, this class opportunistically |
| * inherits from AtomicReference, with the atomic ref used as the "next" |
| * link. |
| * |
| * Nodes are in doubly-linked lists. There are three kinds of special nodes, |
| * distinguished by: * The list header has a null prev link * The list |
| * trailer has a null next link * A deletion marker has a prev link pointing |
| * to itself. All three kinds of special nodes have null element fields. |
| * |
| * Regular nodes have non-null element, next, and prev fields. To avoid |
| * visible inconsistencies when deletions overlap element replacement, |
| * replacements are done by replacing the node, not just setting the |
| * element. |
| * |
| * Nodes can be traversed by read-only ConcurrentLinkedDeque class |
| * operations just by following raw next pointers, so long as they ignore |
| * any special nodes seen along the way. (This is automated in method |
| * forward.) However, traversal using prev pointers is not guaranteed to see |
| * all live nodes since a prev pointer of a deleted node can become |
| * unrecoverably stale. |
| */ |
| |
| class NodeImpl<E> extends AtomicReference<NodeImpl<E>> |
| implements ConcurrentDoublyLinkedList.Node { |
| |
| private volatile NodeImpl<E> prev; |
| |
| final E element; |
| |
| /** Creates a node with given contents */ |
| NodeImpl(E element, NodeImpl<E> next, NodeImpl<E> prev) { |
| super(next); |
| this.prev = prev; |
| this.element = element; |
| } |
| |
| /** Creates a marker node with given successor */ |
| NodeImpl(NodeImpl<E> next) { |
| super(next); |
| this.prev = this; |
| this.element = null; |
| } |
| |
| @Override |
| public boolean remove() { |
| if (isDeleted()) { |
| return false; |
| } |
| |
| while (!delete() && !isDeleted()) |
| ; |
| |
| return true; |
| } |
| |
| /** |
| * Gets next link (which is actually the value held as atomic |
| * reference). |
| */ |
| private NodeImpl<E> getNext() { |
| return get(); |
| } |
| |
| /** |
| * Sets next link |
| * |
| * @param n |
| * the next node |
| */ |
| void setNext(NodeImpl<E> n) { |
| set(n); |
| } |
| |
| /** |
| * compareAndSet next link |
| */ |
| private boolean casNext(NodeImpl<E> cmp, NodeImpl<E> val) { |
| return compareAndSet(cmp, val); |
| } |
| |
| /** |
| * Gets prev link |
| */ |
| private NodeImpl<E> getPrev() { |
| return prev; |
| } |
| |
| /** |
| * Sets prev link |
| * |
| * @param b |
| * the previous node |
| */ |
| void setPrev(NodeImpl<E> b) { |
| prev = b; |
| } |
| |
| /** |
| * Returns true if this is a header, trailer, or marker node |
| */ |
| boolean isSpecial() { |
| return element == null; |
| } |
| |
| /** |
| * Returns true if this is a trailer node |
| */ |
| boolean isTrailer() { |
| return getNext() == null; |
| } |
| |
| /** |
| * Returns true if this is a header node |
| */ |
| boolean isHeader() { |
| return getPrev() == null; |
| } |
| |
| /** |
| * Returns true if this is a marker node |
| */ |
| boolean isMarker() { |
| return getPrev() == this; |
| } |
| |
| /** |
| * Returns true if this node is followed by a marker, meaning that it is |
| * deleted. |
| * |
| * @return true if this node is deleted |
| */ |
| boolean isDeleted() { |
| NodeImpl<E> f = getNext(); |
| return f != null && f.isMarker(); |
| } |
| |
| /** |
| * Returns next node, ignoring deletion marker |
| */ |
| private NodeImpl<E> nextNonmarker() { |
| NodeImpl<E> f = getNext(); |
| return (f == null || !f.isMarker()) ? f : f.getNext(); |
| } |
| |
| /** |
| * Returns the next non-deleted node, swinging next pointer around any |
| * encountered deleted nodes, and also patching up successor''s prev |
| * link to point back to this. Returns null if this node is trailer so |
| * has no successor. |
| * |
| * @return successor, or null if no such |
| */ |
| NodeImpl<E> successor() { |
| NodeImpl<E> f = nextNonmarker(); |
| for (;;) { |
| if (f == null) |
| return null; |
| if (!f.isDeleted()) { |
| if (f.getPrev() != this && !isDeleted()) |
| f.setPrev(this); // relink f's prev |
| return f; |
| } |
| NodeImpl<E> s = f.nextNonmarker(); |
| if (f == getNext()) |
| casNext(f, s); // unlink f |
| f = s; |
| } |
| } |
| |
| /** |
| * Returns the apparent predecessor of target by searching forward for |
| * it starting at this node, patching up pointers while traversing. Used |
| * by predecessor(). |
| * |
| * @return target's predecessor, or null if not found |
| */ |
| private NodeImpl<E> findPredecessorOf(NodeImpl<E> target) { |
| NodeImpl<E> n = this; |
| for (;;) { |
| NodeImpl<E> f = n.successor(); |
| if (f == target) |
| return n; |
| if (f == null) |
| return null; |
| n = f; |
| } |
| } |
| |
| /** |
| * Returns the previous non-deleted node, patching up pointers as |
| * needed. Returns null if this node is header so has no successor. May |
| * also return null if this node is deleted, so doesn't have a distinct |
| * predecessor. |
| * |
| * @return predecessor or null if not found |
| */ |
| NodeImpl<E> predecessor() { |
| NodeImpl<E> n = this; |
| for (;;) { |
| NodeImpl<E> b = n.getPrev(); |
| if (b == null) |
| return n.findPredecessorOf(this); |
| NodeImpl<E> s = b.getNext(); |
| if (s == this) |
| return b; |
| if (s == null || !s.isMarker()) { |
| NodeImpl<E> p = b.findPredecessorOf(this); |
| if (p != null) |
| return p; |
| } |
| n = b; |
| } |
| } |
| |
| /** |
| * Returns the next node containing a nondeleted user element. Use for |
| * forward list traversal. |
| * |
| * @return successor, or null if no such |
| */ |
| NodeImpl<E> forward() { |
| NodeImpl<E> f = successor(); |
| return (f == null || f.isSpecial()) ? null : f; |
| } |
| |
| /** |
| * Returns previous node containing a nondeleted user element, if |
| * possible. Use for backward list traversal, but beware that if this |
| * method is called from a deleted node, it might not be able to |
| * determine a usable predecessor. |
| * |
| * @return predecessor, or null if no such could be found |
| */ |
| NodeImpl<E> back() { |
| NodeImpl<E> f = predecessor(); |
| return (f == null || f.isSpecial()) ? null : f; |
| } |
| |
| /** |
| * Tries to insert a node holding element as successor, failing if this |
| * node is deleted. |
| * |
| * @param element |
| * the element |
| * @return the new node, or null on failure. |
| */ |
| NodeImpl<E> append(E element) { |
| for (;;) { |
| NodeImpl<E> f = getNext(); |
| if (f == null || f.isMarker()) |
| return null; |
| NodeImpl<E> x = new NodeImpl<E>(element, f, this); |
| if (casNext(f, x)) { |
| f.setPrev(x); // optimistically link |
| return x; |
| } |
| } |
| } |
| |
| /** |
| * Tries to insert a node holding element as predecessor, failing if no |
| * live predecessor can be found to link to. |
| * |
| * @param element |
| * the element |
| * @return the new node, or null on failure. |
| */ |
| NodeImpl<E> prepend(E element) { |
| for (;;) { |
| NodeImpl<E> b = predecessor(); |
| if (b == null) |
| return null; |
| NodeImpl<E> x = new NodeImpl<E>(element, this, b); |
| if (b.casNext(this, x)) { |
| setPrev(x); // optimistically link |
| return x; |
| } |
| } |
| } |
| |
| /** |
| * Tries to mark this node as deleted, failing if already deleted or if |
| * this node is header or trailer |
| * |
| * @return true if successful |
| */ |
| boolean delete() { |
| NodeImpl<E> b = getPrev(); |
| NodeImpl<E> f = getNext(); |
| if (b != null && f != null && !f.isMarker() |
| && casNext(f, new NodeImpl(f))) { |
| if (b.casNext(this, f)) |
| f.setPrev(b); |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Tries to insert a node holding element to replace this node. failing |
| * if already deleted. |
| * |
| * @param newElement |
| * the new element |
| * @return the new node, or null on failure. |
| */ |
| NodeImpl<E> replace(E newElement) { |
| for (;;) { |
| NodeImpl<E> b = getPrev(); |
| NodeImpl<E> f = getNext(); |
| if (b == null || f == null || f.isMarker()) |
| return null; |
| NodeImpl<E> x = new NodeImpl<E>(newElement, f, b); |
| if (casNext(f, new NodeImpl(x))) { |
| b.successor(); // to relink b |
| x.successor(); // to relink f |
| return x; |
| } |
| } |
| } |
| } |