jaroslav@597: /* jaroslav@597: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. jaroslav@597: * jaroslav@597: * This code is free software; you can redistribute it and/or modify it jaroslav@597: * under the terms of the GNU General Public License version 2 only, as jaroslav@597: * published by the Free Software Foundation. Oracle designates this jaroslav@597: * particular file as subject to the "Classpath" exception as provided jaroslav@597: * by Oracle in the LICENSE file that accompanied this code. jaroslav@597: * jaroslav@597: * This code is distributed in the hope that it will be useful, but WITHOUT jaroslav@597: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or jaroslav@597: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License jaroslav@597: * version 2 for more details (a copy is included in the LICENSE file that jaroslav@597: * accompanied this code). jaroslav@597: * jaroslav@597: * You should have received a copy of the GNU General Public License version jaroslav@597: * 2 along with this work; if not, write to the Free Software Foundation, jaroslav@597: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. jaroslav@597: * jaroslav@597: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA jaroslav@597: * or visit www.oracle.com if you need additional information or have any jaroslav@597: * questions. jaroslav@597: */ jaroslav@597: jaroslav@597: /* jaroslav@597: * This file is available under and governed by the GNU General Public jaroslav@597: * License version 2 only, as published by the Free Software Foundation. jaroslav@597: * However, the following notice accompanied the original version of this jaroslav@597: * file: jaroslav@597: * jaroslav@597: * Written by Josh Bloch of Google Inc. and released to the public domain, jaroslav@597: * as explained at http://creativecommons.org/publicdomain/zero/1.0/. jaroslav@597: */ jaroslav@597: jaroslav@597: package java.util; jaroslav@597: import java.io.*; jaroslav@597: jaroslav@597: /** jaroslav@597: * Resizable-array implementation of the {@link Deque} interface. Array jaroslav@597: * deques have no capacity restrictions; they grow as necessary to support jaroslav@597: * usage. They are not thread-safe; in the absence of external jaroslav@597: * synchronization, they do not support concurrent access by multiple threads. jaroslav@597: * Null elements are prohibited. This class is likely to be faster than jaroslav@597: * {@link Stack} when used as a stack, and faster than {@link LinkedList} jaroslav@597: * when used as a queue. jaroslav@597: * jaroslav@597: *

Most ArrayDeque operations run in amortized constant time. jaroslav@597: * Exceptions include {@link #remove(Object) remove}, {@link jaroslav@597: * #removeFirstOccurrence removeFirstOccurrence}, {@link #removeLastOccurrence jaroslav@597: * removeLastOccurrence}, {@link #contains contains}, {@link #iterator jaroslav@597: * iterator.remove()}, and the bulk operations, all of which run in linear jaroslav@597: * time. jaroslav@597: * jaroslav@597: *

The iterators returned by this class's iterator method are jaroslav@597: * fail-fast: If the deque is modified at any time after the iterator jaroslav@597: * is created, in any way except through the iterator's own remove jaroslav@597: * method, the iterator will generally throw a {@link jaroslav@597: * ConcurrentModificationException}. Thus, in the face of concurrent jaroslav@597: * modification, the iterator fails quickly and cleanly, rather than risking jaroslav@597: * arbitrary, non-deterministic behavior at an undetermined time in the jaroslav@597: * future. jaroslav@597: * jaroslav@597: *

Note that the fail-fast behavior of an iterator cannot be guaranteed jaroslav@597: * as it is, generally speaking, impossible to make any hard guarantees in the jaroslav@597: * presence of unsynchronized concurrent modification. Fail-fast iterators jaroslav@597: * throw ConcurrentModificationException on a best-effort basis. jaroslav@597: * Therefore, it would be wrong to write a program that depended on this jaroslav@597: * exception for its correctness: the fail-fast behavior of iterators jaroslav@597: * should be used only to detect bugs. jaroslav@597: * jaroslav@597: *

This class and its iterator implement all of the jaroslav@597: * optional methods of the {@link Collection} and {@link jaroslav@597: * Iterator} interfaces. jaroslav@597: * jaroslav@597: *

This class is a member of the jaroslav@597: * jaroslav@597: * Java Collections Framework. jaroslav@597: * jaroslav@597: * @author Josh Bloch and Doug Lea jaroslav@597: * @since 1.6 jaroslav@597: * @param the type of elements held in this collection jaroslav@597: */ jaroslav@597: public class ArrayDeque extends AbstractCollection jaroslav@597: implements Deque, Cloneable, Serializable jaroslav@597: { jaroslav@597: /** jaroslav@597: * The array in which the elements of the deque are stored. jaroslav@597: * The capacity of the deque is the length of this array, which is jaroslav@597: * always a power of two. The array is never allowed to become jaroslav@597: * full, except transiently within an addX method where it is jaroslav@597: * resized (see doubleCapacity) immediately upon becoming full, jaroslav@597: * thus avoiding head and tail wrapping around to equal each jaroslav@597: * other. We also guarantee that all array cells not holding jaroslav@597: * deque elements are always null. jaroslav@597: */ jaroslav@597: private transient E[] elements; jaroslav@597: jaroslav@597: /** jaroslav@597: * The index of the element at the head of the deque (which is the jaroslav@597: * element that would be removed by remove() or pop()); or an jaroslav@597: * arbitrary number equal to tail if the deque is empty. jaroslav@597: */ jaroslav@597: private transient int head; jaroslav@597: jaroslav@597: /** jaroslav@597: * The index at which the next element would be added to the tail jaroslav@597: * of the deque (via addLast(E), add(E), or push(E)). jaroslav@597: */ jaroslav@597: private transient int tail; jaroslav@597: jaroslav@597: /** jaroslav@597: * The minimum capacity that we'll use for a newly created deque. jaroslav@597: * Must be a power of 2. jaroslav@597: */ jaroslav@597: private static final int MIN_INITIAL_CAPACITY = 8; jaroslav@597: jaroslav@597: // ****** Array allocation and resizing utilities ****** jaroslav@597: jaroslav@597: /** jaroslav@597: * Allocate empty array to hold the given number of elements. jaroslav@597: * jaroslav@597: * @param numElements the number of elements to hold jaroslav@597: */ jaroslav@597: private void allocateElements(int numElements) { jaroslav@597: int initialCapacity = MIN_INITIAL_CAPACITY; jaroslav@597: // Find the best power of two to hold elements. jaroslav@597: // Tests "<=" because arrays aren't kept full. jaroslav@597: if (numElements >= initialCapacity) { jaroslav@597: initialCapacity = numElements; jaroslav@597: initialCapacity |= (initialCapacity >>> 1); jaroslav@597: initialCapacity |= (initialCapacity >>> 2); jaroslav@597: initialCapacity |= (initialCapacity >>> 4); jaroslav@597: initialCapacity |= (initialCapacity >>> 8); jaroslav@597: initialCapacity |= (initialCapacity >>> 16); jaroslav@597: initialCapacity++; jaroslav@597: jaroslav@597: if (initialCapacity < 0) // Too many elements, must back off jaroslav@597: initialCapacity >>>= 1;// Good luck allocating 2 ^ 30 elements jaroslav@597: } jaroslav@597: elements = (E[]) new Object[initialCapacity]; jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Double the capacity of this deque. Call only when full, i.e., jaroslav@597: * when head and tail have wrapped around to become equal. jaroslav@597: */ jaroslav@597: private void doubleCapacity() { jaroslav@597: assert head == tail; jaroslav@597: int p = head; jaroslav@597: int n = elements.length; jaroslav@597: int r = n - p; // number of elements to the right of p jaroslav@597: int newCapacity = n << 1; jaroslav@597: if (newCapacity < 0) jaroslav@597: throw new IllegalStateException("Sorry, deque too big"); jaroslav@597: Object[] a = new Object[newCapacity]; jaroslav@597: System.arraycopy(elements, p, a, 0, r); jaroslav@597: System.arraycopy(elements, 0, a, r, p); jaroslav@597: elements = (E[])a; jaroslav@597: head = 0; jaroslav@597: tail = n; jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Copies the elements from our element array into the specified array, jaroslav@597: * in order (from first to last element in the deque). It is assumed jaroslav@597: * that the array is large enough to hold all elements in the deque. jaroslav@597: * jaroslav@597: * @return its argument jaroslav@597: */ jaroslav@597: private T[] copyElements(T[] a) { jaroslav@597: if (head < tail) { jaroslav@597: System.arraycopy(elements, head, a, 0, size()); jaroslav@597: } else if (head > tail) { jaroslav@597: int headPortionLen = elements.length - head; jaroslav@597: System.arraycopy(elements, head, a, 0, headPortionLen); jaroslav@597: System.arraycopy(elements, 0, a, headPortionLen, tail); jaroslav@597: } jaroslav@597: return a; jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Constructs an empty array deque with an initial capacity jaroslav@597: * sufficient to hold 16 elements. jaroslav@597: */ jaroslav@597: public ArrayDeque() { jaroslav@597: elements = (E[]) new Object[16]; jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Constructs an empty array deque with an initial capacity jaroslav@597: * sufficient to hold the specified number of elements. jaroslav@597: * jaroslav@597: * @param numElements lower bound on initial capacity of the deque jaroslav@597: */ jaroslav@597: public ArrayDeque(int numElements) { jaroslav@597: allocateElements(numElements); jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Constructs a deque containing the elements of the specified jaroslav@597: * collection, in the order they are returned by the collection's jaroslav@597: * iterator. (The first element returned by the collection's jaroslav@597: * iterator becomes the first element, or front of the jaroslav@597: * deque.) jaroslav@597: * jaroslav@597: * @param c the collection whose elements are to be placed into the deque jaroslav@597: * @throws NullPointerException if the specified collection is null jaroslav@597: */ jaroslav@597: public ArrayDeque(Collection c) { jaroslav@597: allocateElements(c.size()); jaroslav@597: addAll(c); jaroslav@597: } jaroslav@597: jaroslav@597: // The main insertion and extraction methods are addFirst, jaroslav@597: // addLast, pollFirst, pollLast. The other methods are defined in jaroslav@597: // terms of these. jaroslav@597: jaroslav@597: /** jaroslav@597: * Inserts the specified element at the front of this deque. jaroslav@597: * jaroslav@597: * @param e the element to add jaroslav@597: * @throws NullPointerException if the specified element is null jaroslav@597: */ jaroslav@597: public void addFirst(E e) { jaroslav@597: if (e == null) jaroslav@597: throw new NullPointerException(); jaroslav@597: elements[head = (head - 1) & (elements.length - 1)] = e; jaroslav@597: if (head == tail) jaroslav@597: doubleCapacity(); jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Inserts the specified element at the end of this deque. jaroslav@597: * jaroslav@597: *

This method is equivalent to {@link #add}. jaroslav@597: * jaroslav@597: * @param e the element to add jaroslav@597: * @throws NullPointerException if the specified element is null jaroslav@597: */ jaroslav@597: public void addLast(E e) { jaroslav@597: if (e == null) jaroslav@597: throw new NullPointerException(); jaroslav@597: elements[tail] = e; jaroslav@597: if ( (tail = (tail + 1) & (elements.length - 1)) == head) jaroslav@597: doubleCapacity(); jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Inserts the specified element at the front of this deque. jaroslav@597: * jaroslav@597: * @param e the element to add jaroslav@597: * @return true (as specified by {@link Deque#offerFirst}) jaroslav@597: * @throws NullPointerException if the specified element is null jaroslav@597: */ jaroslav@597: public boolean offerFirst(E e) { jaroslav@597: addFirst(e); jaroslav@597: return true; jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Inserts the specified element at the end of this deque. jaroslav@597: * jaroslav@597: * @param e the element to add jaroslav@597: * @return true (as specified by {@link Deque#offerLast}) jaroslav@597: * @throws NullPointerException if the specified element is null jaroslav@597: */ jaroslav@597: public boolean offerLast(E e) { jaroslav@597: addLast(e); jaroslav@597: return true; jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * @throws NoSuchElementException {@inheritDoc} jaroslav@597: */ jaroslav@597: public E removeFirst() { jaroslav@597: E x = pollFirst(); jaroslav@597: if (x == null) jaroslav@597: throw new NoSuchElementException(); jaroslav@597: return x; jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * @throws NoSuchElementException {@inheritDoc} jaroslav@597: */ jaroslav@597: public E removeLast() { jaroslav@597: E x = pollLast(); jaroslav@597: if (x == null) jaroslav@597: throw new NoSuchElementException(); jaroslav@597: return x; jaroslav@597: } jaroslav@597: jaroslav@597: public E pollFirst() { jaroslav@597: int h = head; jaroslav@597: E result = elements[h]; // Element is null if deque empty jaroslav@597: if (result == null) jaroslav@597: return null; jaroslav@597: elements[h] = null; // Must null out slot jaroslav@597: head = (h + 1) & (elements.length - 1); jaroslav@597: return result; jaroslav@597: } jaroslav@597: jaroslav@597: public E pollLast() { jaroslav@597: int t = (tail - 1) & (elements.length - 1); jaroslav@597: E result = elements[t]; jaroslav@597: if (result == null) jaroslav@597: return null; jaroslav@597: elements[t] = null; jaroslav@597: tail = t; jaroslav@597: return result; jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * @throws NoSuchElementException {@inheritDoc} jaroslav@597: */ jaroslav@597: public E getFirst() { jaroslav@597: E x = elements[head]; jaroslav@597: if (x == null) jaroslav@597: throw new NoSuchElementException(); jaroslav@597: return x; jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * @throws NoSuchElementException {@inheritDoc} jaroslav@597: */ jaroslav@597: public E getLast() { jaroslav@597: E x = elements[(tail - 1) & (elements.length - 1)]; jaroslav@597: if (x == null) jaroslav@597: throw new NoSuchElementException(); jaroslav@597: return x; jaroslav@597: } jaroslav@597: jaroslav@597: public E peekFirst() { jaroslav@597: return elements[head]; // elements[head] is null if deque empty jaroslav@597: } jaroslav@597: jaroslav@597: public E peekLast() { jaroslav@597: return elements[(tail - 1) & (elements.length - 1)]; jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Removes the first occurrence of the specified element in this jaroslav@597: * deque (when traversing the deque from head to tail). jaroslav@597: * If the deque does not contain the element, it is unchanged. jaroslav@597: * More formally, removes the first element e such that jaroslav@597: * o.equals(e) (if such an element exists). jaroslav@597: * Returns true if this deque contained the specified element jaroslav@597: * (or equivalently, if this deque changed as a result of the call). jaroslav@597: * jaroslav@597: * @param o element to be removed from this deque, if present jaroslav@597: * @return true if the deque contained the specified element jaroslav@597: */ jaroslav@597: public boolean removeFirstOccurrence(Object o) { jaroslav@597: if (o == null) jaroslav@597: return false; jaroslav@597: int mask = elements.length - 1; jaroslav@597: int i = head; jaroslav@597: E x; jaroslav@597: while ( (x = elements[i]) != null) { jaroslav@597: if (o.equals(x)) { jaroslav@597: delete(i); jaroslav@597: return true; jaroslav@597: } jaroslav@597: i = (i + 1) & mask; jaroslav@597: } jaroslav@597: return false; jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Removes the last occurrence of the specified element in this jaroslav@597: * deque (when traversing the deque from head to tail). jaroslav@597: * If the deque does not contain the element, it is unchanged. jaroslav@597: * More formally, removes the last element e such that jaroslav@597: * o.equals(e) (if such an element exists). jaroslav@597: * Returns true if this deque contained the specified element jaroslav@597: * (or equivalently, if this deque changed as a result of the call). jaroslav@597: * jaroslav@597: * @param o element to be removed from this deque, if present jaroslav@597: * @return true if the deque contained the specified element jaroslav@597: */ jaroslav@597: public boolean removeLastOccurrence(Object o) { jaroslav@597: if (o == null) jaroslav@597: return false; jaroslav@597: int mask = elements.length - 1; jaroslav@597: int i = (tail - 1) & mask; jaroslav@597: E x; jaroslav@597: while ( (x = elements[i]) != null) { jaroslav@597: if (o.equals(x)) { jaroslav@597: delete(i); jaroslav@597: return true; jaroslav@597: } jaroslav@597: i = (i - 1) & mask; jaroslav@597: } jaroslav@597: return false; jaroslav@597: } jaroslav@597: jaroslav@597: // *** Queue methods *** jaroslav@597: jaroslav@597: /** jaroslav@597: * Inserts the specified element at the end of this deque. jaroslav@597: * jaroslav@597: *

This method is equivalent to {@link #addLast}. jaroslav@597: * jaroslav@597: * @param e the element to add jaroslav@597: * @return true (as specified by {@link Collection#add}) jaroslav@597: * @throws NullPointerException if the specified element is null jaroslav@597: */ jaroslav@597: public boolean add(E e) { jaroslav@597: addLast(e); jaroslav@597: return true; jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Inserts the specified element at the end of this deque. jaroslav@597: * jaroslav@597: *

This method is equivalent to {@link #offerLast}. jaroslav@597: * jaroslav@597: * @param e the element to add jaroslav@597: * @return true (as specified by {@link Queue#offer}) jaroslav@597: * @throws NullPointerException if the specified element is null jaroslav@597: */ jaroslav@597: public boolean offer(E e) { jaroslav@597: return offerLast(e); jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Retrieves and removes the head of the queue represented by this deque. jaroslav@597: * jaroslav@597: * This method differs from {@link #poll poll} only in that it throws an jaroslav@597: * exception if this deque is empty. jaroslav@597: * jaroslav@597: *

This method is equivalent to {@link #removeFirst}. jaroslav@597: * jaroslav@597: * @return the head of the queue represented by this deque jaroslav@597: * @throws NoSuchElementException {@inheritDoc} jaroslav@597: */ jaroslav@597: public E remove() { jaroslav@597: return removeFirst(); jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Retrieves and removes the head of the queue represented by this deque jaroslav@597: * (in other words, the first element of this deque), or returns jaroslav@597: * null if this deque is empty. jaroslav@597: * jaroslav@597: *

This method is equivalent to {@link #pollFirst}. jaroslav@597: * jaroslav@597: * @return the head of the queue represented by this deque, or jaroslav@597: * null if this deque is empty jaroslav@597: */ jaroslav@597: public E poll() { jaroslav@597: return pollFirst(); jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Retrieves, but does not remove, the head of the queue represented by jaroslav@597: * this deque. This method differs from {@link #peek peek} only in jaroslav@597: * that it throws an exception if this deque is empty. jaroslav@597: * jaroslav@597: *

This method is equivalent to {@link #getFirst}. jaroslav@597: * jaroslav@597: * @return the head of the queue represented by this deque jaroslav@597: * @throws NoSuchElementException {@inheritDoc} jaroslav@597: */ jaroslav@597: public E element() { jaroslav@597: return getFirst(); jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Retrieves, but does not remove, the head of the queue represented by jaroslav@597: * this deque, or returns null if this deque is empty. jaroslav@597: * jaroslav@597: *

This method is equivalent to {@link #peekFirst}. jaroslav@597: * jaroslav@597: * @return the head of the queue represented by this deque, or jaroslav@597: * null if this deque is empty jaroslav@597: */ jaroslav@597: public E peek() { jaroslav@597: return peekFirst(); jaroslav@597: } jaroslav@597: jaroslav@597: // *** Stack methods *** jaroslav@597: jaroslav@597: /** jaroslav@597: * Pushes an element onto the stack represented by this deque. In other jaroslav@597: * words, inserts the element at the front of this deque. jaroslav@597: * jaroslav@597: *

This method is equivalent to {@link #addFirst}. jaroslav@597: * jaroslav@597: * @param e the element to push jaroslav@597: * @throws NullPointerException if the specified element is null jaroslav@597: */ jaroslav@597: public void push(E e) { jaroslav@597: addFirst(e); jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Pops an element from the stack represented by this deque. In other jaroslav@597: * words, removes and returns the first element of this deque. jaroslav@597: * jaroslav@597: *

This method is equivalent to {@link #removeFirst()}. jaroslav@597: * jaroslav@597: * @return the element at the front of this deque (which is the top jaroslav@597: * of the stack represented by this deque) jaroslav@597: * @throws NoSuchElementException {@inheritDoc} jaroslav@597: */ jaroslav@597: public E pop() { jaroslav@597: return removeFirst(); jaroslav@597: } jaroslav@597: jaroslav@597: private void checkInvariants() { jaroslav@597: assert elements[tail] == null; jaroslav@597: assert head == tail ? elements[head] == null : jaroslav@597: (elements[head] != null && jaroslav@597: elements[(tail - 1) & (elements.length - 1)] != null); jaroslav@597: assert elements[(head - 1) & (elements.length - 1)] == null; jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Removes the element at the specified position in the elements array, jaroslav@597: * adjusting head and tail as necessary. This can result in motion of jaroslav@597: * elements backwards or forwards in the array. jaroslav@597: * jaroslav@597: *

This method is called delete rather than remove to emphasize jaroslav@597: * that its semantics differ from those of {@link List#remove(int)}. jaroslav@597: * jaroslav@597: * @return true if elements moved backwards jaroslav@597: */ jaroslav@597: private boolean delete(int i) { jaroslav@597: checkInvariants(); jaroslav@597: final E[] elements = this.elements; jaroslav@597: final int mask = elements.length - 1; jaroslav@597: final int h = head; jaroslav@597: final int t = tail; jaroslav@597: final int front = (i - h) & mask; jaroslav@597: final int back = (t - i) & mask; jaroslav@597: jaroslav@597: // Invariant: head <= i < tail mod circularity jaroslav@597: if (front >= ((t - h) & mask)) jaroslav@597: throw new ConcurrentModificationException(); jaroslav@597: jaroslav@597: // Optimize for least element motion jaroslav@597: if (front < back) { jaroslav@597: if (h <= i) { jaroslav@597: System.arraycopy(elements, h, elements, h + 1, front); jaroslav@597: } else { // Wrap around jaroslav@597: System.arraycopy(elements, 0, elements, 1, i); jaroslav@597: elements[0] = elements[mask]; jaroslav@597: System.arraycopy(elements, h, elements, h + 1, mask - h); jaroslav@597: } jaroslav@597: elements[h] = null; jaroslav@597: head = (h + 1) & mask; jaroslav@597: return false; jaroslav@597: } else { jaroslav@597: if (i < t) { // Copy the null tail as well jaroslav@597: System.arraycopy(elements, i + 1, elements, i, back); jaroslav@597: tail = t - 1; jaroslav@597: } else { // Wrap around jaroslav@597: System.arraycopy(elements, i + 1, elements, i, mask - i); jaroslav@597: elements[mask] = elements[0]; jaroslav@597: System.arraycopy(elements, 1, elements, 0, t); jaroslav@597: tail = (t - 1) & mask; jaroslav@597: } jaroslav@597: return true; jaroslav@597: } jaroslav@597: } jaroslav@597: jaroslav@597: // *** Collection Methods *** jaroslav@597: jaroslav@597: /** jaroslav@597: * Returns the number of elements in this deque. jaroslav@597: * jaroslav@597: * @return the number of elements in this deque jaroslav@597: */ jaroslav@597: public int size() { jaroslav@597: return (tail - head) & (elements.length - 1); jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Returns true if this deque contains no elements. jaroslav@597: * jaroslav@597: * @return true if this deque contains no elements jaroslav@597: */ jaroslav@597: public boolean isEmpty() { jaroslav@597: return head == tail; jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Returns an iterator over the elements in this deque. The elements jaroslav@597: * will be ordered from first (head) to last (tail). This is the same jaroslav@597: * order that elements would be dequeued (via successive calls to jaroslav@597: * {@link #remove} or popped (via successive calls to {@link #pop}). jaroslav@597: * jaroslav@597: * @return an iterator over the elements in this deque jaroslav@597: */ jaroslav@597: public Iterator iterator() { jaroslav@597: return new DeqIterator(); jaroslav@597: } jaroslav@597: jaroslav@597: public Iterator descendingIterator() { jaroslav@597: return new DescendingIterator(); jaroslav@597: } jaroslav@597: jaroslav@597: private class DeqIterator implements Iterator { jaroslav@597: /** jaroslav@597: * Index of element to be returned by subsequent call to next. jaroslav@597: */ jaroslav@597: private int cursor = head; jaroslav@597: jaroslav@597: /** jaroslav@597: * Tail recorded at construction (also in remove), to stop jaroslav@597: * iterator and also to check for comodification. jaroslav@597: */ jaroslav@597: private int fence = tail; jaroslav@597: jaroslav@597: /** jaroslav@597: * Index of element returned by most recent call to next. jaroslav@597: * Reset to -1 if element is deleted by a call to remove. jaroslav@597: */ jaroslav@597: private int lastRet = -1; jaroslav@597: jaroslav@597: public boolean hasNext() { jaroslav@597: return cursor != fence; jaroslav@597: } jaroslav@597: jaroslav@597: public E next() { jaroslav@597: if (cursor == fence) jaroslav@597: throw new NoSuchElementException(); jaroslav@597: E result = elements[cursor]; jaroslav@597: // This check doesn't catch all possible comodifications, jaroslav@597: // but does catch the ones that corrupt traversal jaroslav@597: if (tail != fence || result == null) jaroslav@597: throw new ConcurrentModificationException(); jaroslav@597: lastRet = cursor; jaroslav@597: cursor = (cursor + 1) & (elements.length - 1); jaroslav@597: return result; jaroslav@597: } jaroslav@597: jaroslav@597: public void remove() { jaroslav@597: if (lastRet < 0) jaroslav@597: throw new IllegalStateException(); jaroslav@597: if (delete(lastRet)) { // if left-shifted, undo increment in next() jaroslav@597: cursor = (cursor - 1) & (elements.length - 1); jaroslav@597: fence = tail; jaroslav@597: } jaroslav@597: lastRet = -1; jaroslav@597: } jaroslav@597: } jaroslav@597: jaroslav@597: private class DescendingIterator implements Iterator { jaroslav@597: /* jaroslav@597: * This class is nearly a mirror-image of DeqIterator, using jaroslav@597: * tail instead of head for initial cursor, and head instead of jaroslav@597: * tail for fence. jaroslav@597: */ jaroslav@597: private int cursor = tail; jaroslav@597: private int fence = head; jaroslav@597: private int lastRet = -1; jaroslav@597: jaroslav@597: public boolean hasNext() { jaroslav@597: return cursor != fence; jaroslav@597: } jaroslav@597: jaroslav@597: public E next() { jaroslav@597: if (cursor == fence) jaroslav@597: throw new NoSuchElementException(); jaroslav@597: cursor = (cursor - 1) & (elements.length - 1); jaroslav@597: E result = elements[cursor]; jaroslav@597: if (head != fence || result == null) jaroslav@597: throw new ConcurrentModificationException(); jaroslav@597: lastRet = cursor; jaroslav@597: return result; jaroslav@597: } jaroslav@597: jaroslav@597: public void remove() { jaroslav@597: if (lastRet < 0) jaroslav@597: throw new IllegalStateException(); jaroslav@597: if (!delete(lastRet)) { jaroslav@597: cursor = (cursor + 1) & (elements.length - 1); jaroslav@597: fence = head; jaroslav@597: } jaroslav@597: lastRet = -1; jaroslav@597: } jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Returns true if this deque contains the specified element. jaroslav@597: * More formally, returns true if and only if this deque contains jaroslav@597: * at least one element e such that o.equals(e). jaroslav@597: * jaroslav@597: * @param o object to be checked for containment in this deque jaroslav@597: * @return true if this deque contains the specified element jaroslav@597: */ jaroslav@597: public boolean contains(Object o) { jaroslav@597: if (o == null) jaroslav@597: return false; jaroslav@597: int mask = elements.length - 1; jaroslav@597: int i = head; jaroslav@597: E x; jaroslav@597: while ( (x = elements[i]) != null) { jaroslav@597: if (o.equals(x)) jaroslav@597: return true; jaroslav@597: i = (i + 1) & mask; jaroslav@597: } jaroslav@597: return false; jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Removes a single instance of the specified element from this deque. jaroslav@597: * If the deque does not contain the element, it is unchanged. jaroslav@597: * More formally, removes the first element e such that jaroslav@597: * o.equals(e) (if such an element exists). jaroslav@597: * Returns true if this deque contained the specified element jaroslav@597: * (or equivalently, if this deque changed as a result of the call). jaroslav@597: * jaroslav@597: *

This method is equivalent to {@link #removeFirstOccurrence}. jaroslav@597: * jaroslav@597: * @param o element to be removed from this deque, if present jaroslav@597: * @return true if this deque contained the specified element jaroslav@597: */ jaroslav@597: public boolean remove(Object o) { jaroslav@597: return removeFirstOccurrence(o); jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Removes all of the elements from this deque. jaroslav@597: * The deque will be empty after this call returns. jaroslav@597: */ jaroslav@597: public void clear() { jaroslav@597: int h = head; jaroslav@597: int t = tail; jaroslav@597: if (h != t) { // clear all cells jaroslav@597: head = tail = 0; jaroslav@597: int i = h; jaroslav@597: int mask = elements.length - 1; jaroslav@597: do { jaroslav@597: elements[i] = null; jaroslav@597: i = (i + 1) & mask; jaroslav@597: } while (i != t); jaroslav@597: } jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Returns an array containing all of the elements in this deque jaroslav@597: * in proper sequence (from first to last element). jaroslav@597: * jaroslav@597: *

The returned array will be "safe" in that no references to it are jaroslav@597: * maintained by this deque. (In other words, this method must allocate jaroslav@597: * a new array). The caller is thus free to modify the returned array. jaroslav@597: * jaroslav@597: *

This method acts as bridge between array-based and collection-based jaroslav@597: * APIs. jaroslav@597: * jaroslav@597: * @return an array containing all of the elements in this deque jaroslav@597: */ jaroslav@597: public Object[] toArray() { jaroslav@597: return copyElements(new Object[size()]); jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Returns an array containing all of the elements in this deque in jaroslav@597: * proper sequence (from first to last element); the runtime type of the jaroslav@597: * returned array is that of the specified array. If the deque fits in jaroslav@597: * the specified array, it is returned therein. Otherwise, a new array jaroslav@597: * is allocated with the runtime type of the specified array and the jaroslav@597: * size of this deque. jaroslav@597: * jaroslav@597: *

If this deque fits in the specified array with room to spare jaroslav@597: * (i.e., the array has more elements than this deque), the element in jaroslav@597: * the array immediately following the end of the deque is set to jaroslav@597: * null. jaroslav@597: * jaroslav@597: *

Like the {@link #toArray()} method, this method acts as bridge between jaroslav@597: * array-based and collection-based APIs. Further, this method allows jaroslav@597: * precise control over the runtime type of the output array, and may, jaroslav@597: * under certain circumstances, be used to save allocation costs. jaroslav@597: * jaroslav@597: *

Suppose x is a deque known to contain only strings. jaroslav@597: * The following code can be used to dump the deque into a newly jaroslav@597: * allocated array of String: jaroslav@597: * jaroslav@597: *

jaroslav@597:      *     String[] y = x.toArray(new String[0]);
jaroslav@597: * jaroslav@597: * Note that toArray(new Object[0]) is identical in function to jaroslav@597: * toArray(). jaroslav@597: * jaroslav@597: * @param a the array into which the elements of the deque are to jaroslav@597: * be stored, if it is big enough; otherwise, a new array of the jaroslav@597: * same runtime type is allocated for this purpose jaroslav@597: * @return an array containing all of the elements in this deque jaroslav@597: * @throws ArrayStoreException if the runtime type of the specified array jaroslav@597: * is not a supertype of the runtime type of every element in jaroslav@597: * this deque jaroslav@597: * @throws NullPointerException if the specified array is null jaroslav@597: */ jaroslav@597: public T[] toArray(T[] a) { jaroslav@597: int size = size(); jaroslav@597: if (a.length < size) jaroslav@597: a = (T[])java.lang.reflect.Array.newInstance( jaroslav@597: a.getClass().getComponentType(), size); jaroslav@597: copyElements(a); jaroslav@597: if (a.length > size) jaroslav@597: a[size] = null; jaroslav@597: return a; jaroslav@597: } jaroslav@597: jaroslav@597: // *** Object methods *** jaroslav@597: jaroslav@597: /** jaroslav@597: * Returns a copy of this deque. jaroslav@597: * jaroslav@597: * @return a copy of this deque jaroslav@597: */ jaroslav@597: public ArrayDeque clone() { jaroslav@597: try { jaroslav@597: ArrayDeque result = (ArrayDeque) super.clone(); jaroslav@597: result.elements = Arrays.copyOf(elements, elements.length); jaroslav@597: return result; jaroslav@597: jaroslav@597: } catch (CloneNotSupportedException e) { jaroslav@597: throw new AssertionError(); jaroslav@597: } jaroslav@597: } jaroslav@597: jaroslav@597: /** jaroslav@597: * Appease the serialization gods. jaroslav@597: */ jaroslav@597: private static final long serialVersionUID = 2340985798034038923L; jaroslav@597: jaroslav@597: }