/* Copyright (c) 2008-2014, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. There is NO WARRANTY for this software. See license.txt for details. */ package java.util; public class ArrayDeque extends AbstractDeque implements Deque { private Object[] dataArray; // both indexes are inclusive, except when size == 0 private int startIndex; private int endIndex; private int size; private int modCount; public ArrayDeque() { this(16); } public ArrayDeque(int intialSize) { dataArray = new Object[intialSize]; modCount = 0; clear(); } public ArrayDeque(Collection c) { this(c.size()); addAll(c); } private void copyInto(Object[] array) { if (startIndex <= endIndex) { // only one copy needed System.arraycopy(dataArray, startIndex, array, 0, size); } else { int firstCopyCount = dataArray.length - startIndex; System.arraycopy(dataArray, startIndex, array, 0, firstCopyCount); System.arraycopy(dataArray, 0, array, firstCopyCount, endIndex + 1); } } private void ensureCapacity(int newSize) { if (dataArray.length < newSize) { Object[] newArray = new Object[dataArray.length * 2]; copyInto(newArray); dataArray = newArray; startIndex = 0; endIndex = size - 1; } } @Override public boolean offerFirst(T e) { ensureCapacity(size() + 1); modCount++; if (size > 0) { // we don't need to move the head index for the first one startIndex--; if (startIndex < 0) { // wrapping to the end of the array startIndex = dataArray.length - 1; } } size++; dataArray[startIndex] = e; return true; } @Override public boolean offerLast(T e) { ensureCapacity(size() + 1); modCount++; if (size > 0) { // we don't need to move the tail index for the first one endIndex = (endIndex + 1) % dataArray.length; } size++; dataArray[endIndex] = e; return true; } @Override public T pollFirst() { modCount++; if (size == 0) { return null; } @SuppressWarnings("unchecked") T result = (T)dataArray[startIndex]; size--; if (size == 0) { startIndex = endIndex = 0; } else { startIndex = (startIndex + 1) % dataArray.length; } return result; } @Override public T pollLast() { modCount++; if (size == 0) { return null; } @SuppressWarnings("unchecked") T result = (T)dataArray[endIndex]; size--; if (size == 0) { startIndex = endIndex = 0; } else { endIndex--; if (endIndex < 0) { endIndex = dataArray.length - 1; } } return result; } @Override public T peekFirst() { if (size == 0) { return null; } else { @SuppressWarnings("unchecked") T result = (T)dataArray[startIndex]; return result; } } @Override public T peekLast() { if (size == 0) { return null; } else { @SuppressWarnings("unchecked") T result = (T)dataArray[endIndex]; return result; } } @Override public boolean addAll(Collection c) { if (c == null || c.isEmpty()) { return false; } ensureCapacity(size() + c.size()); Iterator it = c.iterator(); while (it.hasNext()) { add(it.next()); } return true; } @Override public boolean removeAll(Collection c) { boolean removed = false; Iterator it = c.iterator(); while (it.hasNext()) { removed = remove(it.next()) || removed; } return removed; } private boolean remove(Object o, boolean first) { modCount++; Iterator it; if (first) { it = iterator(); } else { it = descendingIterator(); } while (it.hasNext()) { T next = it.next(); if (next == null) { if (o == null) { it.remove(); return true; } } else if (next.equals(o)) { it.remove(); return true; } } return false; } @Override public boolean removeFirstOccurrence(Object o) { return remove(o, true); } @Override public boolean removeLastOccurrence(Object o) { return remove(o, false); } @Override public void clear() { size = 0; startIndex = endIndex = 0; modCount++; } @Override public int size() { return size; } @Override public boolean contains(Object element) { Iterator it = iterator(); while (it.hasNext()) { T next = it.next(); if (next == null) { if (element == null) { return true; } } else if (next.equals(element)) { return true; } } return false; } @Override public boolean containsAll(Collection c) { Iterator it = c.iterator(); while (it.hasNext()) { if (! contains(it.next())) { return false; } } return true; } @Override public Object[] toArray() { Object[] result = new Object[size]; copyInto(result); return result; } @Override public S[] toArray(S[] array) { return avian.Data.toArray(this, array); } public Iterator iterator() { return new GenericIterator() { @Override protected int getArrayIndex() { int result = (currentIndex + startIndex) % dataArray.length; return result; } }; } public Iterator descendingIterator() { return new GenericIterator() { @Override protected int getArrayIndex() { int result = (endIndex - currentIndex) % dataArray.length; return result; } }; } private abstract class GenericIterator implements Iterator { protected int expectedModCount = modCount; protected int currentIndex = 0; protected abstract int getArrayIndex(); @Override public T next() { if (modCount != expectedModCount) { throw new ConcurrentModificationException(); } else if (currentIndex == size) { throw new NoSuchElementException(); } @SuppressWarnings("unchecked") T result = (T)dataArray[getArrayIndex()]; currentIndex++; return result; } @Override public boolean hasNext() { return currentIndex < size; } @Override public void remove() { currentIndex--; int removalIndex = getArrayIndex(); if (removalIndex == startIndex) { // avoid array copy pollFirst(); expectedModCount = modCount; } else if (removalIndex == endIndex) { // avoid array copy pollLast(); expectedModCount = modCount; } else { // array must be copied Object[] newArray = new Object[dataArray.length]; if (startIndex <= endIndex) { int firstCopyCount = removalIndex - startIndex; System.arraycopy(dataArray, startIndex, newArray, 0, firstCopyCount); System.arraycopy(dataArray, removalIndex + 1, newArray, firstCopyCount, size - firstCopyCount); } else if (removalIndex > startIndex) { int firstCopyCount = removalIndex - startIndex; System.arraycopy(dataArray, startIndex, newArray, 0, firstCopyCount); System.arraycopy(dataArray, startIndex + firstCopyCount + 1, newArray, firstCopyCount, dataArray.length - removalIndex - 1); System.arraycopy(dataArray, 0, newArray, size - removalIndex, endIndex + 1); } else { int firstCopyCount = dataArray.length - startIndex; System.arraycopy(dataArray, startIndex, newArray, 0, firstCopyCount); System.arraycopy(dataArray, 0, newArray, firstCopyCount, removalIndex); System.arraycopy(dataArray, removalIndex + 1, newArray, firstCopyCount + removalIndex, endIndex - removalIndex); } dataArray = newArray; startIndex = 0; endIndex = --size - 1; } } } }