classlib: more overrides for TreeMap keySet (#818)

This commit is contained in:
Ivan Hetman 2023-10-13 20:57:32 +03:00 committed by GitHub
parent 4a81615749
commit 6faecc91d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 166 additions and 43 deletions

View File

@ -18,6 +18,7 @@ package org.teavm.classlib.java.util;
import java.util.RandomAccess; import java.util.RandomAccess;
import org.teavm.classlib.java.lang.*; import org.teavm.classlib.java.lang.*;
import org.teavm.classlib.java.util.TMap.Entry; import org.teavm.classlib.java.util.TMap.Entry;
import org.teavm.classlib.java.util.random.TRandomGenerator;
public class TCollections extends TObject { public class TCollections extends TObject {
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
@ -181,17 +182,6 @@ public class TCollections extends TObject {
}; };
} }
public static <T> TList<T> unmodifiableList(final TList<? extends T> list) {
return new TAbstractList<>() {
@Override public T get(int index) {
return list.get(index);
}
@Override public int size() {
return list.size();
}
};
}
public static <T> TList<T> nCopies(final int n, final T o) { public static <T> TList<T> nCopies(final int n, final T o) {
return new TAbstractList<>() { return new TAbstractList<>() {
@Override public T get(int index) { @Override public T get(int index) {
@ -283,8 +273,12 @@ public class TCollections extends TObject {
shuffle(list, new TRandom()); shuffle(list, new TRandom());
} }
@SuppressWarnings("unchecked")
public static void shuffle(TList<?> list, TRandom rnd) { 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) { if (list instanceof TRandomAccess) {
shuffleRandomAccess(list, rnd); shuffleRandomAccess(list, rnd);
} else { } 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) { for (int i = list.size() - 1; i > 0; --i) {
int j = rnd.nextInt(i + 1); int j = rnd.nextInt(i + 1);
swap(list, i, j); swap(list, i, j);
@ -460,6 +454,17 @@ public class TCollections extends TObject {
return -1; return -1;
} }
public static <T> TList<T> unmodifiableList(final TList<? extends T> list) {
return new TAbstractList<>() {
@Override public T get(int index) {
return list.get(index);
}
@Override public int size() {
return list.size();
}
};
}
public static <T> TCollection<T> unmodifiableCollection(final TCollection<? extends T> c) { public static <T> TCollection<T> unmodifiableCollection(final TCollection<? extends T> c) {
return new TAbstractCollection<>() { return new TAbstractCollection<>() {
@Override public TIterator<T> iterator() { @Override public TIterator<T> iterator() {
@ -628,6 +633,16 @@ public class TCollections extends TObject {
} }
public static <E> TSet<E> newSetFromMap(TMap<E, TBoolean> map) { public static <E> TSet<E> newSetFromMap(TMap<E, TBoolean> map) {
if (!map.isEmpty()) {
throw new IllegalArgumentException();
}
return new TSetFromMap<>(map); return new TSetFromMap<>(map);
} }
public static <E> TSequencedSet<E> newSequencedSetFromMap(TSequencedMap<E, TBoolean> map) {
if (!map.isEmpty()) {
throw new IllegalArgumentException();
}
return new TSetFromMap.SequencedSetFromMap<E>(map);
}
} }

View File

@ -28,6 +28,7 @@ public class THashMap<K, V> extends TAbstractMap<K, V> implements TCloneable, TS
transient HashEntry<K, V>[] elementData; transient HashEntry<K, V>[] elementData;
transient int modCount; transient int modCount;
private static final int DEFAULT_SIZE = 16; private static final int DEFAULT_SIZE = 16;
private static final float DEFAULT_LOAD_FACTOR = 0.75f;
final float loadFactor; final float loadFactor;
int threshold; int threshold;
@ -244,7 +245,7 @@ public class THashMap<K, V> extends TAbstractMap<K, V> implements TCloneable, TS
} }
public THashMap(int capacity) { 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) { private static int calculateCapacity(int x) {
@ -640,4 +641,15 @@ public class THashMap<K, V> extends TAbstractMap<K, V> implements TCloneable, TS
static boolean areEqualKeys(Object key1, Object key2) { static boolean areEqualKeys(Object key1, Object key2) {
return (key1 == key2) || key1.equals(key2); return (key1 == key2) || key1.equals(key2);
} }
static int capacity(int size) {
return (int) Math.ceil(size / DEFAULT_LOAD_FACTOR);
}
public static <K, V> THashMap<K, V> newHashMap(int size) {
if (size < 0) {
throw new IllegalArgumentException();
}
return new THashMap<>(capacity(size));
}
} }

View File

@ -34,7 +34,7 @@ public class THashSet<E> extends TAbstractSet<E> implements TCloneable, TSeriali
* Constructs a new empty instance of {@code HashSet}. * Constructs a new empty instance of {@code HashSet}.
*/ */
public THashSet() { public THashSet() {
this(new THashMap<E, THashSet<E>>()); this(new THashMap<>());
} }
/** /**
@ -44,7 +44,7 @@ public class THashSet<E> extends TAbstractSet<E> implements TCloneable, TSeriali
* the initial capacity of this {@code HashSet}. * the initial capacity of this {@code HashSet}.
*/ */
public THashSet(int capacity) { public THashSet(int capacity) {
this(new THashMap<E, THashSet<E>>(capacity)); this(new THashMap<>(capacity));
} }
/** /**
@ -57,7 +57,7 @@ public class THashSet<E> extends TAbstractSet<E> implements TCloneable, TSeriali
* the initial load factor. * the initial load factor.
*/ */
public THashSet(int capacity, float loadFactor) { public THashSet(int capacity, float loadFactor) {
this(new THashMap<E, THashSet<E>>(capacity, loadFactor)); this(new THashMap<>(capacity, loadFactor));
} }
/** /**
@ -68,7 +68,7 @@ public class THashSet<E> extends TAbstractSet<E> implements TCloneable, TSeriali
* the collection of elements to add. * the collection of elements to add.
*/ */
public THashSet(TCollection<? extends E> collection) { public THashSet(TCollection<? extends E> collection) {
this(new THashMap<E, THashSet<E>>(collection.size() < 6 ? 11 : collection.size() * 2)); this(new THashMap<>(collection.size() < 6 ? 11 : collection.size() * 2));
for (TIterator<? extends E> iter = collection.iterator(); iter.hasNext();) { for (TIterator<? extends E> iter = collection.iterator(); iter.hasNext();) {
add(iter.next()); add(iter.next());
} }
@ -179,12 +179,15 @@ public class THashSet<E> extends TAbstractSet<E> implements TCloneable, TSeriali
return backingMap.size(); return backingMap.size();
} }
THashMap<E, THashSet<E>> createBackingMap(int capacity, float loadFactor) {
return new THashMap<>(capacity, loadFactor);
}
@Override @Override
public Object clone() { public Object clone() {
return new THashSet<>(this); return new THashSet<>(this);
} }
public static <T> THashSet<T> newHashSet(int size) {
if (size < 0) {
throw new IllegalArgumentException();
}
return new THashSet<>(THashMap.capacity(size));
}
} }

View File

@ -404,6 +404,13 @@ public class TLinkedHashMap<K, V> extends THashMap<K, V> implements TSequencedMa
return new TReversedLinkedHashMap<>(this); return new TReversedLinkedHashMap<>(this);
} }
public static <K, V> TLinkedHashMap<K, V> newLinkedHashMap(int size) {
if (size < 0) {
throw new IllegalArgumentException();
}
return new TLinkedHashMap<>(THashMap.capacity(size));
}
static <T> T checkNotNull(T node) { static <T> T checkNotNull(T node) {
if (node == null) { if (node == null) {
throw new TNoSuchElementException(); throw new TNoSuchElementException();

View File

@ -38,12 +38,6 @@ public class TLinkedHashSet<E> extends THashSet<E> implements TSequencedSet<E>,
} }
} }
/* overrides method in HashMap */
@Override
THashMap<E, THashSet<E>> createBackingMap(int capacity, float loadFactor) {
return new TLinkedHashMap<>(capacity, loadFactor);
}
private TLinkedHashMap<E, THashSet<E>> map() { private TLinkedHashMap<E, THashSet<E>> map() {
return (TLinkedHashMap<E, THashSet<E>>) backingMap; return (TLinkedHashMap<E, THashSet<E>>) backingMap;
} }
@ -140,4 +134,11 @@ public class TLinkedHashSet<E> extends THashSet<E> implements TSequencedSet<E>,
return base; return base;
} }
} }
public static <T> TLinkedHashSet<T> newLinkedHashSet(int size) {
if (size < 0) {
throw new IllegalArgumentException();
}
return new TLinkedHashSet<>(THashMap.capacity(size));
}
} }

