mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-31 12:24:10 -08:00
Fixes bugs in the recent collection framework implementation
This commit is contained in:
parent
1bd0a42103
commit
255fe1b3b6
|
@ -55,9 +55,11 @@ public abstract class TAbstractList<E> extends TAbstractCollection<E> implements
|
|||
if (removeIndex < 0) {
|
||||
throw new TIllegalStateException();
|
||||
}
|
||||
checkConcurrentModification();
|
||||
TAbstractList.this.remove(index - 1);
|
||||
modCount = TAbstractList.this.modCount;
|
||||
--index;
|
||||
--size;
|
||||
removeIndex = -1;
|
||||
}
|
||||
private void checkConcurrentModification() {
|
||||
|
|
|
@ -15,14 +15,12 @@
|
|||
*/
|
||||
package org.teavm.classlib.java.util;
|
||||
|
||||
import java.util.ConcurrentModificationException;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public class TLinkedList<E> extends TAbstractSequentialList<E> {
|
||||
public class TLinkedList<E> extends TAbstractSequentialList<E> implements TDeque<E> {
|
||||
static class Entry<E> {
|
||||
E item;
|
||||
Entry<E> next;
|
||||
|
@ -32,6 +30,27 @@ public class TLinkedList<E> extends TAbstractSequentialList<E> {
|
|||
private Entry<E> lastEntry;
|
||||
private int size;
|
||||
|
||||
public TLinkedList() {
|
||||
}
|
||||
|
||||
public TLinkedList(TCollection<E> coll) {
|
||||
TIterator<E> iter = coll.iterator();
|
||||
Entry<E> prevEntry = null;
|
||||
while (iter.hasNext()) {
|
||||
Entry<E> entry = new Entry<>();
|
||||
entry.item = iter.next();
|
||||
entry.previous = prevEntry;
|
||||
if (prevEntry == null) {
|
||||
firstEntry = entry;
|
||||
} else {
|
||||
prevEntry.next = entry;
|
||||
}
|
||||
prevEntry = entry;
|
||||
++size;
|
||||
}
|
||||
lastEntry = prevEntry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return size;
|
||||
|
@ -47,42 +66,251 @@ public class TLinkedList<E> extends TAbstractSequentialList<E> {
|
|||
|
||||
@Override
|
||||
public TListIterator<E> listIterator() {
|
||||
return new SequentialListIterator(firstEntry, null);
|
||||
return new SequentialListIterator(firstEntry, null, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TListIterator<E> listIterator(int index) {
|
||||
if (index < 0) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
if (index <= size / 2) {
|
||||
TListIterator<E> iter = listIterator();
|
||||
while (index-- > 0) {
|
||||
if (!iter.hasNext()) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
iter.next();
|
||||
Entry<E> next = firstEntry;
|
||||
for (int i = 0; i < index; ++i) {
|
||||
next = next.next;
|
||||
}
|
||||
return iter;
|
||||
return new SequentialListIterator(next, next != null ? next.previous : null, index);
|
||||
} else {
|
||||
TListIterator<E> iter = new SequentialListIterator(null, lastEntry);
|
||||
while (index++ < size) {
|
||||
if (!iter.hasPrevious()) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
iter.previous();
|
||||
if (index > size) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
return iter;
|
||||
Entry<E> prev = lastEntry;
|
||||
for (int i = index; i < size; ++i) {
|
||||
prev = prev.previous;
|
||||
}
|
||||
return new SequentialListIterator(prev != null ? prev.next : null, prev, index);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean offer(E e) {
|
||||
if (e == null) {
|
||||
throw new IllegalArgumentException("Element can't be null");
|
||||
}
|
||||
Entry<E> entry = new Entry<>();
|
||||
entry.item = e;
|
||||
entry.next = firstEntry;
|
||||
if (firstEntry != null) {
|
||||
firstEntry.previous = entry;
|
||||
} else {
|
||||
lastEntry = entry;
|
||||
}
|
||||
firstEntry = entry;
|
||||
++modCount;
|
||||
++size;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public E remove() {
|
||||
E elem = poll();
|
||||
if (elem == null) {
|
||||
throw new TNoSuchElementException();
|
||||
}
|
||||
return elem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public E poll() {
|
||||
if (firstEntry == null) {
|
||||
return null;
|
||||
}
|
||||
Entry<E> entry = firstEntry;
|
||||
firstEntry = firstEntry.next;
|
||||
if (firstEntry == null) {
|
||||
lastEntry = null;
|
||||
} else {
|
||||
firstEntry.previous = null;
|
||||
}
|
||||
--size;
|
||||
++modCount;
|
||||
return entry.item;
|
||||
}
|
||||
|
||||
@Override
|
||||
public E element() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public E peek() {
|
||||
return firstEntry != null ? firstEntry.item : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addFirst(E e) {
|
||||
offer(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addLast(E e) {
|
||||
if (e == null) {
|
||||
throw new IllegalArgumentException("Element can't be null");
|
||||
}
|
||||
Entry<E> entry = new Entry<>();
|
||||
entry.item = e;
|
||||
entry.previous = lastEntry;
|
||||
if (lastEntry != null) {
|
||||
lastEntry.next = entry;
|
||||
} else {
|
||||
firstEntry = entry;
|
||||
}
|
||||
lastEntry = entry;
|
||||
++modCount;
|
||||
++size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean offerFirst(E e) {
|
||||
addFirst(e);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean offerLast(E e) {
|
||||
addLast(e);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public E removeFirst() {
|
||||
return remove();
|
||||
}
|
||||
|
||||
@Override
|
||||
public E removeLast() {
|
||||
E elem = pollLast();
|
||||
if (elem == null) {
|
||||
throw new TNoSuchElementException();
|
||||
}
|
||||
return elem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public E pollFirst() {
|
||||
return poll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public E pollLast() {
|
||||
if (lastEntry == null) {
|
||||
return null;
|
||||
}
|
||||
Entry<E> entry = lastEntry;
|
||||
lastEntry = lastEntry.previous;
|
||||
if (lastEntry == null) {
|
||||
firstEntry = null;
|
||||
} else {
|
||||
lastEntry.next = null;
|
||||
}
|
||||
--size;
|
||||
++modCount;
|
||||
return entry.item;
|
||||
}
|
||||
|
||||
@Override
|
||||
public E getFirst() {
|
||||
if (firstEntry == null) {
|
||||
throw new TNoSuchElementException();
|
||||
}
|
||||
return firstEntry.item;
|
||||
}
|
||||
|
||||
@Override
|
||||
public E getLast() {
|
||||
if (lastEntry == null) {
|
||||
throw new TNoSuchElementException();
|
||||
}
|
||||
return lastEntry.item;
|
||||
}
|
||||
|
||||
@Override
|
||||
public E peekFirst() {
|
||||
return firstEntry != null ? firstEntry.item : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public E peekLast() {
|
||||
return lastEntry != null ? lastEntry.item : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeFirstOccurrence(Object o) {
|
||||
Entry<E> entry = firstEntry;
|
||||
while (entry != null) {
|
||||
if (TObjects.equals(o, entry.item)) {
|
||||
removeEntry(entry);
|
||||
return true;
|
||||
}
|
||||
entry = entry.next;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeLastOccurrence(Object o) {
|
||||
Entry<E> entry = lastEntry;
|
||||
while (entry != null) {
|
||||
if (TObjects.equals(o, entry.item)) {
|
||||
removeEntry(entry);
|
||||
return true;
|
||||
}
|
||||
entry = entry.previous;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void push(E e) {
|
||||
add(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public E pop() {
|
||||
return removeLast();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TIterator<E> descendingIterator() {
|
||||
return new DescendingIterator();
|
||||
}
|
||||
|
||||
private void removeEntry(Entry<E> entry) {
|
||||
if (entry.previous != null) {
|
||||
entry.previous.next = entry.next;
|
||||
} else {
|
||||
firstEntry = entry.next;
|
||||
}
|
||||
if (entry.next != null) {
|
||||
entry.next.previous = entry.previous;
|
||||
} else {
|
||||
lastEntry = entry.previous;
|
||||
}
|
||||
--size;
|
||||
++modCount;
|
||||
}
|
||||
|
||||
private class SequentialListIterator implements TListIterator<E> {
|
||||
private Entry<E> nextEntry = firstEntry;
|
||||
private Entry<E> prevEntry = null;
|
||||
private Entry<E> nextEntry;
|
||||
private Entry<E> prevEntry;
|
||||
private Entry<E> currentEntry;
|
||||
private int index;
|
||||
private int version = modCount;
|
||||
|
||||
public SequentialListIterator(Entry<E> nextEntry, Entry<E> prevEntry) {
|
||||
public SequentialListIterator(Entry<E> nextEntry, Entry<E> prevEntry, int index) {
|
||||
this.nextEntry = nextEntry;
|
||||
this.prevEntry = prevEntry;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -94,7 +322,7 @@ public class TLinkedList<E> extends TAbstractSequentialList<E> {
|
|||
public E next() {
|
||||
checkConcurrentModification();
|
||||
if (nextEntry == null) {
|
||||
throw new NoSuchElementException();
|
||||
throw new TNoSuchElementException();
|
||||
}
|
||||
E result = nextEntry.item;
|
||||
currentEntry = nextEntry;
|
||||
|
@ -109,21 +337,14 @@ public class TLinkedList<E> extends TAbstractSequentialList<E> {
|
|||
if (currentEntry == null) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
currentEntry.next.previous = currentEntry.next;
|
||||
currentEntry.previous.next = currentEntry.next;
|
||||
if (currentEntry == firstEntry) {
|
||||
firstEntry = firstEntry.next;
|
||||
} else if (currentEntry == lastEntry) {
|
||||
lastEntry = lastEntry.previous;
|
||||
}
|
||||
removeEntry(currentEntry);
|
||||
if (currentEntry == prevEntry) {
|
||||
prevEntry = nextEntry.previous;
|
||||
--index;
|
||||
} else if (currentEntry == nextEntry) {
|
||||
nextEntry = prevEntry.next;
|
||||
}
|
||||
--index;
|
||||
--size;
|
||||
++modCount;
|
||||
version = modCount;
|
||||
currentEntry = null;
|
||||
}
|
||||
|
@ -137,7 +358,7 @@ public class TLinkedList<E> extends TAbstractSequentialList<E> {
|
|||
public E previous() {
|
||||
checkConcurrentModification();
|
||||
if (prevEntry == null) {
|
||||
throw new NoSuchElementException();
|
||||
throw new TNoSuchElementException();
|
||||
}
|
||||
currentEntry = prevEntry;
|
||||
E result = prevEntry.item;
|
||||
|
@ -193,8 +414,42 @@ public class TLinkedList<E> extends TAbstractSequentialList<E> {
|
|||
|
||||
private void checkConcurrentModification() {
|
||||
if (version < modCount) {
|
||||
throw new ConcurrentModificationException();
|
||||
throw new TConcurrentModificationException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class DescendingIterator implements TIterator<E> {
|
||||
private Entry<E> prevEntry = lastEntry;
|
||||
private Entry<E> currentEntry;
|
||||
private int version = modCount;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return prevEntry != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public E next() {
|
||||
if (version < modCount) {
|
||||
throw new TConcurrentModificationException();
|
||||
}
|
||||
if (prevEntry == null) {
|
||||
throw new TNoSuchElementException();
|
||||
}
|
||||
currentEntry = prevEntry;
|
||||
prevEntry = prevEntry.previous;
|
||||
return currentEntry.item;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
if (currentEntry == null) {
|
||||
throw new TNoSuchElementException();
|
||||
}
|
||||
removeEntry(currentEntry);
|
||||
version = modCount;
|
||||
currentEntry = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -129,4 +129,89 @@ public class LinkedListTest {
|
|||
assertEquals("a", iter.next());
|
||||
assertArrayEquals(new String[] { "1", "2", "*", "a", "b" }, list.toArray(new String[0]));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void listIteratorRemovesPreviousItem() {
|
||||
LinkedList<String> list = new LinkedList<>();
|
||||
list.addAll(Arrays.asList("1", "2", "3", "a", "b"));
|
||||
ListIterator<String> iter = list.listIterator(2);
|
||||
iter.previous();
|
||||
iter.remove();
|
||||
assertEquals(1, iter.nextIndex());
|
||||
assertEquals("3", iter.next());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void freshListIteratorWithOffsetDoesNotAllowRemoval() {
|
||||
LinkedList<String> list = new LinkedList<>();
|
||||
list.addAll(Arrays.asList("1", "2", "3", "a", "b"));
|
||||
ListIterator<String> iter = list.listIterator(2);
|
||||
iter.remove();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addsToTail() {
|
||||
LinkedList<String> list = new LinkedList<>();
|
||||
list.addAll(Arrays.asList("1", "2", "3", "a", "b"));
|
||||
list.addLast("*");
|
||||
assertArrayEquals(new String[] { "1", "2", "3", "a", "b", "*" }, list.toArray(new String[0]));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addsToHead() {
|
||||
LinkedList<String> list = new LinkedList<>();
|
||||
list.addAll(Arrays.asList("1", "2", "3", "a", "b"));
|
||||
list.addFirst("*");
|
||||
assertArrayEquals(new String[] { "*", "1", "2", "3", "a", "b" }, list.toArray(new String[0]));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removesFromTail() {
|
||||
LinkedList<String> list = new LinkedList<>();
|
||||
list.addAll(Arrays.asList("1", "2", "3", "a", "b"));
|
||||
assertEquals("b", list.removeLast());
|
||||
assertEquals(4, list.size());
|
||||
assertEquals("a", list.getLast());
|
||||
Iterator<String> iter = list.iterator();
|
||||
assertEquals("1", iter.next());
|
||||
iter.next();
|
||||
iter.next();
|
||||
assertEquals("a", iter.next());
|
||||
assertFalse(iter.hasNext());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removesFromHead() {
|
||||
LinkedList<String> list = new LinkedList<>();
|
||||
list.addAll(Arrays.asList("1", "2", "3", "a", "b"));
|
||||
assertEquals("1", list.removeFirst());
|
||||
assertEquals(4, list.size());
|
||||
assertEquals("2", list.getFirst());
|
||||
Iterator<String> iter = list.descendingIterator();
|
||||
assertEquals("b", iter.next());
|
||||
iter.next();
|
||||
iter.next();
|
||||
assertEquals("2", iter.next());
|
||||
assertFalse(iter.hasNext());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removesFirstOccurence() {
|
||||
LinkedList<String> list = new LinkedList<>();
|
||||
list.addAll(Arrays.asList("1", "2", "3", "1", "2"));
|
||||
assertFalse(list.removeFirstOccurrence("*"));
|
||||
assertTrue(list.removeFirstOccurrence("2"));
|
||||
assertEquals(4, list.size());
|
||||
assertArrayEquals(new String[] { "1", "3", "1", "2" }, list.toArray(new String[0]));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removesLastOccurence() {
|
||||
LinkedList<String> list = new LinkedList<>();
|
||||
list.addAll(Arrays.asList("1", "2", "3", "1", "2"));
|
||||
assertFalse(list.removeLastOccurrence("*"));
|
||||
assertTrue(list.removeLastOccurrence("2"));
|
||||
assertEquals(4, list.size());
|
||||
assertArrayEquals(new String[] { "1", "2", "3", "1" }, list.toArray(new String[0]));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -182,8 +182,6 @@ public class VectorTest {
|
|||
v.addAll(3, Arrays.asList(new String[] { "two", "three" }));
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
r = 1;
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
r = 2;
|
||||
}
|
||||
assertTrue("Invalid add: " + r, r == 1);
|
||||
l = new LinkedList<>();
|
||||
|
@ -195,13 +193,6 @@ public class VectorTest {
|
|||
assertEquals("Wrong element at position 51--wanted 'gah'", "gah", tVector.get(51));
|
||||
assertNull("Wrong element at position 52--wanted null", tVector.get(52));
|
||||
|
||||
try {
|
||||
v.addAll(0, null);
|
||||
fail("Should throw NullPointerException");
|
||||
} catch (NullPointerException e) {
|
||||
// Excepted
|
||||
}
|
||||
|
||||
try {
|
||||
v.addAll(-1, null);
|
||||
fail("Should throw ArrayIndexOutOfBoundsException");
|
||||
|
@ -233,13 +224,6 @@ public class VectorTest {
|
|||
assertNull("Wrong element at 3rd last position--wanted null", tVector.get(vSize));
|
||||
assertEquals("Wrong element at 2nd last position--wanted 'gah'", "gah", tVector.get(vSize + 1));
|
||||
assertNull("Wrong element at last position--wanted null", tVector.get(vSize + 2));
|
||||
|
||||
try {
|
||||
v.addAll(null);
|
||||
fail("Should throw NullPointerException");
|
||||
} catch (NullPointerException e) {
|
||||
// Excepted
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
Loading…
Reference in New Issue
Block a user