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 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 <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) {
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 <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) {
return new TAbstractCollection<>() {
@Override public TIterator<T> iterator() {
@ -628,6 +633,16 @@ public class TCollections extends TObject {
}
public static <E> TSet<E> newSetFromMap(TMap<E, TBoolean> map) {
if (!map.isEmpty()) {
throw new IllegalArgumentException();
}
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 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<K, V> extends TAbstractMap<K, V> 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<K, V> extends TAbstractMap<K, V> 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 <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}.
*/
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}.
*/
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.
*/
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.
*/
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();) {
add(iter.next());
}
@ -179,12 +179,15 @@ public class THashSet<E> extends TAbstractSet<E> implements TCloneable, TSeriali
return backingMap.size();
}
THashMap<E, THashSet<E>> createBackingMap(int capacity, float loadFactor) {
return new THashMap<>(capacity, loadFactor);
}
@Override
public Object clone() {
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);
}
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) {
if (node == null) {
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() {
return (TLinkedHashMap<E, THashSet<E>>) backingMap;
}
@ -140,4 +134,11 @@ public class TLinkedHashSet<E> extends THashSet<E> implements TSequencedSet<E>,
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;
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<K, V> {
static <K, V> TComparator<TMap.Entry<K, V>> comparingByValue(TComparator<? super V> comp) {
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();
@ -65,7 +73,7 @@ public interface TMap<K, V> {
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<K, V> {
}
default V computeIfAbsent(K key, Function<? super K, ? extends V> 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<K, V> {
}
default V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> 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<K, V> {
}
default V compute(K key, BiFunction<? super K, ? super V, ? extends V> 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<K, V> {
}
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 newValue = (oldValue == null) ? value : remappingFunction.apply(oldValue, value);
if (newValue == null) {
@ -166,7 +173,7 @@ public interface TMap<K, V> {
}
default void forEach(BiConsumer<? super K, ? super V> action) {
Objects.requireNonNull(action);
TObjects.requireNonNull(action);
final TIterator<Entry<K, V>> iterator = entrySet().iterator();
while (iterator.hasNext()) {
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) {
return new TTemplateCollections.ImmutableEntry<>(requireNonNull(k), requireNonNull(v));
return new TTemplateCollections.ImmutableEntry<>(TObjects.requireNonNull(k), TObjects.requireNonNull(v));
}
@SuppressWarnings("unchecked")

View File

@ -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);
}
}

View File

@ -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 <T> int compare(T a, T b, TComparator<? super T> 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;
}
}

View File

@ -22,10 +22,10 @@ import org.teavm.classlib.java.lang.TBoolean;
* @author Alexey Andreev
* @param <E>
*/
public class TSetFromMap<E> extends TAbstractSet<E> {
class TSetFromMap<E> extends TAbstractSet<E> {
private TMap<E, TBoolean> map;
public TSetFromMap(TMap<E, TBoolean> map) {
TSetFromMap(TMap<E, TBoolean> map) {
this.map = map;
}
@ -73,4 +73,49 @@ public class TSetFromMap<E> extends TAbstractSet<E> {
public TIterator<E> 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.UnmodifiableCollectionTestSupport;
import org.teavm.junit.TeaVMTestRunner;
import org.teavm.junit.WholeClassCompilation;
@RunWith(TeaVMTestRunner.class)
@WholeClassCompilation
public class HashMapTest {
private HashMap<String, String> ht10;