View File

@ -15,8 +15,6 @@
*/ */
package org.teavm.classlib.java.util; 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.BiConsumer;
import java.util.function.BiFunction; import java.util.function.BiFunction;
import java.util.function.Function; import java.util.function.Function;
@ -44,6 +42,16 @@ public interface TMap<K, V> {
static <K, V> TComparator<TMap.Entry<K, V>> comparingByValue(TComparator<? super V> comp) { static <K, V> TComparator<TMap.Entry<K, V>> comparingByValue(TComparator<? super V> comp) {
return (a, b) -> comp.compare(a.getValue(), b.getValue()); return (a, b) -> comp.compare(a.getValue(), b.getValue());
} }
@SuppressWarnings("unchecked")
static <K, V> TMap.Entry<K, V> copyOf(TMap.Entry<? extends K, ? extends V> e) {
TObjects.requireNonNull(e);
if (e instanceof TTemplateCollections.ImmutableEntry) {
return (TMap.Entry<K, V>) e;
} else {
return TMap.entry(e.getKey(), e.getValue());
}
}
} }
int size(); int size();
@ -65,7 +73,7 @@ public interface TMap<K, V> {
V remove(Object key); V remove(Object key);
default boolean remove(Object key, Object value) { 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); remove(key);
return true; return true;
} }
@ -109,7 +117,7 @@ public interface TMap<K, V> {
} }
default V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) { default V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
Objects.requireNonNull(mappingFunction); TObjects.requireNonNull(mappingFunction);
V v = get(key); V v = get(key);
if (v == null) { if (v == null) {
V newValue = mappingFunction.apply(key); V newValue = mappingFunction.apply(key);
@ -122,11 +130,10 @@ public interface TMap<K, V> {
} }
default V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) { default V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
Objects.requireNonNull(remappingFunction); TObjects.requireNonNull(remappingFunction);
V v = get(key); V v = get(key);
if (v != null) { if (v != null) {
V oldValue = v; V newValue = remappingFunction.apply(key, v);
V newValue = remappingFunction.apply(key, oldValue);
if (newValue != null) { if (newValue != null) {
put(key, newValue); put(key, newValue);
} else { } else {
@ -138,7 +145,7 @@ public interface TMap<K, V> {
} }
default V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) { default V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
Objects.requireNonNull(remappingFunction); TObjects.requireNonNull(remappingFunction);
V oldValue = get(key); V oldValue = get(key);
V newValue = remappingFunction.apply(key, oldValue); V newValue = remappingFunction.apply(key, oldValue);
if (oldValue != null) { if (oldValue != null) {
@ -154,7 +161,7 @@ public interface TMap<K, V> {
} }
default V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) { default V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
Objects.requireNonNull(remappingFunction); TObjects.requireNonNull(remappingFunction);
V oldValue = get(key); V oldValue = get(key);
V newValue = (oldValue == null) ? value : remappingFunction.apply(oldValue, value); V newValue = (oldValue == null) ? value : remappingFunction.apply(oldValue, value);
if (newValue == null) { if (newValue == null) {
@ -166,7 +173,7 @@ public interface TMap<K, V> {
} }
default void forEach(BiConsumer<? super K, ? super V> action) { default void forEach(BiConsumer<? super K, ? super V> action) {
Objects.requireNonNull(action); TObjects.requireNonNull(action);
final TIterator<Entry<K, V>> iterator = entrySet().iterator(); final TIterator<Entry<K, V>> iterator = entrySet().iterator();
while (iterator.hasNext()) { while (iterator.hasNext()) {
final Entry<K, V> entry = iterator.next(); final Entry<K, V> entry = iterator.next();
@ -296,7 +303,7 @@ public interface TMap<K, V> {
} }
static <K, V> TMap.Entry<K, V> entry(K k, V v) { static <K, V> TMap.Entry<K, V> 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") @SuppressWarnings("unchecked")

View File

@ -16,6 +16,7 @@
package org.teavm.classlib.java.util; package org.teavm.classlib.java.util;
import org.teavm.classlib.java.lang.TRuntimeException; import org.teavm.classlib.java.lang.TRuntimeException;
import org.teavm.classlib.java.lang.TThrowable;
public class TNoSuchElementException extends TRuntimeException { public class TNoSuchElementException extends TRuntimeException {
private static final long serialVersionUID = -4890604137042866919L; private static final long serialVersionUID = -4890604137042866919L;
@ -27,4 +28,12 @@ public class TNoSuchElementException extends TRuntimeException {
public TNoSuchElementException(String message) { public TNoSuchElementException(String message) {
super(message); super(message);
} }
public TNoSuchElementException(String s, TThrowable cause) {
super(s, cause);
}
public TNoSuchElementException(TThrowable cause) {
super(cause);
}
} }

View File

@ -38,6 +38,11 @@ public final class TObjects extends TObject {
return o != null ? o.toString() : nullDefault; 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 <T> int compare(T a, T b, TComparator<? super T> c) { public static <T> int compare(T a, T b, TComparator<? super T> c) {
return a == null && b == null ? 0 : c.compare(a, b); return a == null && b == null ? 0 : c.compare(a, b);
} }
@ -131,6 +136,13 @@ public final class TObjects extends TObject {
return index; 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) { public static int checkFromToIndex(int fromIndex, int toIndex, int length) {
if (fromIndex < 0 || fromIndex > toIndex || toIndex > length) { if (fromIndex < 0 || fromIndex > toIndex || toIndex > length) {
throw new IndexOutOfBoundsException(); throw new IndexOutOfBoundsException();
@ -138,10 +150,24 @@ public final class TObjects extends TObject {
return fromIndex; 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) { public static int checkFromIndexSize(int fromIndex, int size, int length) {
if (fromIndex < 0 || size < 0 || fromIndex + size > length) { if (fromIndex < 0 || size < 0 || fromIndex + size > length) {
throw new IndexOutOfBoundsException(); throw new IndexOutOfBoundsException();
} }
return fromIndex; 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;
}
} }

View File

@ -22,10 +22,10 @@ import org.teavm.classlib.java.lang.TBoolean;
* @author Alexey Andreev * @author Alexey Andreev
* @param <E> * @param <E>
*/ */
public class TSetFromMap<E> extends TAbstractSet<E> { class TSetFromMap<E> extends TAbstractSet<E> {
private TMap<E, TBoolean> map; private TMap<E, TBoolean> map;
public TSetFromMap(TMap<E, TBoolean> map) { TSetFromMap(TMap<E, TBoolean> map) {
this.map = map; this.map = map;
} }
@ -73,4 +73,49 @@ public class TSetFromMap<E> extends TAbstractSet<E> {
public TIterator<E> iterator() { public TIterator<E> iterator() {
return map.keySet().iterator(); return map.keySet().iterator();
} }
static class SequencedSetFromMap<E> extends TSetFromMap<E> implements TSequencedSet<E> {
SequencedSetFromMap(TSequencedMap<E, TBoolean> map) {
super(map);
}
private TSequencedMap<E, TBoolean> map() {
return (TSequencedMap<E, TBoolean>) super.map;
}
@Override
public TSequencedSet<E> 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();
}
}
} }

View File

@ -39,10 +39,8 @@ import org.junit.runner.RunWith;
import org.teavm.classlib.support.MapTest2Support; import org.teavm.classlib.support.MapTest2Support;
import org.teavm.classlib.support.UnmodifiableCollectionTestSupport; import org.teavm.classlib.support.UnmodifiableCollectionTestSupport;
import org.teavm.junit.TeaVMTestRunner; import org.teavm.junit.TeaVMTestRunner;
import org.teavm.junit.WholeClassCompilation;
@RunWith(TeaVMTestRunner.class) @RunWith(TeaVMTestRunner.class)
@WholeClassCompilation
public class HashMapTest { public class HashMapTest {
private HashMap<String, String> ht10; private HashMap<String, String> ht10;