diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TAbstractCollection.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TAbstractCollection.java index 9503de976..ea07cea09 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TAbstractCollection.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TAbstractCollection.java @@ -15,6 +15,7 @@ */ package org.teavm.classlib.java.util; +import java.lang.reflect.Array; import org.teavm.classlib.java.lang.TObject; import org.teavm.classlib.java.lang.TUnsupportedOperationException; @@ -53,8 +54,21 @@ public abstract class TAbstractCollection extends TObject implements TCollect } @Override + @SuppressWarnings("unchecked") public T[] toArray(T[] a) { - return null; + int size = size(); + if (a.length < size) { + a = (T[])Array.newInstance(a.getClass().getComponentType(), size); + } else { + for (int i = size; i < a.length; ++i) { + a[i] = null; + } + } + int i = 0; + for (TIterator iter = iterator(); iter.hasNext();) { + a[i++] = (T)iter.next(); + } + return a; } @Override diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TAbstractList.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TAbstractList.java index 4468ca4df..ff31589a0 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TAbstractList.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TAbstractList.java @@ -15,10 +15,427 @@ */ package org.teavm.classlib.java.util; +import org.teavm.classlib.java.lang.TIllegalArgumentException; +import org.teavm.classlib.java.lang.TIllegalStateException; +import org.teavm.classlib.java.lang.TIndexOutOfBoundsException; +import org.teavm.classlib.java.lang.TUnsupportedOperationException; + /** - * + * * @author Alexey Andreev */ -public class TAbstractList { +public abstract class TAbstractList extends TAbstractCollection implements TList { + protected transient int modCount; + protected TAbstractList() { + } + + @Override + public boolean add(E e) { + add(size(), e); + return true; + } + + @Override + public TIterator iterator() { + return new TIterator() { + private int index; + private int modCount = TAbstractList.this.modCount; + private int size = size(); + @Override public boolean hasNext() { + return index < size; + } + @Override public E next() { + checkConcurrentModification(); + return get(index++); + } + @Override public void remove() { + TAbstractList.this.remove(index - 1); + } + private void checkConcurrentModification() { + if (modCount < TAbstractList.this.modCount) { + throw new TConcurrentModificationException(); + } + } + }; + } + + @Override + public boolean addAll(int index, TCollection c) { + if (index < 0 || index > size()) { + throw new TIllegalArgumentException(); + } + if (c.isEmpty()) { + return false; + } + for (TIterator iter = c.iterator(); iter.hasNext();) { + add(index++, iter.next()); + } + return true; + } + + @Override + public E set(int index, E element) { + throw new TUnsupportedOperationException(); + } + + @Override + public void add(int index, E element) { + throw new TUnsupportedOperationException(); + } + + @Override + public E remove(int index) { + throw new TUnsupportedOperationException(); + } + + @Override + public int indexOf(Object o) { + int sz = size(); + for (int i = 0; i < sz; ++i) { + Object e = get(i); + if (o == null ? e == null : o.equals(e)) { + return i; + } + } + return -1; + } + + @Override + public int lastIndexOf(Object o) { + int sz = size(); + for (int i = sz - 1; i >= 0; --i) { + Object e = get(i); + if (o == null ? e == null : o.equals(e)) { + return i; + } + } + return -1; + } + + @Override + public void clear() { + removeRange(0, size()); + } + + @Override + public TListIterator listIterator() { + return listIterator(0); + } + + @Override + public TListIterator listIterator(int index) { + return new TListIteratorImpl(index, modCount, size()); + } + + @Override + public TList subList(int fromIndex, int toIndex) { + if (fromIndex > toIndex) { + throw new TIllegalArgumentException(); + } + if (fromIndex < 0 || toIndex >= size()) { + throw new TIndexOutOfBoundsException(); + } + if (this instanceof TRandomAccess) { + return new SubAbstractListRandomAccess<>(this, fromIndex, toIndex); + } + return new SubAbstractList<>(this, fromIndex, toIndex); + + } + + protected void removeRange(int start, int end) { + for (int i = start; i < end; i++) { + remove(i); + } + } + + private class TListIteratorImpl implements TListIterator { + private int i; + private int j; + private int lastModCount; + private int sz; + public TListIteratorImpl(int i, int lastModCount, int sz) { + this.i = i; + this.j = i; + this.lastModCount = lastModCount; + this.sz = sz; + } + @Override public boolean hasNext() { + return i < sz; + } + @Override public E next() { + checkConcurrentModification(); + if (i == sz) { + throw new TNoSuchElementException(); + } + j = i; + return get(i++); + } + @Override public void remove() { + if (j == -1) { + throw new TIllegalStateException(); + } + checkConcurrentModification(); + TAbstractList.this.remove(j); + --sz; + lastModCount = modCount; + } + @Override public boolean hasPrevious() { + return i > 0; + } + @Override public E previous() { + checkConcurrentModification(); + j = i - 1; + if (j < 0) { + throw new TNoSuchElementException(); + } + return get((i--) - 1); + } + @Override public int nextIndex() { + return i; + } + @Override public int previousIndex() { + return i - 1; + } + @Override public void set(E e) { + if (j == -1) { + throw new TIllegalStateException(); + } + checkConcurrentModification(); + TAbstractList.this.set(j, e); + } + @Override public void add(E e) { + if (j == -1) { + throw new TIllegalStateException(); + } + TAbstractList.this.add(i++, e); + lastModCount = modCount; + j = -1; + } + private void checkConcurrentModification() { + if (lastModCount < modCount) { + throw new TConcurrentModificationException(); + } + } + } + + private static final class SubAbstractListRandomAccess extends SubAbstractList implements TRandomAccess { + SubAbstractListRandomAccess(TAbstractList list, int start, int end) { + super(list, start, end); + } + } + + private static class SubAbstractList extends TAbstractList { + private final TAbstractList fullList; + private int offset; + private int size; + + private static final class SubAbstractListIterator implements TListIterator { + private final SubAbstractList subList; + private final TListIterator iterator; + private int start; + private int end; + + SubAbstractListIterator(TListIterator it, SubAbstractList list, int offset, int length) { + super(); + iterator = it; + subList = list; + start = offset; + end = start + length; + } + + @Override + public void add(E object) { + iterator.add(object); + subList.sizeChanged(true); + end++; + } + + @Override + public boolean hasNext() { + return iterator.nextIndex() < end; + } + + @Override + public boolean hasPrevious() { + return iterator.previousIndex() >= start; + } + + @Override + public E next() { + if (iterator.nextIndex() < end) { + return iterator.next(); + } + throw new TNoSuchElementException(); + } + + @Override + public int nextIndex() { + return iterator.nextIndex() - start; + } + + @Override + public E previous() { + if (iterator.previousIndex() >= start) { + return iterator.previous(); + } + throw new TNoSuchElementException(); + } + + @Override + public int previousIndex() { + int previous = iterator.previousIndex(); + if (previous >= start) { + return previous - start; + } + return -1; + } + + @Override + public void remove() { + iterator.remove(); + subList.sizeChanged(false); + end--; + } + + @Override + public void set(E object) { + iterator.set(object); + } + } + + SubAbstractList(TAbstractList list, int start, int end) { + super(); + fullList = list; + modCount = fullList.modCount; + offset = start; + size = end - start; + } + + @Override + public void add(int location, E object) { + if (modCount == fullList.modCount) { + if (0 <= location && location <= size) { + fullList.add(location + offset, object); + size++; + modCount = fullList.modCount; + } else { + throw new TIndexOutOfBoundsException(); + } + } else { + throw new TConcurrentModificationException(); + } + } + + @Override + public boolean addAll(int location, TCollection collection) { + if (modCount == fullList.modCount) { + if (0 <= location && location <= size) { + boolean result = fullList.addAll(location + offset, collection); + if (result) { + size += collection.size(); + modCount = fullList.modCount; + } + return result; + } + throw new TIndexOutOfBoundsException(); + } + throw new TConcurrentModificationException(); + } + + @Override + public boolean addAll(TCollection collection) { + if (modCount == fullList.modCount) { + boolean result = fullList.addAll(offset + size, collection); + if (result) { + size += collection.size(); + modCount = fullList.modCount; + } + return result; + } + throw new TConcurrentModificationException(); + } + + @Override + public E get(int location) { + if (modCount == fullList.modCount) { + if (0 <= location && location < size) { + return fullList.get(location + offset); + } + throw new IndexOutOfBoundsException(); + } + throw new TConcurrentModificationException(); + } + + @Override + public TIterator iterator() { + return listIterator(0); + } + + @Override + public TListIterator listIterator(int location) { + if (modCount == fullList.modCount) { + if (0 <= location && location <= size) { + return new SubAbstractListIterator<>(fullList.listIterator(location + offset), this, offset, size); + } + throw new TIndexOutOfBoundsException(); + } + throw new TConcurrentModificationException(); + } + + @Override + public E remove(int location) { + if (modCount == fullList.modCount) { + if (0 <= location && location < size) { + E result = fullList.remove(location + offset); + size--; + modCount = fullList.modCount; + return result; + } + throw new IndexOutOfBoundsException(); + } + throw new TConcurrentModificationException(); + } + + @Override + protected void removeRange(int start, int end) { + if (start != end) { + if (modCount == fullList.modCount) { + fullList.removeRange(start + offset, end + offset); + size -= end - start; + modCount = fullList.modCount; + } else { + throw new TConcurrentModificationException(); + } + } + } + + @Override + public E set(int location, E object) { + if (modCount == fullList.modCount) { + if (0 <= location && location < size) { + return fullList.set(location + offset, object); + } + throw new TIndexOutOfBoundsException(); + } + throw new TConcurrentModificationException(); + } + + @Override + public int size() { + if (modCount == fullList.modCount) { + return size; + } + throw new TConcurrentModificationException(); + } + + void sizeChanged(boolean increment) { + if (increment) { + size++; + } else { + size--; + } + modCount = fullList.modCount; + } + } } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TArrayList.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TArrayList.java new file mode 100644 index 000000000..4837f169a --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TArrayList.java @@ -0,0 +1,172 @@ +/* + * 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.io.TSerializable; +import org.teavm.classlib.java.lang.*; + +/** + * + * @author Alexey Andreev + */ +public class TArrayList extends TAbstractList implements TCloneable, TSerializable { + private E[] array; + private int size; + + public TArrayList() { + this(10); + } + + @SuppressWarnings("unchecked") + public TArrayList(int initialCapacity) { + array = (E[])new Object[initialCapacity]; + } + + public TArrayList(TCollection c) { + this(c.size()); + TIterator iter = c.iterator(); + for (int i = 0; i < array.length; ++i) { + array[i] = iter.next(); + } + } + + public void trimToSize() { + array = Arrays.copyOf(array, size); + } + + public void ensureCapacity(int minCapacity) { + if (array.length < minCapacity) { + array = TArrays.copyOf(array, array.length + TMath.min(5, array.length / 2)); + } + } + + @Override + public E get(int index) { + checkIndex(index); + return array[index]; + } + + @Override + public int size() { + return size; + } + + @Override + public TObject clone() { + return new TArrayList<>(this); + } + + @Override + public E set(int index, E element) { + checkIndex(index); + E old = array[index]; + array[index] = element; + return old; + } + + @Override + public void add(int index, E element) { + checkIndexForAdd(index); + ensureCapacity(size + 1); + for (int i = size; i > index; --i) { + array[i] = array[i - 1]; + } + array[index] = element; + ++modCount; + } + + @Override + public E remove(int index) { + checkIndex(index); + E old = array[index]; + --size; + for (int i = index; i < size; ++i) { + array[i] = array[i + 1]; + } + array[size] = null; + ++modCount; + return old; + } + + @Override + public boolean remove(Object o) { + int index = indexOf(o); + if (index >= 0) { + remove(index); + return true; + } else { + return false; + } + } + + @Override + public void clear() { + Arrays.fill(array, 0, size, null); + size = 0; + } + + @Override + public boolean addAll(int index, TCollection c) { + checkIndexForAdd(index); + if (c.isEmpty()) { + return false; + } + ensureCapacity(size + c.size()); + int gap = c.size(); + size += gap; + for (int i = gap - 1; i > index; --i) { + array[i] = array[i - gap]; + } + TIterator iter = c.iterator(); + for (int i = 0; i < gap; ++i) { + array[index++] = iter.next(); + } + ++modCount; + return true; + } + + @Override + protected void removeRange(int start, int end) { + if (start > end) { + throw new TIllegalArgumentException(); + } + if (start < 0 || end > size) { + throw new TIndexOutOfBoundsException(); + } + if (start == end) { + return; + } + for (int i = end; i < size; ++i) { + array[start++] = array[end++]; + } + Arrays.fill(array, start, end, null); + size -= end - start; + ++modCount; + } + + private void checkIndex(int index) { + if (index < 0 || index >= size) { + throw new TIndexOutOfBoundsException(); + } + } + + private void checkIndexForAdd(int index) { + if (index < 0 || index > size) { + throw new TIndexOutOfBoundsException(); + } + } +} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TArrays.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TArrays.java index ce1b6d3ba..9cc2a55d3 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TArrays.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TArrays.java @@ -15,10 +15,7 @@ */ package org.teavm.classlib.java.util; -import org.teavm.classlib.java.lang.TMath; -import org.teavm.classlib.java.lang.TObject; -import org.teavm.classlib.java.lang.TString; -import org.teavm.classlib.java.lang.TStringBuilder; +import org.teavm.classlib.java.lang.*; /** * @@ -43,6 +40,16 @@ public class TArrays extends TObject { return result; } + public static T[] copyOf(T[] original, int newLength) { + @SuppressWarnings("unchecked") + T[] result = (T[])new Object[newLength]; + int sz = TMath.min(newLength, original.length); + for (int i = 0; i < sz; ++i) { + result[i] = original[i]; + } + return result; + } + public static TString toString(TObject[] a) { TStringBuilder sb = new TStringBuilder(); sb.append(TString.wrap("[")); @@ -159,4 +166,20 @@ public class TArrays extends TObject { sb.append(TString.wrap("]")); return TString.wrap(sb.toString()); } + + public static void fill(TObject[] a, int fromIndex, int toIndex, TObject val) { + if (fromIndex > toIndex) { + throw new TIllegalArgumentException(); + } + if (fromIndex < 0 || toIndex > a.length) { + throw new TIndexOutOfBoundsException(); + } + while (fromIndex < toIndex) { + a[fromIndex++] = val; + } + } + + public static void fill(TObject[] a, TObject val) { + fill(a, 0, a.length, val); + } } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TList.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TList.java index c297f20bb..2abc4789b 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TList.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TList.java @@ -15,13 +15,11 @@ */ package org.teavm.classlib.java.util; -import org.teavm.classlib.java.lang.TObject; - /** * * @author Alexey Andreev */ -public interface TList extends TCollection { +public interface TList extends TCollection { boolean addAll(int index, TCollection c); E get(int index); diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TListIterator.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TListIterator.java index addc83a83..90d2f0531 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TListIterator.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TListIterator.java @@ -15,13 +15,11 @@ */ package org.teavm.classlib.java.util; -import org.teavm.classlib.java.lang.TObject; - /** * * @author Alexey Andreev */ -public interface TListIterator extends TIterator { +public interface TListIterator extends TIterator { boolean hasPrevious(); E previous(); diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TNoSuchElementException.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TNoSuchElementException.java new file mode 100644 index 000000000..a51a92655 --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TNoSuchElementException.java @@ -0,0 +1,35 @@ +/* + * 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.TRuntimeException; +import org.teavm.classlib.java.lang.TString; + +/** + * + * @author Alexey Andreev + */ +public class TNoSuchElementException extends TRuntimeException { + private static final long serialVersionUID = -4890604137042866919L; + + public TNoSuchElementException() { + super(); + } + + public TNoSuchElementException(TString message) { + super(message); + } +}