Adds ArrayDeque

This commit is contained in:
konsoletyper 2014-03-20 17:39:52 +04:00
parent 2968ef9e83
commit 5fd2b18eba
3 changed files with 571 additions and 0 deletions

View File

@ -0,0 +1,64 @@
/*
* Copyright 2014 Alexey Andreev.
*
* 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.teavm.classlib.java.util;
import org.teavm.classlib.java.lang.TIllegalStateException;
/**
*
* @author Alexey Andreev
*/
public abstract class TAbstractQueue<E> extends TAbstractCollection<E> implements TQueue<E> {
@Override
public boolean add(E e) {
if (offer(e)) {
return true;
}
throw new TIllegalStateException();
}
@Override
public E remove() {
if (isEmpty()) {
throw new TNoSuchElementException();
}
return poll();
}
@Override
public E element() {
if (isEmpty()) {
throw new TNoSuchElementException();
}
return peek();
}
@Override
public void clear() {
while (!isEmpty()) {
poll();
}
}
@Override
public boolean addAll(TCollection<? extends E> c) {
boolean oneAdded = false;
for (TIterator<? extends E> iter = c.iterator(); iter.hasNext();) {
oneAdded |= add(iter.next());
}
return oneAdded;
}
}

View File

@ -0,0 +1,376 @@
/*
* Copyright 2014 Alexey Andreev.
*
* 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.teavm.classlib.java.util;
import java.util.Arrays;
import org.teavm.classlib.java.lang.*;
/**
*
* @author Alexey Andreev
*/
public class TArrayDeque<E> extends TAbstractCollection<E> implements TDeque<E> {
private int version;
private Object[] array;
private int head;
private int tail;
public TArrayDeque() {
this(8);
}
public TArrayDeque(int numElements) {
array = new Object[numElements + 1];
}
public TArrayDeque(TCollection<? extends E> c) {
if (c.isEmpty()) {
array = new Object[8];
} else {
array = new Object[c.size() + 1];
int index = 0;
for (TIterator<? extends E> iter = c.iterator(); iter.hasNext();) {
array[index++] = iter.next();
}
tail = array.length - 1;
}
}
@Override
public void addFirst(E e) {
if (e == null) {
throw new TNullPointerException();
}
ensureCapacity(size() + 1);
--head;
if (head < 0) {
head += array.length;
}
array[head] = e;
++version;
}
@Override
public void addLast(E e) {
if (e == null) {
throw new TNullPointerException();
}
ensureCapacity(size() + 1);
array[tail++] = e;
if (tail >= array.length) {
tail = 0;
}
++version;
}
@Override
public boolean offerFirst(E e) {
addFirst(e);
return true;
}
@Override
public boolean offerLast(E e) {
addLast(e);
return true;
}
@Override
public E removeFirst() {
E value = pollFirst();
if (value == null) {
throw new TNoSuchElementException();
}
return value;
}
@Override
public E removeLast() {
E value = pollLast();
if (value == null) {
throw new TNoSuchElementException();
}
return value;
}
@Override
public E pollFirst() {
if (head == tail) {
return null;
}
@SuppressWarnings("unchecked")
E result = (E)array[head];
array[head] = null;
head++;
if (head >= array.length) {
head = 0;
}
++version;
return result;
}
@Override
public E pollLast() {
if (head == tail) {
return null;
}
--tail;
if (tail < 0) {
tail = array.length - 1;
}
@SuppressWarnings("unchecked")
E result = (E)array[tail];
array[tail] = null;
++version;
return result;
}
@Override
public E getFirst() {
E result = peekFirst();
if (result == null) {
throw new TNoSuchElementException();
}
return result;
}
@Override
public E getLast() {
E result = peekLast();
if (result == null) {
throw new TNoSuchElementException();
}
return result;
}
@Override
@SuppressWarnings("unchecked")
public E peekFirst() {
return !isEmpty() ? (E)array[head] : null;
}
@Override
@SuppressWarnings("unchecked")
public E peekLast() {
return !isEmpty() ? (E)array[tail > 0 ? tail - 1 : array.length - 1] : null;
}
@Override
public boolean removeFirstOccurrence(Object o) {
if (o == null) {
return false;
}
for (TIterator<E> iter = iterator(); iter.hasNext();) {
if (iter.next().equals(o)) {
iter.remove();
return true;
}
}
return false;
}
@Override
public boolean removeLastOccurrence(Object o) {
if (o == null) {
return false;
}
for (TIterator<E> iter = descendingIterator(); iter.hasNext();) {
if (iter.next().equals(o)) {
iter.remove();
return true;
}
}
return false;
}
@Override
public boolean add(E e) {
addLast(e);
return true;
}
@Override
public boolean offer(E e) {
return offerLast(e);
}
@Override
public E remove() {
return removeFirst();
}
@Override
public E poll() {
return pollFirst();
}
@Override
public E element() {
return getFirst();
}
@Override
public E peek() {
return peekFirst();
}
@Override
public void push(E e) {
addFirst(e);
}
@Override
public E pop() {
return removeFirst();
}
@Override
public int size() {
return tail >= head ? tail - head : array.length - head + tail;
}
@Override
public boolean isEmpty() {
return head == tail;
}
private void removeAt(int index) {
if (head < tail) {
if (tail - index < index - head) {
for (int i = index + 1; i < tail; ++i) {
array[i - 1] = array[i];
}
array[tail - 1] = null;
} else {
for (int i = index - 1; i >= head; --i) {
array[i + 1] = array[i];
}
array[head] = null;
}
} else {
if (index >= head) {
for (int i = index - 1; i >= head; --i) {
array[i + 1] = array[i];
}
array[head] = null;
} else {
for (int i = index + 1; i < tail; ++i) {
array[i - 1] = array[i];
}
array[tail - 1] = null;
}
}
}
@Override
public TIterator<E> iterator() {
return new TIterator<E>() {
private int refVersion = version;
private int index = head;
private int lastIndex = -1;
private boolean wrapped = head <= tail;
@Override public boolean hasNext() {
return !wrapped || index < tail;
}
@Override public E next() {
if (version > refVersion) {
throw new TConcurrentModificationException();
}
lastIndex = index;
@SuppressWarnings("unchecked")
E result = (E)array[index++];
if (index >= array.length) {
index = 0;
wrapped = true;
}
return result;
}
@Override public void remove() {
removeAt(lastIndex);
lastIndex = -1;
}
};
}
@Override
public TIterator<E> descendingIterator() {
return new TIterator<E>() {
private int refVersion = version;
private int index = tail;
private int lastIndex = -1;
private boolean wrapped = head <= tail;
@Override public boolean hasNext() {
return !wrapped || index > head;
}
@Override public E next() {
if (version > refVersion) {
throw new TConcurrentModificationException();
}
--index;
if (index < 0) {
index = array.length - 1;
wrapped = true;
}
lastIndex = index;
@SuppressWarnings("unchecked")
E result = (E)array[index];
return result;
}
@Override public void remove() {
removeAt(lastIndex);
lastIndex = -1;
}
};
}
private void ensureCapacity(int capacity) {
if (capacity < array.length) {
return;
}
int newArraySize = TMath.max(array.length * 2, capacity * 3 / 2 + 1);
if (newArraySize < 1) {
newArraySize = TInteger.MAX_VALUE;
}
Object[] newArray = new Object[newArraySize];
int j = 0;
if (head <= tail) {
for (int i = head; i < tail; ++i) {
newArray[j++] = array[i];
}
} else {
for (int i = head; i < array.length; ++i) {
newArray[j++] = array[i];
}
for (int i = 0; i < tail; ++i) {
newArray[j++] = array[i];
}
}
head = 0;
tail = j;
array = newArray;
}
@Override
public void clear() {
Arrays.fill(array, null);
head = tail;
}
@Override
protected TArrayDeque<E> clone() {
return new TArrayDeque<>(this);
}
}

