| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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 java.util; |
| |
| import java.io.IOException; |
| import java.io.ObjectInputStream; |
| import java.io.ObjectOutputStream; |
| import java.io.Serializable; |
| import java.lang.reflect.Array; |
| |
| /** |
| * An implementation of Deque, backed by an array. |
| * |
| * ArrayDeques have no size limit, can not contain null element, and they are |
| * not thread-safe. |
| * |
| * All optional operations are supported, and the elements can be any objects. |
| * |
| * @param <E> |
| * the type of elements in this collection |
| * |
| * @since 1.6 |
| */ |
| public class ArrayDeque<E> extends AbstractCollection<E> implements Deque<E>, |
| Cloneable, Serializable { |
| |
| private static final long serialVersionUID = 2340985798034038923L; |
| |
| private static final int DEFAULT_SIZE = 16; |
| |
| private enum DequeStatus { |
| Empty, Normal, Full; |
| } |
| |
| private transient DequeStatus status; |
| |
| private transient int modCount; |
| |
| // the pointer of the head element |
| private transient int front; |
| |
| // the pointer of the "next" position of the tail element |
| private transient int rear; |
| |
| private transient E[] elements; |
| |
| @SuppressWarnings("hiding") |
| private class ArrayDequeIterator<E> implements Iterator<E> { |
| private int pos; |
| |
| private final int expectedModCount; |
| |
| private boolean canRemove; |
| |
| @SuppressWarnings("synthetic-access") |
| ArrayDequeIterator() { |
| super(); |
| pos = front; |
| expectedModCount = modCount; |
| canRemove = false; |
| } |
| |
| @SuppressWarnings("synthetic-access") |
| public boolean hasNext() { |
| if (expectedModCount != modCount) { |
| return false; |
| } |
| return hasNextInternal(); |
| } |
| |
| private boolean hasNextInternal() { |
| // canRemove means "next" method is called, and the Full |
| // status can ensure that this method is not called just |
| // after "remove" method is call.(so, canRemove can keep |
| // true after "next" method called) |
| return (pos != rear) |
| || ((status == DequeStatus.Full) && !canRemove); |
| } |
| |
| @SuppressWarnings( { "synthetic-access", "unchecked" }) |
| public E next() { |
| if (hasNextInternal()) { |
| E result = (E) elements[pos]; |
| if (expectedModCount == modCount && null != result) { |
| canRemove = true; |
| pos = circularBiggerPos(pos); |
| return result; |
| } |
| throw new ConcurrentModificationException(); |
| } |
| throw new NoSuchElementException(); |
| } |
| |
| @SuppressWarnings("synthetic-access") |
| public void remove() { |
| if (canRemove) { |
| int removedPos = circularSmallerPos(pos); |
| if (expectedModCount == modCount |
| && null != elements[removedPos]) { |
| removeInternal(removedPos, true); |
| canRemove = false; |
| return; |
| } |
| throw new ConcurrentModificationException(); |
| } |
| throw new IllegalStateException(); |
| } |
| } |
| |
| /* |
| * NOTES:descendingIterator is not fail-fast, according to the documentation |
| * and test case. |
| */ |
| @SuppressWarnings("hiding") |
| private class ReverseArrayDequeIterator<E> implements Iterator<E> { |
| private int pos; |
| |
| private final int expectedModCount; |
| |
| private boolean canRemove; |
| |
| @SuppressWarnings("synthetic-access") |
| ReverseArrayDequeIterator() { |
| super(); |
| expectedModCount = modCount; |
| pos = circularSmallerPos(rear); |
| canRemove = false; |
| } |
| |
| @SuppressWarnings("synthetic-access") |
| public boolean hasNext() { |
| if (expectedModCount != modCount) { |
| return false; |
| } |
| return hasNextInternal(); |
| } |
| |
| private boolean hasNextInternal() { |
| // canRemove means "next" method is called, and the Full |
| // status can ensure that this method is not called just |
| // after "remove" method is call.(so, canRemove can keep |
| // true after "next" method called) |
| return (circularBiggerPos(pos) != front) |
| || ((status == DequeStatus.Full) && !canRemove); |
| } |
| |
| @SuppressWarnings( { "synthetic-access", "unchecked" }) |
| public E next() { |
| if (hasNextInternal()) { |
| E result = (E) elements[pos]; |
| canRemove = true; |
| pos = circularSmallerPos(pos); |
| return result; |
| } |
| throw new NoSuchElementException(); |
| } |
| |
| @SuppressWarnings("synthetic-access") |
| public void remove() { |
| if (canRemove) { |
| removeInternal(circularBiggerPos(pos), false); |
| canRemove = false; |
| return; |
| } |
| throw new IllegalStateException(); |
| } |
| } |
| |
| /** |
| * Constructs a new empty instance of ArrayDeque big enough for 16 elements. |
| */ |
| public ArrayDeque() { |
| this(DEFAULT_SIZE); |
| } |
| |
| /** |
| * Constructs a new empty instance of ArrayDeque big enough for specified |
| * number of elements. |
| * |
| * @param minSize |
| * the smallest size of the ArrayDeque |
| */ |
| @SuppressWarnings("unchecked") |
| public ArrayDeque(final int minSize) { |
| int size = countInitSize(minSize); |
| elements = (E[]) new Object[size]; |
| front = rear = 0; |
| status = DequeStatus.Empty; |
| modCount = 0; |
| } |
| |
| /* |
| * count out the size for a new deque, and ensure that size >= minSize |
| */ |
| private int countInitSize(final int minSize) { |
| int size = Math.max(minSize, DEFAULT_SIZE); |
| // get the smallest number that not smaller than size, |
| // and is a power of 2. |
| size = Integer.highestOneBit(size - 1) << 1; |
| if (0 >= size) { |
| size = minSize; |
| } |
| return size; |
| } |
| |
| /** |
| * Constructs a new instance of ArrayDeque containing the elements of the |
| * specified collection, with the order returned by the collection's |
| * iterator. |
| * |
| * @param c |
| * the source of the elements |
| * @throws NullPointerException |
| * if the collection is null |
| */ |
| @SuppressWarnings("unchecked") |
| public ArrayDeque(Collection<? extends E> c) { |
| elements = (E[]) new Object[countInitSize(c.size())]; |
| front = rear = 0; |
| status = DequeStatus.Empty; |
| modCount = 0; |
| Iterator<? extends E> it = c.iterator(); |
| while (it.hasNext()) { |
| addLastImpl(it.next()); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @param e |
| * the element |
| * @throws NullPointerException |
| * if the element is null |
| * @see java.util.Deque#addFirst(java.lang.Object) |
| */ |
| public void addFirst(E e) { |
| offerFirst(e); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @param e |
| * the element |
| * @throws NullPointerException |
| * if the element is null |
| * @see java.util.Deque#addLast(java.lang.Object) |
| */ |
| public void addLast(E e) { |
| addLastImpl(e); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @param e |
| * the element |
| * @return true |
| * @throws NullPointerException |
| * if the element is null |
| * @see java.util.Deque#offerFirst(java.lang.Object) |
| */ |
| public boolean offerFirst(E e) { |
| checkNull(e); |
| checkAndExpand(); |
| front = circularSmallerPos(front); |
| elements[front] = e; |
| resetStatus(true); |
| modCount++; |
| return true; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @param e |
| * the element |
| * @return true if the operation succeeds or false if it fails |
| * @throws NullPointerException |
| * if the element is null |
| * @see java.util.Deque#offerLast(java.lang.Object) |
| */ |
| public boolean offerLast(E e) { |
| return addLastImpl(e); |
| } |
| |
| /** |
| * Inserts the element at the tail of the deque. |
| * |
| * @param e |
| * the element |
| * @return true if the operation succeeds or false if it fails. |
| * @throws NullPointerException |
| * if the element is null |
| * @see java.util.Queue#offer(java.lang.Object) |
| */ |
| public boolean offer(E e) { |
| return addLastImpl(e); |
| } |
| |
| /** |
| * Inserts the element to the tail of the deque. |
| * |
| * @param e |
| * the element |
| * @return true |
| * @see java.util.AbstractCollection#add(java.lang.Object) |
| */ |
| @Override |
| public boolean add(E e) { |
| return addLastImpl(e); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @param e |
| * the element to push |
| * @throws NullPointerException |
| * if the element is null |
| * @see java.util.Deque#push(java.lang.Object) |
| */ |
| public void push(E e) { |
| offerFirst(e); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @return the head element |
| * @throws NoSuchElementException |
| * if the deque is empty |
| * @see java.util.Deque#removeFirst() |
| */ |
| public E removeFirst() { |
| checkEmpty(); |
| return removePollFirstImpl(); |
| } |
| |
| /** |
| * Gets and removes the head element of this deque. This method throws an |
| * exception if the deque is empty. |
| * |
| * @return the head element |
| * @throws NoSuchElementException |
| * if the deque is empty |
| * @see java.util.Queue#remove() |
| */ |
| public E remove() { |
| return removeFirst(); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @return the head element |
| * @throws NoSuchElementException |
| * if the deque is empty |
| * @see java.util.Deque#pop() |
| */ |
| public E pop() { |
| return removeFirst(); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @return the tail element |
| * @throws NoSuchElementException |
| * if the deque is empty |
| * @see java.util.Deque#removeLast() |
| */ |
| public E removeLast() { |
| checkEmpty(); |
| return removeLastImpl(); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @return the head element or null if the deque is empty |
| * @see java.util.Deque#pollFirst() |
| */ |
| public E pollFirst() { |
| return (status == DequeStatus.Empty) ? null : removePollFirstImpl(); |
| } |
| |
| /** |
| * Gets and removes the head element of this deque. This method returns null |
| * if the deque is empty. |
| * |
| * @return the head element or null if the deque is empty |
| * @see java.util.Queue#poll() |
| */ |
| public E poll() { |
| return pollFirst(); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @return the tail element or null if the deque is empty |
| * @see java.util.Deque#pollLast() |
| */ |
| public E pollLast() { |
| return (status == DequeStatus.Empty) ? null : removeLastImpl(); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @return the head element |
| * @throws NoSuchElementException |
| * if the deque is empty |
| * @see java.util.Deque#getFirst() |
| */ |
| public E getFirst() { |
| checkEmpty(); |
| return elements[front]; |
| } |
| |
| /** |
| * Gets but does not remove the head element of this deque. It throws an |
| * exception if the deque is empty. |
| * |
| * @return the head element |
| * @throws NoSuchElementException |
| * if the deque is empty |
| * @see java.util.Queue#element() |
| */ |
| public E element() { |
| return getFirst(); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @return the tail element |
| * @throws NoSuchElementException |
| * if the deque is empty |
| * @see java.util.Deque#getLast() |
| */ |
| public E getLast() { |
| checkEmpty(); |
| return elements[circularSmallerPos(rear)]; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @return the head element or null if the deque is empty |
| * @see java.util.Deque#peekFirst() |
| */ |
| public E peekFirst() { |
| return (status == DequeStatus.Empty) ? null : elements[front]; |
| } |
| |
| /** |
| * Gets but not removes the head element of this deque. This method returns |
| * null if the deque is empty. |
| * |
| * @return the head element or null if the deque is empty |
| * @see java.util.Queue#peek() |
| */ |
| public E peek() { |
| return (status == DequeStatus.Empty) ? null : elements[front]; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @return the tail element or null if the deque is empty |
| * @see java.util.Deque#peekLast() |
| */ |
| public E peekLast() { |
| return (status == DequeStatus.Empty) ? null |
| : elements[circularSmallerPos(rear)]; |
| } |
| |
| private void checkNull(E e) { |
| if (null == e) { |
| throw new NullPointerException(); |
| } |
| } |
| |
| private void checkEmpty() { |
| if (status == DequeStatus.Empty) { |
| throw new NoSuchElementException(); |
| } |
| } |
| |
| private int circularSmallerPos(int current) { |
| return (current - 1 < 0) ? (elements.length - 1) : current - 1; |
| } |
| |
| private int circularBiggerPos(int current) { |
| return (current + 1 >= elements.length) ? 0 : current + 1; |
| } |
| |
| @SuppressWarnings("unchecked") |
| /* |
| * If array of elements is full, there will be a new bigger array to store |
| * the elements. |
| */ |
| private void checkAndExpand() { |
| if (status != DequeStatus.Full) { |
| return; |
| } |
| if (Integer.MAX_VALUE == elements.length) { |
| throw new IllegalStateException(); |
| } |
| int length = elements.length; |
| int newLength = length << 1; |
| // bigger than Integer.MAX_VALUE |
| if (newLength < 0) { |
| newLength = Integer.MAX_VALUE; |
| } |
| E[] newElements = (E[]) new Object[newLength]; |
| System.arraycopy(elements, front, newElements, 0, length - front); |
| System.arraycopy(elements, 0, newElements, length - front, front); |
| front = 0; |
| rear = length; |
| status = DequeStatus.Normal; |
| elements = newElements; |
| } |
| |
| /** |
| * Resets the status after adding or removing operation. |
| * |
| * @param adding |
| * if the method is called after an "adding" operation |
| */ |
| private void resetStatus(boolean adding) { |
| if (front == rear) { |
| status = adding ? DequeStatus.Full : DequeStatus.Empty; |
| } else { |
| status = DequeStatus.Normal; |
| } |
| } |
| |
| private boolean addLastImpl(E e) { |
| checkNull(e); |
| checkAndExpand(); |
| elements[rear] = e; |
| rear = circularBiggerPos(rear); |
| resetStatus(true); |
| modCount++; |
| return true; |
| } |
| |
| private E removePollFirstImpl() { |
| E element = elements[front]; |
| elements[front] = null; |
| front = circularBiggerPos(front); |
| resetStatus(false); |
| modCount++; |
| return element; |
| } |
| |
| private E removeLastImpl() { |
| int last = circularSmallerPos(rear); |
| E element = elements[last]; |
| elements[last] = null; |
| rear = last; |
| resetStatus(false); |
| modCount++; |
| return element; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @param obj |
| * the element to be removed |
| * @return true if the operation succeeds or false if the deque does not |
| * contain the element |
| * @see java.util.Deque#removeFirstOccurrence(java.lang.Object) |
| */ |
| public boolean removeFirstOccurrence(Object obj) { |
| return removeFirstOccurrenceImpl(obj); |
| } |
| |
| /** |
| * Removes the first equivalent element of the specified object. If the |
| * deque does not contain the element, it is unchanged and returns false. |
| * |
| * @param obj |
| * the element to be removed |
| * @return true if the operation succeeds or false if the deque does not |
| * contain the element |
| * @see java.util.AbstractCollection#remove(java.lang.Object) |
| */ |
| @Override |
| public boolean remove(Object obj) { |
| return removeFirstOccurrenceImpl(obj); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @param obj |
| * the element to be removed |
| * @return true if the operation succeeds or false if the deque does not |
| * contain the element. |
| * @see java.util.Deque#removeLastOccurrence(java.lang.Object) |
| */ |
| public boolean removeLastOccurrence(final Object obj) { |
| if (null != obj) { |
| Iterator<E> iter = descendingIterator(); |
| while (iter.hasNext()) { |
| if (iter.next().equals(obj)) { |
| iter.remove(); |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| |
| private boolean removeFirstOccurrenceImpl(final Object obj) { |
| if (null != obj) { |
| Iterator<E> iter = iterator(); |
| while (iter.hasNext()) { |
| if (iter.next().equals(obj)) { |
| iter.remove(); |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| |
| /* |
| * Removes the element in the cursor position and shifts front elements to |
| * fill the gap if frontShift is true, shifts rear elements otherwise. |
| * |
| */ |
| private void removeInternal(final int current, final boolean frontShift) { |
| int cursor = current; |
| if (frontShift) { |
| while (cursor != front) { |
| int next = circularSmallerPos(cursor); |
| elements[cursor] = elements[next]; |
| cursor = next; |
| } |
| front = circularBiggerPos(front); |
| } else { |
| while (cursor != rear) { |
| int next = circularBiggerPos(cursor); |
| elements[cursor] = elements[next]; |
| cursor = next; |
| } |
| rear = circularSmallerPos(rear); |
| } |
| elements[cursor] = null; |
| resetStatus(false); |
| } |
| |
| /** |
| * Returns the size of the deque. |
| * |
| * @return the size of the deque |
| * @see java.util.AbstractCollection#size() |
| */ |
| @Override |
| public int size() { |
| if (status == DequeStatus.Full) { |
| return elements.length; |
| } |
| return (front <= rear) ? (rear - front) |
| : (rear + elements.length - front); |
| } |
| |
| /** |
| * Returns true if the deque has no elements. |
| * |
| * @return true if the deque has no elements, false otherwise |
| * @see java.util.AbstractCollection#isEmpty() |
| */ |
| @Override |
| public boolean isEmpty() { |
| return 0 == size(); |
| } |
| |
| /** |
| * Returns true if the specified element is in the deque. |
| * |
| * @param obj |
| * the element |
| * @return true if the element is in the deque, false otherwise |
| * @see java.util.AbstractCollection#contains(java.lang.Object) |
| */ |
| @SuppressWarnings("cast") |
| @Override |
| public boolean contains(final Object obj) { |
| if (null != obj) { |
| Iterator<E> it = new ArrayDequeIterator<E>(); |
| while (it.hasNext()) { |
| if (obj.equals((E) it.next())) { |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Empty the deque. |
| * |
| * @see java.util.AbstractCollection#clear() |
| */ |
| @SuppressWarnings("cast") |
| @Override |
| public void clear() { |
| if (status != DequeStatus.Empty) { |
| int cursor = front; |
| do { |
| elements[cursor] = null; |
| cursor = circularBiggerPos(cursor); |
| } while (cursor != rear); |
| status = DequeStatus.Empty; |
| } |
| front = rear = 0; |
| modCount = 0; |
| } |
| |
| /** |
| * Returns a clone of the deque. |
| * |
| * @return the clone of the deque |
| * @see java.lang.Object#clone() |
| * @see java.lang.Cloneable |
| */ |
| @SuppressWarnings("unchecked") |
| @Override |
| public ArrayDeque<E> clone() { |
| try { |
| ArrayDeque<E> newDeque = (ArrayDeque<E>) super.clone(); |
| newDeque.elements = elements.clone(); |
| return newDeque; |
| } catch (CloneNotSupportedException e) { |
| return null; |
| } |
| } |
| |
| /** |
| * Returns all the elements in an array from head to tail. The result is a |
| * copy of all the elements. |
| * |
| * @return the Array of all the elements |
| * @see java.util.AbstractCollection#toArray() |
| */ |
| @Override |
| public Object[] toArray() { |
| return newArray(new Object[size()]); |
| } |
| |
| /** |
| * Returns all the elements in an array from head to tail, and the type of |
| * the result array is the type of the argument array. If the argument array |
| * is big enough, the elements from the deque will be stored in it(elements |
| * following the tail of the deque is set to null, if any); otherwise, it |
| * will return a new array with the size of the argument array and size of |
| * the deque. |
| * |
| * @param array |
| * the array stores all the elements from the deque, if it has |
| * enough space; otherwise, a new array of the same type and the |
| * size of the deque will be used |
| * @return the Array of all the elements |
| * @throws ArrayStoreException |
| * if the type of the argument array is not compatible with |
| * every element in the deque |
| * @throws NullPointerException |
| * if the argument array is null |
| * @see java.util.AbstractCollection#toArray |
| */ |
| @Override |
| public <T> T[] toArray(T[] array) { |
| return newArray(array); |
| } |
| |
| @SuppressWarnings("unchecked") |
| private <T> T[] newArray(T[] array) { |
| int size = size(); |
| if (size > array.length) { |
| Class<?> clazz = array.getClass().getComponentType(); |
| array = (T[]) Array.newInstance(clazz, size); |
| } |
| if (front < rear) { |
| System.arraycopy(elements, front, array, 0, size); |
| } else if (size != 0) { |
| int length = elements.length; |
| System.arraycopy(elements, front, array, 0, length - front); |
| System.arraycopy(elements, 0, array, length - front, rear); |
| } |
| if (size < array.length) { |
| array[size] = null; |
| } |
| return array; |
| } |
| |
| /** |
| * Returns the iterator of the deque. The elements will be ordered from head |
| * to tail. |
| * |
| * @return the iterator |
| * @see java.util.AbstractCollection#iterator() |
| */ |
| @SuppressWarnings("synthetic-access") |
| @Override |
| public Iterator<E> iterator() { |
| return new ArrayDequeIterator<E>(); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @return the reverse order Iterator |
| * @see java.util.Deque#descendingIterator() |
| */ |
| public Iterator<E> descendingIterator() { |
| return new ReverseArrayDequeIterator<E>(); |
| } |
| |
| /** |
| * Deserialization method. |
| * |
| * @param stream |
| * the ObjectInputStream |
| * @throws IOException |
| * @throws ClassNotFoundException |
| */ |
| @SuppressWarnings("unchecked") |
| private void readObject(ObjectInputStream stream) throws IOException, |
| ClassNotFoundException { |
| stream.defaultReadObject(); |
| int size = stream.readInt(); |
| elements = (E[]) new Object[countInitSize(size)]; |
| front = rear = 0; |
| status = DequeStatus.Empty; |
| modCount = 0; |
| for (int i = 0; i < size; i++) { |
| addLastImpl((E) stream.readObject()); |
| } |
| } |
| |
| /** |
| * Serialization method. |
| * |
| * @param stream |
| * the ObjectOutputStream |
| * @serialData The current size of the deque, followed by all the elements |
| * from head to tail. |
| * @throws IOException |
| * |
| */ |
| private void writeObject(ObjectOutputStream stream) throws IOException { |
| stream.defaultWriteObject(); |
| stream.writeInt(size()); |
| Iterator<?> it = new ArrayDequeIterator<E>(); |
| while (it.hasNext()) { |
| stream.writeObject(it.next()); |
| } |
| } |
| |
| } |