blob: 95aadf022794f2ce3db98625093cd2b203d39ef3 [file] [log] [blame]
/*
* 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());
}
}
}