View File

@ -0,0 +1,131 @@
/*
* Copyright 2014 Alexey Andreev.
*
* 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.teavm.classlib.java.util;
import static org.junit.Assert.*;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Iterator;
import org.junit.Test;
/**
*
* @author Alexey Andreev
*/
public class ArrayDequeTest {
@Test
public void addsToFront() {
Deque<Integer> deque = new ArrayDeque<>();
deque.addFirst(1);
deque.addFirst(2);
Iterator<Integer> iter = deque.iterator();
assertEquals(2, deque.size());
assertEquals((Integer)2, iter.next());
assertEquals((Integer)1, iter.next());
assertFalse(iter.hasNext());
}
@Test
public void addsToBack() {
Deque<Integer> deque = new ArrayDeque<>();
deque.addLast(1);
deque.addLast(2);
Iterator<Integer> iter = deque.iterator();
assertEquals(2, deque.size());
assertEquals((Integer)1, iter.next());
assertEquals((Integer)2, iter.next());
assertFalse(iter.hasNext());
}
@Test
public void addsManyToFront() {
Deque<Integer> deque = new ArrayDeque<>();
for (int i = 0; i < 1000; ++i) {
deque.addFirst(i);
}
assertEquals(1000, deque.size());
Iterator<Integer> iter = deque.iterator();
assertEquals((Integer)999, iter.next());
for (int i = 2; i < 500; ++i) {
iter.next();
}
assertEquals((Integer)500, iter.next());
for (int i = 1; i < 500; ++i) {
iter.next();
}
assertEquals((Integer)0, iter.next());
}
@Test
public void addsManyToBack() {
Deque<Integer> deque = new ArrayDeque<>();
for (int i = 0; i < 1000; ++i) {
deque.addLast(i);
}
assertEquals(1000, deque.size());
Iterator<Integer> iter = deque.iterator();
assertEquals((Integer)0, iter.next());
for (int i = 1; i < 500; ++i) {
iter.next();
}
assertEquals((Integer)500, iter.next());
for (int i = 2; i < 500; ++i) {
iter.next();
}
assertEquals((Integer)999, iter.next());
}
@Test
public void removesFromFront() {
Deque<Integer> deque = new ArrayDeque<>();
deque.addFirst(1);
deque.addFirst(2);
assertEquals((Integer)2, deque.removeFirst());
assertEquals((Integer)1, deque.removeFirst());
assertEquals(0, deque.size());
}
@Test
public void removesFromBack() {
Deque<Integer> deque = new ArrayDeque<>();
deque.addFirst(1);
deque.addFirst(2);
assertEquals((Integer)1, deque.removeLast());
assertEquals((Integer)2, deque.removeLast());
assertEquals(0, deque.size());
}
@Test
public void addAndRemoves() {
Deque<Integer> deque = new ArrayDeque<>();
for (int i = 0; i < 100; ++i) {
deque.addLast(i);
}
assertEquals((Integer)0, deque.removeFirst());
for (int i = 1; i < 20; ++i) {
deque.removeFirst();
}
assertEquals((Integer)20, deque.removeFirst());
for (int i = 101; i < 111; ++i) {
deque.addLast(i);
}
assertEquals((Integer)110, deque.removeLast());
for (int i = 2; i < 40; ++i) {
deque.removeLast();
}
assertEquals((Integer)70, deque.removeLast());
}
}