diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/TCollections.java b/classlib/src/main/java/org/teavm/classlib/java/util/TCollections.java index bc86b888c..5927f019c 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/TCollections.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/TCollections.java @@ -18,6 +18,7 @@ package org.teavm.classlib.java.util; import java.util.RandomAccess; import org.teavm.classlib.java.lang.*; import org.teavm.classlib.java.util.TMap.Entry; +import org.teavm.classlib.java.util.random.TRandomGenerator; public class TCollections extends TObject { @SuppressWarnings("rawtypes") @@ -181,17 +182,6 @@ public class TCollections extends TObject { }; } - public static TList unmodifiableList(final TList list) { - return new TAbstractList<>() { - @Override public T get(int index) { - return list.get(index); - } - @Override public int size() { - return list.size(); - } - }; - } - public static TList nCopies(final int n, final T o) { return new TAbstractList<>() { @Override public T get(int index) { @@ -283,8 +273,12 @@ public class TCollections extends TObject { shuffle(list, new TRandom()); } - @SuppressWarnings("unchecked") public static void shuffle(TList list, TRandom rnd) { + shuffle(list, (TRandomGenerator) rnd); + } + + @SuppressWarnings("unchecked") + public static void shuffle(TList list, TRandomGenerator rnd) { if (list instanceof TRandomAccess) { shuffleRandomAccess(list, rnd); } else { @@ -295,7 +289,7 @@ public class TCollections extends TObject { } } - private static void shuffleRandomAccess(TList list, TRandom rnd) { + private static void shuffleRandomAccess(TList list, TRandomGenerator rnd) { for (int i = list.size() - 1; i > 0; --i) { int j = rnd.nextInt(i + 1); swap(list, i, j); @@ -460,6 +454,17 @@ public class TCollections extends TObject { return -1; } + public static TList unmodifiableList(final TList list) { + return new TAbstractList<>() { + @Override public T get(int index) { + return list.get(index); + } + @Override public int size() { + return list.size(); + } + }; + } + public static TCollection unmodifiableCollection(final TCollection c) { return new TAbstractCollection<>() { @Override public TIterator iterator() { @@ -628,6 +633,16 @@ public class TCollections extends TObject { } public static TSet newSetFromMap(TMap map) { + if (!map.isEmpty()) { + throw new IllegalArgumentException(); + } return new TSetFromMap<>(map); } + + public static TSequencedSet newSequencedSetFromMap(TSequencedMap map) { + if (!map.isEmpty()) { + throw new IllegalArgumentException(); + } + return new TSetFromMap.SequencedSetFromMap(map); + } } diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/THashMap.java b/classlib/src/main/java/org/teavm/classlib/java/util/THashMap.java index 93252b789..b5901c785 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/THashMap.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/THashMap.java @@ -28,6 +28,7 @@ public class THashMap extends TAbstractMap implements TCloneable, TS transient HashEntry[] elementData; transient int modCount; private static final int DEFAULT_SIZE = 16; + private static final float DEFAULT_LOAD_FACTOR = 0.75f; final float loadFactor; int threshold; @@ -244,7 +245,7 @@ public class THashMap extends TAbstractMap implements TCloneable, TS } public THashMap(int capacity) { - this(capacity, 0.75f); // default load factor of 0.75 + this(capacity, DEFAULT_LOAD_FACTOR); } private static int calculateCapacity(int x) { @@ -640,4 +641,15 @@ public class THashMap extends TAbstractMap implements TCloneable, TS static boolean areEqualKeys(Object key1, Object key2) { return (key1 == key2) || key1.equals(key2); } + + static int capacity(int size) { + return (int) Math.ceil(size / DEFAULT_LOAD_FACTOR); + } + + public static THashMap newHashMap(int size) { + if (size < 0) { + throw new IllegalArgumentException(); + } + return new THashMap<>(capacity(size)); + } } diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/THashSet.java b/classlib/src/main/java/org/teavm/classlib/java/util/THashSet.java index 7cc9d28e6..a67675f2a 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/THashSet.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/THashSet.java @@ -34,7 +34,7 @@ public class THashSet extends TAbstractSet implements TCloneable, TSeriali * Constructs a new empty instance of {@code HashSet}. */ public THashSet() { - this(new THashMap>()); + this(new THashMap<>()); } /** @@ -44,7 +44,7 @@ public class THashSet extends TAbstractSet implements TCloneable, TSeriali * the initial capacity of this {@code HashSet}. */ public THashSet(int capacity) { - this(new THashMap>(capacity)); + this(new THashMap<>(capacity)); } /** @@ -57,7 +57,7 @@ public class THashSet extends TAbstractSet implements TCloneable, TSeriali * the initial load factor. */ public THashSet(int capacity, float loadFactor) { - this(new THashMap>(capacity, loadFactor)); + this(new THashMap<>(capacity, loadFactor)); } /** @@ -68,7 +68,7 @@ public class THashSet extends TAbstractSet implements TCloneable, TSeriali * the collection of elements to add. */ public THashSet(TCollection collection) { - this(new THashMap>(collection.size() < 6 ? 11 : collection.size() * 2)); + this(new THashMap<>(collection.size() < 6 ? 11 : collection.size() * 2)); for (TIterator iter = collection.iterator(); iter.hasNext();) { add(iter.next()); } @@ -179,12 +179,15 @@ public class THashSet extends TAbstractSet implements TCloneable, TSeriali return backingMap.size(); } - THashMap> createBackingMap(int capacity, float loadFactor) { - return new THashMap<>(capacity, loadFactor); - } - @Override public Object clone() { return new THashSet<>(this); } + + public static THashSet newHashSet(int size) { + if (size < 0) { + throw new IllegalArgumentException(); + } + return new THashSet<>(THashMap.capacity(size)); + } } diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/TLinkedHashMap.java b/classlib/src/main/java/org/teavm/classlib/java/util/TLinkedHashMap.java index cbefe33fe..8fe865d84 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/TLinkedHashMap.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/TLinkedHashMap.java @@ -404,6 +404,13 @@ public class TLinkedHashMap extends THashMap implements TSequencedMa return new TReversedLinkedHashMap<>(this); } + public static TLinkedHashMap newLinkedHashMap(int size) { + if (size < 0) { + throw new IllegalArgumentException(); + } + return new TLinkedHashMap<>(THashMap.capacity(size)); + } + static T checkNotNull(T node) { if (node == null) { throw new TNoSuchElementException(); diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/TLinkedHashSet.java b/classlib/src/main/java/org/teavm/classlib/java/util/TLinkedHashSet.java index 5de785b94..202660ccd 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/TLinkedHashSet.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/TLinkedHashSet.java @@ -38,12 +38,6 @@ public class TLinkedHashSet extends THashSet implements TSequencedSet, } } - /* overrides method in HashMap */ - @Override - THashMap> createBackingMap(int capacity, float loadFactor) { - return new TLinkedHashMap<>(capacity, loadFactor); - } - private TLinkedHashMap> map() { return (TLinkedHashMap>) backingMap; } @@ -140,4 +134,11 @@ public class TLinkedHashSet extends THashSet implements TSequencedSet, return base; } } + + public static TLinkedHashSet newLinkedHashSet(int size) { + if (size < 0) { + throw new IllegalArgumentException(); + } + return new TLinkedHashSet<>(THashMap.capacity(size)); + } } diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/TMap.java b/classlib/src/main/java/org/teavm/classlib/java/util/TMap.java index 7335634a8..d0626c87f 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/TMap.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/TMap.java @@ -15,8 +15,6 @@ */ package org.teavm.classlib.java.util; -import static java.util.Objects.requireNonNull; -import java.util.Objects; import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.Function; @@ -44,6 +42,16 @@ public interface TMap { static TComparator> comparingByValue(TComparator comp) { return (a, b) -> comp.compare(a.getValue(), b.getValue()); } + + @SuppressWarnings("unchecked") + static TMap.Entry copyOf(TMap.Entry e) { + TObjects.requireNonNull(e); + if (e instanceof TTemplateCollections.ImmutableEntry) { + return (TMap.Entry) e; + } else { + return TMap.entry(e.getKey(), e.getValue()); + } + } } int size(); @@ -65,7 +73,7 @@ public interface TMap { V remove(Object key); default boolean remove(Object key, Object value) { - if (containsKey(key) && Objects.equals(get(key), value)) { + if (containsKey(key) && TObjects.equals(get(key), value)) { remove(key); return true; } @@ -109,7 +117,7 @@ public interface TMap { } default V computeIfAbsent(K key, Function mappingFunction) { - Objects.requireNonNull(mappingFunction); + TObjects.requireNonNull(mappingFunction); V v = get(key); if (v == null) { V newValue = mappingFunction.apply(key); @@ -122,11 +130,10 @@ public interface TMap { } default V computeIfPresent(K key, BiFunction remappingFunction) { - Objects.requireNonNull(remappingFunction); + TObjects.requireNonNull(remappingFunction); V v = get(key); if (v != null) { - V oldValue = v; - V newValue = remappingFunction.apply(key, oldValue); + V newValue = remappingFunction.apply(key, v); if (newValue != null) { put(key, newValue); } else { @@ -138,7 +145,7 @@ public interface TMap { } default V compute(K key, BiFunction remappingFunction) { - Objects.requireNonNull(remappingFunction); + TObjects.requireNonNull(remappingFunction); V oldValue = get(key); V newValue = remappingFunction.apply(key, oldValue); if (oldValue != null) { @@ -154,7 +161,7 @@ public interface TMap { } default V merge(K key, V value, BiFunction remappingFunction) { - Objects.requireNonNull(remappingFunction); + TObjects.requireNonNull(remappingFunction); V oldValue = get(key); V newValue = (oldValue == null) ? value : remappingFunction.apply(oldValue, value); if (newValue == null) { @@ -166,7 +173,7 @@ public interface TMap { } default void forEach(BiConsumer action) { - Objects.requireNonNull(action); + TObjects.requireNonNull(action); final TIterator> iterator = entrySet().iterator(); while (iterator.hasNext()) { final Entry entry = iterator.next(); @@ -296,7 +303,7 @@ public interface TMap { } static TMap.Entry entry(K k, V v) { - return new TTemplateCollections.ImmutableEntry<>(requireNonNull(k), requireNonNull(v)); + return new TTemplateCollections.ImmutableEntry<>(TObjects.requireNonNull(k), TObjects.requireNonNull(v)); } @SuppressWarnings("unchecked") diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/TNoSuchElementException.java b/classlib/src/main/java/org/teavm/classlib/java/util/TNoSuchElementException.java index 9147ee6e0..82701bb2b 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/TNoSuchElementException.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/TNoSuchElementException.java @@ -16,6 +16,7 @@ package org.teavm.classlib.java.util; import org.teavm.classlib.java.lang.TRuntimeException; +import org.teavm.classlib.java.lang.TThrowable; public class TNoSuchElementException extends TRuntimeException { private static final long serialVersionUID = -4890604137042866919L; @@ -27,4 +28,12 @@ public class TNoSuchElementException extends TRuntimeException { public TNoSuchElementException(String message) { super(message); } + + public TNoSuchElementException(String s, TThrowable cause) { + super(s, cause); + } + + public TNoSuchElementException(TThrowable cause) { + super(cause); + } } diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/TObjects.java b/classlib/src/main/java/org/teavm/classlib/java/util/TObjects.java index f46935ab1..d17f1a258 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/TObjects.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/TObjects.java @@ -38,6 +38,11 @@ public final class TObjects extends TObject { return o != null ? o.toString() : nullDefault; } + public static String toIdentityString(Object o) { + requireNonNull(o); + return o.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(o)); + } + public static int compare(T a, T b, TComparator c) { return a == null && b == null ? 0 : c.compare(a, b); } @@ -131,6 +136,13 @@ public final class TObjects extends TObject { return index; } + public static long checkIndex(long index, long length) { + if (index < 0 || index >= length) { + throw new IndexOutOfBoundsException(); + } + return index; + } + public static int checkFromToIndex(int fromIndex, int toIndex, int length) { if (fromIndex < 0 || fromIndex > toIndex || toIndex > length) { throw new IndexOutOfBoundsException(); @@ -138,10 +150,24 @@ public final class TObjects extends TObject { return fromIndex; } + public static long checkFromToIndex(long fromIndex, long toIndex, long length) { + if (fromIndex < 0 || fromIndex > toIndex || toIndex > length) { + throw new IndexOutOfBoundsException(); + } + return fromIndex; + } + public static int checkFromIndexSize(int fromIndex, int size, int length) { if (fromIndex < 0 || size < 0 || fromIndex + size > length) { throw new IndexOutOfBoundsException(); } return fromIndex; } + + public static long checkFromIndexSize(long fromIndex, long size, long length) { + if (fromIndex < 0 || size < 0 || fromIndex + size > length) { + throw new IndexOutOfBoundsException(); + } + return fromIndex; + } } diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/TSetFromMap.java b/classlib/src/main/java/org/teavm/classlib/java/util/TSetFromMap.java index 1ceb3ce9e..3e79aaa3e 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/TSetFromMap.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/TSetFromMap.java @@ -22,10 +22,10 @@ import org.teavm.classlib.java.lang.TBoolean; * @author Alexey Andreev * @param */ -public class TSetFromMap extends TAbstractSet { +class TSetFromMap extends TAbstractSet { private TMap map; - public TSetFromMap(TMap map) { + TSetFromMap(TMap map) { this.map = map; } @@ -73,4 +73,49 @@ public class TSetFromMap extends TAbstractSet { public TIterator iterator() { return map.keySet().iterator(); } + + static class SequencedSetFromMap extends TSetFromMap implements TSequencedSet { + SequencedSetFromMap(TSequencedMap map) { + super(map); + } + + private TSequencedMap map() { + return (TSequencedMap) super.map; + } + + @Override + public TSequencedSet reversed() { + return new SequencedSetFromMap<>(map().reversed()); + } + + @Override + public void addFirst(E e) { + map().putFirst(e, TBoolean.TRUE); + } + + @Override + public void addLast(E e) { + map().putLast(e, TBoolean.TRUE); + } + + @Override + public E getFirst() { + return TLinkedHashMap.checkNotNull(map().firstEntry()).getKey(); + } + + @Override + public E getLast() { + return TLinkedHashMap.checkNotNull(map().lastEntry()).getKey(); + } + + @Override + public E removeFirst() { + return TLinkedHashMap.checkNotNull(map().pollFirstEntry()).getKey(); + } + + @Override + public E removeLast() { + return TLinkedHashMap.checkNotNull(map().pollLastEntry()).getKey(); + } + } } diff --git a/tests/src/test/java/org/teavm/classlib/java/util/HashMapTest.java b/tests/src/test/java/org/teavm/classlib/java/util/HashMapTest.java index 401bf6d05..ff4ede710 100644 --- a/tests/src/test/java/org/teavm/classlib/java/util/HashMapTest.java +++ b/tests/src/test/java/org/teavm/classlib/java/util/HashMapTest.java @@ -39,10 +39,8 @@ import org.junit.runner.RunWith; import org.teavm.classlib.support.MapTest2Support; import org.teavm.classlib.support.UnmodifiableCollectionTestSupport; import org.teavm.junit.TeaVMTestRunner; -import org.teavm.junit.WholeClassCompilation; @RunWith(TeaVMTestRunner.class) -@WholeClassCompilation public class HashMapTest { private HashMap ht10;