mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14:10 -08:00
classlib: fix issues in EnumSet and EnumMap (#834)
This commit is contained in:
parent
16cd0aaab2
commit
4b6c4bd3d3
|
@ -107,6 +107,7 @@ public abstract class TAbstractCollection<E> extends TObject implements TCollect
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean removeAll(TCollection<?> c) {
|
public boolean removeAll(TCollection<?> c) {
|
||||||
|
TObjects.requireNonNull(c);
|
||||||
boolean changed = false;
|
boolean changed = false;
|
||||||
for (TIterator<E> iter = iterator(); iter.hasNext();) {
|
for (TIterator<E> iter = iterator(); iter.hasNext();) {
|
||||||
E e = iter.next();
|
E e = iter.next();
|
||||||
|
@ -120,6 +121,7 @@ public abstract class TAbstractCollection<E> extends TObject implements TCollect
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean retainAll(TCollection<?> c) {
|
public boolean retainAll(TCollection<?> c) {
|
||||||
|
TObjects.requireNonNull(c);
|
||||||
boolean changed = false;
|
boolean changed = false;
|
||||||
for (TIterator<E> iter = iterator(); iter.hasNext();) {
|
for (TIterator<E> iter = iterator(); iter.hasNext();) {
|
||||||
E e = iter.next();
|
E e = iter.next();
|
||||||
|
|
|
@ -16,21 +16,16 @@
|
||||||
package org.teavm.classlib.java.util;
|
package org.teavm.classlib.java.util;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.AbstractMap;
|
|
||||||
import java.util.AbstractSet;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Iterator;
|
import org.teavm.classlib.java.lang.TCloneNotSupportedException;
|
||||||
import java.util.Map;
|
import org.teavm.interop.Rename;
|
||||||
import java.util.NoSuchElementException;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public class TEnumMap<K extends Enum<K>, V> extends AbstractMap<K, V> implements Serializable, Cloneable {
|
public class TEnumMap<K extends Enum<K>, V> extends TAbstractMap<K, V> implements Serializable, Cloneable {
|
||||||
private Class<K> keyType;
|
private Class<K> keyType;
|
||||||
private Object[] data;
|
private Object[] data;
|
||||||
private boolean[] provided;
|
private boolean[] provided;
|
||||||
private int size;
|
private int size;
|
||||||
private Set<Entry<K, V>> entrySet;
|
private TSet<Entry<K, V>> entrySet;
|
||||||
|
|
||||||
public TEnumMap(Class<K> keyType) {
|
public TEnumMap(Class<K> keyType) {
|
||||||
initFromKeyType(keyType);
|
initFromKeyType(keyType);
|
||||||
|
@ -40,16 +35,24 @@ public class TEnumMap<K extends Enum<K>, V> extends AbstractMap<K, V> implements
|
||||||
initFromOtherEnumMap(m);
|
initFromOtherEnumMap(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TEnumMap(Map<K, V> m) {
|
public TEnumMap(TMap<K, V> m) {
|
||||||
if (m instanceof TEnumMap) {
|
if (m instanceof TEnumMap) {
|
||||||
initFromOtherEnumMap((TEnumMap<K, V>) m);
|
initFromOtherEnumMap((TEnumMap<K, V>) m);
|
||||||
} else {
|
} else {
|
||||||
if (m.isEmpty()) {
|
if (m.isEmpty()) {
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
}
|
}
|
||||||
initFromKeyType(m.keySet().iterator().next().getDeclaringClass());
|
for (TIterator<? extends TMap.Entry<K, V>> it = m.entrySet().iterator(); it.hasNext();) {
|
||||||
for (Entry<K, V> entry : m.entrySet()) {
|
TMap.Entry<K, V> entry = it.next();
|
||||||
int index = entry.getKey().ordinal();
|
K key = entry.getKey();
|
||||||
|
if (keyType == null) {
|
||||||
|
initFromKeyType(key.getDeclaringClass());
|
||||||
|
}
|
||||||
|
Class<?> cls = key.getClass();
|
||||||
|
if (cls != keyType && cls.getSuperclass() != keyType) {
|
||||||
|
throw new ClassCastException();
|
||||||
|
}
|
||||||
|
int index = key.ordinal();
|
||||||
provided[index] = true;
|
provided[index] = true;
|
||||||
data[index] = entry.getValue();
|
data[index] = entry.getValue();
|
||||||
}
|
}
|
||||||
|
@ -78,7 +81,7 @@ public class TEnumMap<K extends Enum<K>, V> extends AbstractMap<K, V> implements
|
||||||
@Override
|
@Override
|
||||||
public boolean containsValue(Object value) {
|
public boolean containsValue(Object value) {
|
||||||
for (int i = 0; i < data.length; ++i) {
|
for (int i = 0; i < data.length; ++i) {
|
||||||
if (provided[i] && Objects.equals(value, data[i])) {
|
if (provided[i] && TObjects.equals(value, data[i])) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -107,6 +110,10 @@ public class TEnumMap<K extends Enum<K>, V> extends AbstractMap<K, V> implements
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public V put(K key, V value) {
|
public V put(K key, V value) {
|
||||||
|
Class<?> cls = key.getClass();
|
||||||
|
if (cls != keyType && cls.getSuperclass() != keyType) {
|
||||||
|
throw new ClassCastException();
|
||||||
|
}
|
||||||
int index = key.ordinal();
|
int index = key.ordinal();
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
V old = (V) data[index];
|
V old = (V) data[index];
|
||||||
|
@ -135,14 +142,24 @@ public class TEnumMap<K extends Enum<K>, V> extends AbstractMap<K, V> implements
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void putAll(Map<? extends K, ? extends V> m) {
|
@SuppressWarnings("unchecked")
|
||||||
for (Map.Entry<? extends K, ? extends V> entry : m.entrySet()) {
|
public void putAll(TMap<? extends K, ? extends V> m) {
|
||||||
int index = entry.getKey().ordinal();
|
if (m instanceof TEnumMap) {
|
||||||
if (!provided[index]) {
|
TEnumMap<K, V> em = (TEnumMap<K, V>) m;
|
||||||
provided[index] = true;
|
if (!em.isEmpty() && this.keyType != em.keyType) {
|
||||||
|
throw new ClassCastException(em.keyType + " != " + keyType);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < data.length; i++) {
|
||||||
|
if (em.provided[i]) {
|
||||||
|
this.data[i] = em.data[i];
|
||||||
|
if (!this.provided[i]) {
|
||||||
|
this.provided[i] = true;
|
||||||
size++;
|
size++;
|
||||||
}
|
}
|
||||||
data[index] = entry.getValue();
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
super.putAll(m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,13 +172,29 @@ public class TEnumMap<K extends Enum<K>, V> extends AbstractMap<K, V> implements
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Rename("clone")
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public TEnumMap<K, V> clone0() {
|
||||||
|
try {
|
||||||
|
TEnumMap<K, V> map = (TEnumMap<K, V>) super.clone();
|
||||||
|
map.keyType = this.keyType;
|
||||||
|
map.provided = this.provided.clone();
|
||||||
|
map.data = this.data.clone();
|
||||||
|
map.size = this.size;
|
||||||
|
|
||||||
|
return map;
|
||||||
|
} catch (TCloneNotSupportedException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<Entry<K, V>> entrySet() {
|
public TSet<Entry<K, V>> entrySet() {
|
||||||
if (entrySet == null) {
|
if (entrySet == null) {
|
||||||
entrySet = new AbstractSet<Entry<K, V>>() {
|
entrySet = new TAbstractSet<>() {
|
||||||
@Override
|
@Override
|
||||||
public Iterator<Entry<K, V>> iterator() {
|
public TIterator<Entry<K, V>> iterator() {
|
||||||
return new Iterator<Entry<K, V>>() {
|
return new TIterator<>() {
|
||||||
int index;
|
int index;
|
||||||
int removeIndex = -1;
|
int removeIndex = -1;
|
||||||
|
|
||||||
|
@ -177,7 +210,7 @@ public class TEnumMap<K extends Enum<K>, V> extends AbstractMap<K, V> implements
|
||||||
@Override
|
@Override
|
||||||
public Entry<K, V> next() {
|
public Entry<K, V> next() {
|
||||||
if (index >= data.length) {
|
if (index >= data.length) {
|
||||||
throw new NoSuchElementException();
|
throw new TNoSuchElementException();
|
||||||
}
|
}
|
||||||
removeIndex = index;
|
removeIndex = index;
|
||||||
EntryImpl result = new EntryImpl(index++);
|
EntryImpl result = new EntryImpl(index++);
|
||||||
|
@ -196,9 +229,11 @@ public class TEnumMap<K extends Enum<K>, V> extends AbstractMap<K, V> implements
|
||||||
if (removeIndex < 0) {
|
if (removeIndex < 0) {
|
||||||
throw new IllegalStateException();
|
throw new IllegalStateException();
|
||||||
}
|
}
|
||||||
|
if (provided[removeIndex]) {
|
||||||
data[removeIndex] = null;
|
data[removeIndex] = null;
|
||||||
provided[removeIndex] = false;
|
provided[removeIndex] = false;
|
||||||
size--;
|
size--;
|
||||||
|
}
|
||||||
removeIndex = -1;
|
removeIndex = -1;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -210,12 +245,32 @@ public class TEnumMap<K extends Enum<K>, V> extends AbstractMap<K, V> implements
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean remove(Object o) {
|
public boolean contains(Object o) {
|
||||||
if (!keyType.isInstance(o)) {
|
if (!(o instanceof TMap.Entry<?, ?>)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int index = ((Enum<?>) o).ordinal();
|
TMap.Entry<?, ?> e = (TMap.Entry<?, ?>) o;
|
||||||
if (provided[index]) {
|
Class<?> cls = e.getKey().getClass();
|
||||||
|
if (cls != keyType && cls.getSuperclass() != keyType) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int index = ((Enum<?>) e.getKey()).ordinal();
|
||||||
|
return provided[index] && TObjects.equals(data[index], e.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean remove(Object o) {
|
||||||
|
if (!(o instanceof TMap.Entry<?, ?>)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
TMap.Entry<?, ?> e = (TMap.Entry<?, ?>) o;
|
||||||
|
|
||||||
|
Class<?> cls = e.getKey().getClass();
|
||||||
|
if (cls != keyType && cls.getSuperclass() != keyType) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int index = ((Enum<?>) e.getKey()).ordinal();
|
||||||
|
if (provided[index] && TObjects.equals(e.getValue(), data[index])) {
|
||||||
provided[index] = false;
|
provided[index] = false;
|
||||||
data[index] = null;
|
data[index] = null;
|
||||||
size--;
|
size--;
|
||||||
|
@ -237,28 +292,119 @@ public class TEnumMap<K extends Enum<K>, V> extends AbstractMap<K, V> implements
|
||||||
this.index = index;
|
this.index = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public K getKey() {
|
private K key() {
|
||||||
return (K) TGenericEnumSet.getConstants(keyType)[index];
|
return (K) TGenericEnumSet.getConstants(keyType)[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public V getValue() {
|
private V value() {
|
||||||
return (V) data[index];
|
return (V) data[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public K getKey() {
|
||||||
|
if (!provided[index]) {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
return key();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public V getValue() {
|
||||||
|
if (!provided[index]) {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
return value();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public V setValue(V value) {
|
public V setValue(V value) {
|
||||||
|
if (!provided[index]) {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
V old = (V) data[index];
|
V old = (V) data[index];
|
||||||
data[index] = value;
|
data[index] = value;
|
||||||
return old;
|
return old;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (obj instanceof TMap.Entry) {
|
||||||
|
TMap.Entry<?, ?> entry = (TMap.Entry<?, ?>) obj;
|
||||||
|
return TObjects.equals(key(), entry.getKey()) && TObjects.equals(value(), entry.getValue());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return TObjects.hashCode(key()) ^ TObjects.hashCode(value());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return key() + "=" + value();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return entrySet;
|
return entrySet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TCollection<V> values() {
|
||||||
|
if (cachedValues == null) {
|
||||||
|
cachedValues = new TAbstractCollection<>() {
|
||||||
|
@Override
|
||||||
|
public int size() {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean contains(Object o) {
|
||||||
|
return containsValue(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean remove(Object o) {
|
||||||
|
for (int i = 0; i < data.length; i++) {
|
||||||
|
if (provided[i] && TObjects.equals(o, data[i])) {
|
||||||
|
data[i] = null;
|
||||||
|
provided[i] = false;
|
||||||
|
size--;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clear() {
|
||||||
|
TEnumMap.this.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TIterator<V> iterator() {
|
||||||
|
final TIterator<TMap.Entry<K, V>> it = entrySet().iterator();
|
||||||
|
return new TIterator<>() {
|
||||||
|
@Override public boolean hasNext() {
|
||||||
|
return it.hasNext();
|
||||||
|
}
|
||||||
|
@Override public V next() {
|
||||||
|
return it.next().getValue();
|
||||||
|
}
|
||||||
|
@Override public void remove() {
|
||||||
|
it.remove();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return cachedValues;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,10 +28,16 @@ public abstract class TEnumSet<E extends Enum<E>> extends AbstractSet<E> impleme
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <E extends Enum<E>> TEnumSet<E> allOf(Class<E> elementType) {
|
public static <E extends Enum<E>> TEnumSet<E> allOf(Class<E> elementType) {
|
||||||
int count = TGenericEnumSet.getConstants(elementType).length;
|
Enum<?>[] constants = TGenericEnumSet.getConstants(elementType);
|
||||||
int[] bits = new int[((count - 1) / 32) + 1];
|
if (constants == null) {
|
||||||
|
throw new ClassCastException();
|
||||||
|
}
|
||||||
|
int count = constants.length;
|
||||||
|
int[] bits = new int[count == 0 ? 0 : ((count - 1) / Integer.SIZE) + 1];
|
||||||
Arrays.fill(bits, ~0);
|
Arrays.fill(bits, ~0);
|
||||||
|
if (count > 0) {
|
||||||
zeroHighBits(bits, count);
|
zeroHighBits(bits, count);
|
||||||
|
}
|
||||||
return new TGenericEnumSet<>(elementType, bits);
|
return new TGenericEnumSet<>(elementType, bits);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +68,7 @@ public abstract class TEnumSet<E extends Enum<E>> extends AbstractSet<E> impleme
|
||||||
TGenericEnumSet<E> other = (TGenericEnumSet<E>) s;
|
TGenericEnumSet<E> other = (TGenericEnumSet<E>) s;
|
||||||
int count = TGenericEnumSet.getConstants(other.cls).length;
|
int count = TGenericEnumSet.getConstants(other.cls).length;
|
||||||
int[] bits = new int[other.bits.length];
|
int[] bits = new int[other.bits.length];
|
||||||
for (int i = 0; i < bits.length - 1; ++i) {
|
for (int i = 0; i < bits.length; ++i) {
|
||||||
bits[i] = ~other.bits[i];
|
bits[i] = ~other.bits[i];
|
||||||
}
|
}
|
||||||
zeroHighBits(bits, count);
|
zeroHighBits(bits, count);
|
||||||
|
@ -148,6 +154,6 @@ public abstract class TEnumSet<E extends Enum<E>> extends AbstractSet<E> impleme
|
||||||
abstract void fastAdd(int n);
|
abstract void fastAdd(int n);
|
||||||
|
|
||||||
private static void zeroHighBits(int[] bits, int count) {
|
private static void zeroHighBits(int[] bits, int count) {
|
||||||
bits[bits.length - 1] &= (~0) >>> (32 - count % 32);
|
bits[bits.length - 1] &= ~0 >>> (Integer.SIZE - count % Integer.SIZE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,6 @@ package org.teavm.classlib.java.util;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.NoSuchElementException;
|
|
||||||
import org.teavm.classlib.java.lang.TClass;
|
import org.teavm.classlib.java.lang.TClass;
|
||||||
import org.teavm.platform.Platform;
|
import org.teavm.platform.Platform;
|
||||||
import org.teavm.platform.PlatformClass;
|
import org.teavm.platform.PlatformClass;
|
||||||
|
@ -29,8 +28,12 @@ class TGenericEnumSet<E extends Enum<E>> extends TEnumSet<E> {
|
||||||
|
|
||||||
TGenericEnumSet(Class<E> cls) {
|
TGenericEnumSet(Class<E> cls) {
|
||||||
this.cls = cls;
|
this.cls = cls;
|
||||||
int constantCount = getConstants(cls).length;
|
Enum<?>[] constants = getConstants(cls);
|
||||||
int bitCount = ((constantCount - 1) / 32) + 1;
|
if (constants == null) {
|
||||||
|
throw new ClassCastException();
|
||||||
|
}
|
||||||
|
int constantCount = constants.length;
|
||||||
|
int bitCount = constantCount == 0 ? 0 : ((constantCount - 1) / Integer.SIZE) + 1;
|
||||||
this.bits = new int[bitCount];
|
this.bits = new int[bitCount];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,34 +50,39 @@ class TGenericEnumSet<E extends Enum<E>> extends TEnumSet<E> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Iterator<E> iterator() {
|
public Iterator<E> iterator() {
|
||||||
return new Iterator<E>() {
|
return new Iterator<>() {
|
||||||
int index;
|
private int index = find();
|
||||||
int indexToRemove = -1;
|
private int indexToRemove = -1;
|
||||||
int count = size();
|
|
||||||
|
private int find() {
|
||||||
|
int overflow = bits.length * Integer.SIZE;
|
||||||
|
while (index < overflow) {
|
||||||
|
int next = Integer.numberOfTrailingZeros(bits[index / Integer.SIZE] >>> (index % Integer.SIZE));
|
||||||
|
if (next < Integer.SIZE) {
|
||||||
|
index += next;
|
||||||
|
return index;
|
||||||
|
} else {
|
||||||
|
index = (index / Integer.SIZE + 1) * Integer.SIZE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasNext() {
|
public boolean hasNext() {
|
||||||
return count > 0;
|
return index < bits.length * Integer.SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public E next() {
|
public E next() {
|
||||||
if (count == 0) {
|
if (!hasNext()) {
|
||||||
throw new NoSuchElementException();
|
throw new TNoSuchElementException();
|
||||||
}
|
}
|
||||||
indexToRemove = index;
|
indexToRemove = index;
|
||||||
while (true) {
|
|
||||||
int next = Integer.numberOfTrailingZeros(bits[index / 32] >>> (index % 32));
|
|
||||||
if (next < 32) {
|
|
||||||
index += next;
|
|
||||||
--count;
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
E returnValue = (E) getConstants(cls)[index++];
|
E returnValue = (E) getConstants(cls)[index++];
|
||||||
|
index = find();
|
||||||
return returnValue;
|
return returnValue;
|
||||||
} else {
|
|
||||||
index = (index / 32 + 1) * 32;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -82,8 +90,8 @@ class TGenericEnumSet<E extends Enum<E>> extends TEnumSet<E> {
|
||||||
if (indexToRemove < 0) {
|
if (indexToRemove < 0) {
|
||||||
throw new IllegalStateException();
|
throw new IllegalStateException();
|
||||||
}
|
}
|
||||||
int bitNumber = indexToRemove / 32;
|
int bitNumber = indexToRemove / Integer.SIZE;
|
||||||
bits[bitNumber] &= ~(1 << (indexToRemove % 32));
|
bits[bitNumber] &= ~(1 << (indexToRemove % Integer.SIZE));
|
||||||
indexToRemove = -1;
|
indexToRemove = -1;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -104,15 +112,13 @@ class TGenericEnumSet<E extends Enum<E>> extends TEnumSet<E> {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!(o instanceof TGenericEnumSet)) {
|
if (!(o instanceof TGenericEnumSet)) {
|
||||||
return false;
|
return super.equals(o);
|
||||||
}
|
}
|
||||||
TGenericEnumSet<?> other = (TGenericEnumSet<?>) o;
|
TGenericEnumSet<?> other = (TGenericEnumSet<?>) o;
|
||||||
return cls == other.cls && Arrays.equals(bits, other.bits);
|
if (this.cls != other.cls) {
|
||||||
|
return this.size() == 0 && other.size() == 0;
|
||||||
}
|
}
|
||||||
|
return Arrays.equals(bits, other.bits);
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Arrays.hashCode(bits);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -140,19 +146,23 @@ class TGenericEnumSet<E extends Enum<E>> extends TEnumSet<E> {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int n = ((Enum<?>) o).ordinal();
|
int n = ((Enum<?>) o).ordinal();
|
||||||
int bitNumber = n / 32;
|
int bitNumber = n / Integer.SIZE;
|
||||||
int bit = 1 << (n % 32);
|
int bit = 1 << (n % Integer.SIZE);
|
||||||
return (bits[bitNumber] & bit) != 0;
|
return (bits[bitNumber] & bit) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void fastAdd(int n) {
|
void fastAdd(int n) {
|
||||||
int bitNumber = n / 32;
|
int bitNumber = n / Integer.SIZE;
|
||||||
bits[bitNumber] |= 1 << (n % 32);
|
bits[bitNumber] |= 1 << (n % Integer.SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean add(E t) {
|
public boolean add(E t) {
|
||||||
|
Class<?> tCls = t.getClass();
|
||||||
|
if (tCls != cls && tCls.getSuperclass() != cls) {
|
||||||
|
throw new ClassCastException();
|
||||||
|
}
|
||||||
int n = t.ordinal();
|
int n = t.ordinal();
|
||||||
int bitNumber = n / 32;
|
int bitNumber = n / 32;
|
||||||
int bit = 1 << (n % 32);
|
int bit = 1 << (n % 32);
|
||||||
|
@ -171,8 +181,8 @@ class TGenericEnumSet<E extends Enum<E>> extends TEnumSet<E> {
|
||||||
}
|
}
|
||||||
|
|
||||||
int n = ((Enum<?>) o).ordinal();
|
int n = ((Enum<?>) o).ordinal();
|
||||||
int bitNumber = n / 32;
|
int bitNumber = n / Integer.SIZE;
|
||||||
int bit = 1 << (n % 32);
|
int bit = 1 << (n % Integer.SIZE);
|
||||||
if ((bits[bitNumber] & bit) != 0) {
|
if ((bits[bitNumber] & bit) != 0) {
|
||||||
bits[bitNumber] &= ~bit;
|
bits[bitNumber] &= ~bit;
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -17,16 +17,23 @@ package org.teavm.classlib.java.util;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotEquals;
|
||||||
|
import static org.junit.Assert.assertNotSame;
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertSame;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.EnumMap;
|
import java.util.EnumMap;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.teavm.junit.TeaVMTestRunner;
|
import org.teavm.junit.TeaVMTestRunner;
|
||||||
|
@ -228,7 +235,486 @@ public class EnumMapTest {
|
||||||
assertEquals(1, map.size());
|
assertEquals(1, map.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void constructorMap() {
|
||||||
|
EnumMap enumMap;
|
||||||
|
Map enumColorMap = null;
|
||||||
|
try {
|
||||||
|
enumMap = new EnumMap(enumColorMap);
|
||||||
|
fail("Expected NullPointerException");
|
||||||
|
} catch (NullPointerException e) {
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
enumColorMap = new EnumMap<Color, Double>(Color.class);
|
||||||
|
enumMap = new EnumMap(enumColorMap);
|
||||||
|
enumColorMap.put(Color.Blue, 3);
|
||||||
|
enumMap = new EnumMap(enumColorMap);
|
||||||
|
|
||||||
|
HashMap hashColorMap = null;
|
||||||
|
try {
|
||||||
|
enumMap = new EnumMap(hashColorMap);
|
||||||
|
fail("Expected NullPointerException");
|
||||||
|
} catch (NullPointerException e) {
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
|
||||||
|
hashColorMap = new HashMap();
|
||||||
|
try {
|
||||||
|
enumMap = new EnumMap(hashColorMap);
|
||||||
|
fail("Expected IllegalArgumentException");
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
|
||||||
|
hashColorMap.put(Color.Green, 2);
|
||||||
|
enumMap = new EnumMap(hashColorMap);
|
||||||
|
assertEquals("Constructor fails", 2, enumMap.get(Color.Green));
|
||||||
|
assertNull("Constructor fails", enumMap.get(Color.Red));
|
||||||
|
enumMap.put(Color.Red, 1);
|
||||||
|
assertEquals("Wrong value", 1, enumMap.get(Color.Red));
|
||||||
|
hashColorMap.put(Size.Big, 3);
|
||||||
|
try {
|
||||||
|
enumMap = new EnumMap(hashColorMap);
|
||||||
|
fail("Expected ClassCastException");
|
||||||
|
} catch (ClassCastException e) {
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
|
||||||
|
hashColorMap = new HashMap();
|
||||||
|
hashColorMap.put(1, 1);
|
||||||
|
try {
|
||||||
|
enumMap = new EnumMap(hashColorMap);
|
||||||
|
fail("Expected ClassCastException");
|
||||||
|
} catch (ClassCastException e) {
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||||
|
public void putAll() {
|
||||||
|
EnumMap enumColorMap = new EnumMap(Color.class);
|
||||||
|
enumColorMap.put(Color.Green, 2);
|
||||||
|
EnumMap enumSizeMap = new EnumMap(Size.class);
|
||||||
|
enumColorMap.putAll(enumSizeMap);
|
||||||
|
enumSizeMap.put(Size.Big, 1);
|
||||||
|
try {
|
||||||
|
enumColorMap.putAll(enumSizeMap);
|
||||||
|
fail("Expected ClassCastException");
|
||||||
|
} catch (ClassCastException e) {
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
EnumMap enumColorMap1 = new EnumMap<Color, Double>(Color.class);
|
||||||
|
enumColorMap1.put(Color.Blue, 3);
|
||||||
|
enumColorMap.putAll(enumColorMap1);
|
||||||
|
assertEquals("Get returned incorrect value for given key", 3, enumColorMap.get(Color.Blue));
|
||||||
|
assertEquals("Wrong Size", 2, enumColorMap.size());
|
||||||
|
enumColorMap = new EnumMap<Color, Double>(Color.class);
|
||||||
|
HashMap hashColorMap = null;
|
||||||
|
try {
|
||||||
|
enumColorMap.putAll(hashColorMap);
|
||||||
|
fail("Expected NullPointerException");
|
||||||
|
} catch (NullPointerException e) {
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
hashColorMap = new HashMap();
|
||||||
|
enumColorMap.putAll(hashColorMap);
|
||||||
|
hashColorMap.put(Color.Green, 2);
|
||||||
|
enumColorMap.putAll(hashColorMap);
|
||||||
|
assertEquals("Get returned incorrect value for given key", 2, enumColorMap.get(Color.Green));
|
||||||
|
assertNull("Get returned non-null for non mapped key", enumColorMap.get(Color.Red));
|
||||||
|
hashColorMap.put(Color.Red, 1);
|
||||||
|
enumColorMap.putAll(hashColorMap);
|
||||||
|
assertEquals("Get returned incorrect value for given key", 2, enumColorMap.get(Color.Green));
|
||||||
|
hashColorMap.put(Size.Big, 3);
|
||||||
|
try {
|
||||||
|
enumColorMap.putAll(hashColorMap);
|
||||||
|
fail("Expected ClassCastException");
|
||||||
|
} catch (ClassCastException e) {
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
hashColorMap = new HashMap();
|
||||||
|
hashColorMap.put(1, 1);
|
||||||
|
try {
|
||||||
|
enumColorMap.putAll(hashColorMap);
|
||||||
|
fail("Expected ClassCastException");
|
||||||
|
} catch (ClassCastException e) {
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void cloneWorks() {
|
||||||
|
EnumMap<Size, Integer> enumSizeMap = new EnumMap<>(Size.class);
|
||||||
|
Integer integer = Integer.valueOf("3");
|
||||||
|
enumSizeMap.put(Size.Small, integer);
|
||||||
|
EnumMap<Size, Integer> enumSizeMapClone = enumSizeMap.clone();
|
||||||
|
assertNotSame("Should not be same", enumSizeMap, enumSizeMapClone);
|
||||||
|
assertEquals("Clone answered unequal EnumMap", enumSizeMap, enumSizeMapClone);
|
||||||
|
assertSame("Should be same", enumSizeMap.get(Size.Small), enumSizeMapClone.get(Size.Small));
|
||||||
|
assertSame("Clone is not shallow clone", integer, enumSizeMapClone.get(Size.Small));
|
||||||
|
enumSizeMap.remove(Size.Small);
|
||||||
|
assertSame("Clone is not shallow clone", integer, enumSizeMapClone.get(Size.Small));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||||
|
public void entrySet() {
|
||||||
|
EnumMap<Size, Integer> enumSizeMap = new EnumMap<>(Size.class);
|
||||||
|
enumSizeMap.put(Size.Middle, 1);
|
||||||
|
enumSizeMap.put(Size.Big, null);
|
||||||
|
MockEntry<Size, Integer> mockEntry = new MockEntry<>(Size.Middle, 1);
|
||||||
|
Set<Map.Entry<Size, Integer>> set = enumSizeMap.entrySet();
|
||||||
|
Set<Map.Entry<Size, Integer>> set1 = enumSizeMap.entrySet();
|
||||||
|
assertSame("Should be same", set1, set);
|
||||||
|
try {
|
||||||
|
set.add(mockEntry);
|
||||||
|
fail("Should throw UnsupportedOperationException");
|
||||||
|
} catch (UnsupportedOperationException e) {
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
assertTrue("Returned false for contained object", set.contains(mockEntry));
|
||||||
|
mockEntry = new MockEntry<>(Size.Middle, null);
|
||||||
|
assertFalse("Returned true for uncontained object", set.contains(mockEntry));
|
||||||
|
assertFalse("Returned true for uncontained object", set.contains(Size.Small));
|
||||||
|
assertFalse("Returned true for uncontained object", set.contains(new MockEntry(1, 1)));
|
||||||
|
assertFalse("Returned true for uncontained object", set.contains(1));
|
||||||
|
mockEntry = new MockEntry<>(Size.Big, null);
|
||||||
|
assertTrue("Returned false for contained object", set.contains(mockEntry));
|
||||||
|
assertTrue("Returned false when the object can be removed", set.remove(mockEntry));
|
||||||
|
assertFalse("Returned true for uncontained object", set.contains(mockEntry));
|
||||||
|
assertFalse("Returned true when the object can not be removed", set.remove(mockEntry));
|
||||||
|
assertFalse("Returned true when the object can not be removed", set.remove(new MockEntry(1, 1)));
|
||||||
|
assertFalse("Returned true when the object can not be removed", set.remove(1));
|
||||||
|
// The set is backed by the map so changes to one are reflected by the
|
||||||
|
// other.
|
||||||
|
enumSizeMap.put(Size.Big, 3);
|
||||||
|
mockEntry = new MockEntry<>(Size.Big, 3);
|
||||||
|
assertTrue("Returned false for contained object", set.contains(mockEntry));
|
||||||
|
enumSizeMap.remove(Size.Big);
|
||||||
|
assertFalse("Returned true for uncontained object", set.contains(mockEntry));
|
||||||
|
assertEquals("Wrong size", 1, set.size());
|
||||||
|
set.clear();
|
||||||
|
assertEquals("Wrong size", 0, set.size());
|
||||||
|
enumSizeMap = new EnumMap<>(Size.class);
|
||||||
|
enumSizeMap.put(Size.Middle, 1);
|
||||||
|
enumSizeMap.put(Size.Big, null);
|
||||||
|
set = enumSizeMap.entrySet();
|
||||||
|
Collection<Map.Entry<Size, Integer>> c = new ArrayList<>();
|
||||||
|
c.add(new MockEntry<>(Size.Middle, 1));
|
||||||
|
assertTrue("Return wrong value", set.containsAll(c));
|
||||||
|
assertTrue("Remove does not success", set.removeAll(c));
|
||||||
|
enumSizeMap.put(Size.Middle, 1);
|
||||||
|
c.add(new MockEntry(Size.Big, 3));
|
||||||
|
assertTrue("Remove does not success", set.removeAll(c));
|
||||||
|
assertFalse("Should return false", set.removeAll(c));
|
||||||
|
assertEquals("Wrong size", 1, set.size());
|
||||||
|
enumSizeMap = new EnumMap<>(Size.class);
|
||||||
|
enumSizeMap.put(Size.Middle, 1);
|
||||||
|
enumSizeMap.put(Size.Big, null);
|
||||||
|
set = enumSizeMap.entrySet();
|
||||||
|
c = new ArrayList<>();
|
||||||
|
c.add(new MockEntry(Size.Middle, 1));
|
||||||
|
c.add(new MockEntry(Size.Big, 3));
|
||||||
|
assertTrue("Retain does not success", set.retainAll(c));
|
||||||
|
assertEquals("Wrong size", 1, set.size());
|
||||||
|
assertFalse("Should return false", set.retainAll(c));
|
||||||
|
enumSizeMap = new EnumMap<>(Size.class);
|
||||||
|
enumSizeMap.put(Size.Middle, 1);
|
||||||
|
enumSizeMap.put(Size.Big, null);
|
||||||
|
set = enumSizeMap.entrySet();
|
||||||
|
Object[] array = set.toArray();
|
||||||
|
assertEquals("Wrong length", 2, array.length);
|
||||||
|
Map.Entry entry = (Map.Entry) array[0];
|
||||||
|
assertEquals("Wrong key", Size.Middle, entry.getKey());
|
||||||
|
assertEquals("Wrong value", 1, entry.getValue());
|
||||||
|
Object[] array1 = new Object[10];
|
||||||
|
array1 = set.toArray();
|
||||||
|
assertEquals("Wrong length", 2, array1.length);
|
||||||
|
entry = (Map.Entry) array[0];
|
||||||
|
assertEquals("Wrong key", Size.Middle, entry.getKey());
|
||||||
|
assertEquals("Wrong value", 1, entry.getValue());
|
||||||
|
array1 = new Object[10];
|
||||||
|
array1 = set.toArray(array1);
|
||||||
|
assertEquals("Wrong length", 10, array1.length);
|
||||||
|
entry = (Map.Entry) array[1];
|
||||||
|
assertEquals("Wrong key", Size.Big, entry.getKey());
|
||||||
|
assertNull("Should be null", array1[2]);
|
||||||
|
set = enumSizeMap.entrySet();
|
||||||
|
Integer integer = Integer.valueOf("1");
|
||||||
|
assertFalse("Returned true when the object can not be removed", set.remove(integer));
|
||||||
|
assertTrue("Returned false when the object can be removed", set.remove(entry));
|
||||||
|
enumSizeMap = new EnumMap<>(EnumMapTest.Size.class);
|
||||||
|
enumSizeMap.put(Size.Middle, 1);
|
||||||
|
enumSizeMap.put(Size.Big, null);
|
||||||
|
set = enumSizeMap.entrySet();
|
||||||
|
Iterator<Map.Entry<Size, Integer>> iter = set.iterator();
|
||||||
|
entry = iter.next();
|
||||||
|
assertTrue("Returned false for contained object", set.contains(entry));
|
||||||
|
mockEntry = new MockEntry<>(Size.Middle, 2);
|
||||||
|
assertFalse("Returned true for uncontained object", set.contains(mockEntry));
|
||||||
|
assertFalse("Returned true for uncontained object", set
|
||||||
|
.contains(new MockEntry(2, 2)));
|
||||||
|
entry = iter.next();
|
||||||
|
assertTrue("Returned false for contained object", set.contains(entry));
|
||||||
|
enumSizeMap.put(Size.Middle, 1);
|
||||||
|
enumSizeMap.remove(Size.Big);
|
||||||
|
mockEntry = new MockEntry<>(Size.Big, null);
|
||||||
|
assertEquals("Wrong size", 1, set.size());
|
||||||
|
assertFalse("Returned true for uncontained object", set.contains(mockEntry));
|
||||||
|
enumSizeMap.put(Size.Big, 2);
|
||||||
|
mockEntry = new MockEntry<>(Size.Big, 2);
|
||||||
|
assertTrue("Returned false for contained object", set
|
||||||
|
.contains(mockEntry));
|
||||||
|
iter.remove();
|
||||||
|
try {
|
||||||
|
iter.remove();
|
||||||
|
fail("Should throw IllegalStateException");
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
entry.setValue(2);
|
||||||
|
fail("Should throw IllegalStateException");
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
set.contains(entry);
|
||||||
|
fail("Should throw IllegalStateException");
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
enumSizeMap = new EnumMap(Size.class);
|
||||||
|
enumSizeMap.put(Size.Middle, 1);
|
||||||
|
enumSizeMap.put(Size.Big, null);
|
||||||
|
set = enumSizeMap.entrySet();
|
||||||
|
iter = set.iterator();
|
||||||
|
entry = iter.next();
|
||||||
|
assertEquals("Wrong key", Size.Middle, entry.getKey());
|
||||||
|
assertTrue("Returned false for contained object", set.contains(entry));
|
||||||
|
enumSizeMap.put(Size.Middle, 3);
|
||||||
|
assertTrue("Returned false for contained object", set.contains(entry));
|
||||||
|
entry.setValue(2);
|
||||||
|
assertTrue("Returned false for contained object", set.contains(entry));
|
||||||
|
assertFalse("Returned true for uncontained object", set.remove(1));
|
||||||
|
iter.next();
|
||||||
|
assertEquals("Wrong key", Size.Middle, entry.getKey());
|
||||||
|
set.clear();
|
||||||
|
assertEquals("Wrong size", 0, set.size());
|
||||||
|
enumSizeMap = new EnumMap<>(Size.class);
|
||||||
|
enumSizeMap.put(Size.Middle, 1);
|
||||||
|
enumSizeMap.put(Size.Big, null);
|
||||||
|
set = enumSizeMap.entrySet();
|
||||||
|
iter = set.iterator();
|
||||||
|
mockEntry = new MockEntry<>(Size.Middle, 1);
|
||||||
|
assertNotEquals("Wrong result", entry, mockEntry);
|
||||||
|
try {
|
||||||
|
iter.remove();
|
||||||
|
fail("Should throw IllegalStateException");
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
entry = iter.next();
|
||||||
|
assertEquals("Wrong key", Size.Middle, entry.getKey());
|
||||||
|
assertEquals("Should return true", entry, mockEntry);
|
||||||
|
assertEquals("Should be equal", mockEntry.hashCode(), entry.hashCode());
|
||||||
|
mockEntry = new MockEntry<>(Size.Big, 1);
|
||||||
|
assertNotEquals("Wrong result", entry, mockEntry);
|
||||||
|
entry = iter.next();
|
||||||
|
assertNotEquals("Wrong result", entry, mockEntry);
|
||||||
|
assertEquals("Wrong key", Size.Big, entry.getKey());
|
||||||
|
iter.remove();
|
||||||
|
assertNotEquals("Wrong result", entry, mockEntry);
|
||||||
|
assertEquals("Wrong size", 1, set.size());
|
||||||
|
try {
|
||||||
|
iter.remove();
|
||||||
|
fail("Should throw IllegalStateException");
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
iter.next();
|
||||||
|
fail("Should throw NoSuchElementException");
|
||||||
|
} catch (NoSuchElementException e) {
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@SuppressWarnings({ "unchecked", "boxing" })
|
||||||
|
public void values() {
|
||||||
|
EnumMap<Color, Integer> enumColorMap = new EnumMap<>(Color.class);
|
||||||
|
enumColorMap.put(Color.Red, 1);
|
||||||
|
enumColorMap.put(Color.Blue, null);
|
||||||
|
Collection<Integer> collection = enumColorMap.values();
|
||||||
|
Collection<Integer> collection1 = enumColorMap.values();
|
||||||
|
assertSame("Should be same", collection1, collection);
|
||||||
|
try {
|
||||||
|
collection.add(1);
|
||||||
|
fail("Should throw UnsupportedOperationException");
|
||||||
|
} catch (UnsupportedOperationException e) {
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
assertTrue("Returned false for contained object", collection.contains(1));
|
||||||
|
assertTrue("Returned false for contained object", collection.contains(null));
|
||||||
|
assertFalse("Returned true for uncontained object", collection.contains(2));
|
||||||
|
assertTrue("Returned false when the object can be removed", collection.remove(null));
|
||||||
|
assertFalse("Returned true for uncontained object", collection.contains(null));
|
||||||
|
assertFalse("Returned true when the object can not be removed", collection.remove(null));
|
||||||
|
// The set is backed by the map so changes to one are reflected by the other.
|
||||||
|
enumColorMap.put(Color.Blue, 3);
|
||||||
|
assertTrue("Returned false for contained object", collection.contains(3));
|
||||||
|
enumColorMap.remove(Color.Blue);
|
||||||
|
assertFalse("Returned true for uncontained object", collection.contains(3));
|
||||||
|
assertEquals("Wrong size", 1, collection.size());
|
||||||
|
collection.clear();
|
||||||
|
assertEquals("Wrong size", 0, collection.size());
|
||||||
|
enumColorMap = new EnumMap<>(Color.class);
|
||||||
|
enumColorMap.put(Color.Red, 1);
|
||||||
|
enumColorMap.put(Color.Blue, null);
|
||||||
|
collection = enumColorMap.values();
|
||||||
|
Collection c = new ArrayList<>();
|
||||||
|
c.add(1);
|
||||||
|
assertTrue("Should return true", collection.containsAll(c));
|
||||||
|
c.add(3.4);
|
||||||
|
assertFalse("Should return false", collection.containsAll(c));
|
||||||
|
assertTrue("Should return true", collection.removeAll(c));
|
||||||
|
assertEquals("Wrong size", 1, collection.size());
|
||||||
|
assertFalse("Should return false", collection.removeAll(c));
|
||||||
|
assertEquals("Wrong size", 1, collection.size());
|
||||||
|
try {
|
||||||
|
collection.addAll(c);
|
||||||
|
fail("Should throw UnsupportedOperationException");
|
||||||
|
} catch (UnsupportedOperationException e) {
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
enumColorMap.put(Color.Red, 1);
|
||||||
|
assertEquals("Wrong size", 2, collection.size());
|
||||||
|
assertTrue("Should return true", collection.retainAll(c));
|
||||||
|
assertEquals("Wrong size", 1, collection.size());
|
||||||
|
assertFalse("Should return false", collection.retainAll(c));
|
||||||
|
assertEquals(1, collection.size());
|
||||||
|
Object[] array = collection.toArray();
|
||||||
|
assertEquals("Wrong length", 1, array.length);
|
||||||
|
assertEquals("Wrong key", 1, array[0]);
|
||||||
|
enumColorMap = new EnumMap<>(Color.class);
|
||||||
|
enumColorMap.put(Color.Red, 1);
|
||||||
|
enumColorMap.put(Color.Blue, null);
|
||||||
|
collection = enumColorMap.values();
|
||||||
|
assertEquals("Wrong size", 2, collection.size());
|
||||||
|
assertFalse("Returned true when the object can not be removed",
|
||||||
|
collection.remove(Integer.valueOf("10")));
|
||||||
|
Iterator<Integer> iter = enumColorMap.values().iterator();
|
||||||
|
Object value = iter.next();
|
||||||
|
assertTrue("Returned false for contained object", collection.contains(value));
|
||||||
|
value = iter.next();
|
||||||
|
assertTrue("Returned false for contained object", collection.contains(value));
|
||||||
|
enumColorMap.put(Color.Green, 1);
|
||||||
|
enumColorMap.remove(Color.Blue);
|
||||||
|
assertFalse("Returned true for uncontained object", collection.contains(value));
|
||||||
|
iter.remove();
|
||||||
|
assertEquals("{Red=1, Green=1}", enumColorMap.toString());
|
||||||
|
try {
|
||||||
|
iter.remove();
|
||||||
|
fail("Should throw IllegalStateException");
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
assertFalse("Returned true for uncontained object", collection.contains(value));
|
||||||
|
iter = enumColorMap.values().iterator();
|
||||||
|
value = iter.next();
|
||||||
|
assertTrue("Returned false for contained object", collection.contains(value));
|
||||||
|
enumColorMap.put(Color.Green, 3);
|
||||||
|
assertTrue("Returned false for contained object", collection.contains(value));
|
||||||
|
assertTrue("Returned false for contained object", collection.remove(Integer.valueOf("1")));
|
||||||
|
assertEquals("Wrong size", 1, collection.size());
|
||||||
|
collection.clear();
|
||||||
|
assertEquals("Wrong size", 0, collection.size());
|
||||||
|
enumColorMap = new EnumMap<>(Color.class);
|
||||||
|
Integer integer1 = 1;
|
||||||
|
enumColorMap.put(Color.Green, integer1);
|
||||||
|
enumColorMap.put(Color.Blue, null);
|
||||||
|
collection = enumColorMap.values();
|
||||||
|
iter = enumColorMap.values().iterator();
|
||||||
|
try {
|
||||||
|
iter.remove();
|
||||||
|
fail("Should throw IllegalStateException");
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
value = iter.next();
|
||||||
|
assertEquals("Wrong value", integer1, value);
|
||||||
|
assertSame("Wrong value", integer1, value);
|
||||||
|
assertNotEquals("Returned true for unequal object", iter, value);
|
||||||
|
iter.remove();
|
||||||
|
assertNotEquals("Returned true for unequal object", iter, value);
|
||||||
|
try {
|
||||||
|
iter.remove();
|
||||||
|
fail("Should throw IllegalStateException");
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
assertEquals("Wrong size", 1, collection.size());
|
||||||
|
value = iter.next();
|
||||||
|
assertNotEquals("Returned true for unequal object", iter, value);
|
||||||
|
iter.remove();
|
||||||
|
try {
|
||||||
|
iter.next();
|
||||||
|
fail("Should throw NoSuchElementException");
|
||||||
|
} catch (NoSuchElementException e) {
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Size {
|
||||||
|
Small, Middle, Big {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
enum Color {
|
||||||
|
Red, Green, Blue {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
enum Empty {
|
||||||
|
//Empty
|
||||||
|
}
|
||||||
|
|
||||||
enum L {
|
enum L {
|
||||||
A, B, C
|
A, B, C
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class MockEntry<K, V> implements Map.Entry<K, V> {
|
||||||
|
private K key;
|
||||||
|
private V value;
|
||||||
|
public MockEntry(K key, V value) {
|
||||||
|
this.key = key;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return (key == null ? 0 : key.hashCode())
|
||||||
|
^ (value == null ? 0 : value.hashCode());
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
return o instanceof Map.Entry<?, ?> e
|
||||||
|
&& Objects.equals(key, e.getKey())
|
||||||
|
&& Objects.equals(value, e.getValue());
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public K getKey() {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public V getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public V setValue(V object) {
|
||||||
|
V oldValue = value;
|
||||||
|
value = object;
|
||||||
|
return oldValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,9 @@ import static org.junit.Assert.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
import org.teavm.junit.SkipPlatform;
|
||||||
import org.teavm.junit.TeaVMTestRunner;
|
import org.teavm.junit.TeaVMTestRunner;
|
||||||
|
import org.teavm.junit.TestPlatform;
|
||||||
|
|
||||||
@RunWith(TeaVMTestRunner.class)
|
@RunWith(TeaVMTestRunner.class)
|
||||||
public class EnumSetTest {
|
public class EnumSetTest {
|
||||||
|
@ -196,6 +198,215 @@ public class EnumSetTest {
|
||||||
assertEquals(original, set);
|
assertEquals(original, set);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@SkipPlatform({ TestPlatform.WEBASSEMBLY, TestPlatform.WASI })
|
||||||
|
public void iterator() {
|
||||||
|
Set<EnumFoo> set = EnumSet.noneOf(EnumFoo.class);
|
||||||
|
set.add(EnumFoo.a);
|
||||||
|
set.add(EnumFoo.b);
|
||||||
|
Iterator<EnumFoo> iterator = set.iterator();
|
||||||
|
Iterator<EnumFoo> anotherIterator = set.iterator();
|
||||||
|
assertNotSame("Should not be same", iterator, anotherIterator);
|
||||||
|
try {
|
||||||
|
iterator.remove();
|
||||||
|
fail("Should throw IllegalStateException");
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
// expectedd
|
||||||
|
}
|
||||||
|
assertTrue("Should has next element:", iterator.hasNext());
|
||||||
|
assertSame("Should be identical", EnumFoo.a, iterator.next());
|
||||||
|
iterator.remove();
|
||||||
|
assertTrue("Should has next element:", iterator.hasNext());
|
||||||
|
assertSame("Should be identical", EnumFoo.b, iterator.next());
|
||||||
|
assertFalse("Should not has next element:", iterator.hasNext());
|
||||||
|
assertFalse("Should not has next element:", iterator.hasNext());
|
||||||
|
assertEquals("Size should be 1:", 1, set.size());
|
||||||
|
try {
|
||||||
|
iterator.next();
|
||||||
|
fail("Should throw NoSuchElementException");
|
||||||
|
} catch (NoSuchElementException e) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
set = EnumSet.noneOf(EnumFoo.class);
|
||||||
|
set.add(EnumFoo.a);
|
||||||
|
iterator = set.iterator();
|
||||||
|
assertEquals("Should be equal", EnumFoo.a, iterator.next());
|
||||||
|
iterator.remove();
|
||||||
|
try {
|
||||||
|
iterator.remove();
|
||||||
|
fail("Should throw IllegalStateException");
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
Set<EmptyEnum> emptySet = EnumSet.allOf(EmptyEnum.class);
|
||||||
|
Iterator<EmptyEnum> emptyIterator = emptySet.iterator();
|
||||||
|
try {
|
||||||
|
emptyIterator.next();
|
||||||
|
fail("Should throw NoSuchElementException");
|
||||||
|
} catch (NoSuchElementException e) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
Set<EnumWithInnerClass> setWithSubclass = EnumSet
|
||||||
|
.allOf(EnumWithInnerClass.class);
|
||||||
|
setWithSubclass.remove(EnumWithInnerClass.e);
|
||||||
|
Iterator<EnumWithInnerClass> iteratorWithSubclass = setWithSubclass
|
||||||
|
.iterator();
|
||||||
|
assertSame("Should be same", EnumWithInnerClass.a, iteratorWithSubclass.next());
|
||||||
|
assertTrue("Should return true", iteratorWithSubclass.hasNext());
|
||||||
|
assertSame("Should be same", EnumWithInnerClass.b, iteratorWithSubclass.next());
|
||||||
|
setWithSubclass.remove(EnumWithInnerClass.c);
|
||||||
|
assertTrue("Should return true", iteratorWithSubclass.hasNext());
|
||||||
|
assertSame("Should be same", EnumWithInnerClass.c, iteratorWithSubclass.next());
|
||||||
|
assertTrue("Should return true", iteratorWithSubclass.hasNext());
|
||||||
|
assertSame("Should be same", EnumWithInnerClass.d, iteratorWithSubclass.next());
|
||||||
|
setWithSubclass.add(EnumWithInnerClass.e);
|
||||||
|
assertTrue("Should return true", iteratorWithSubclass.hasNext());
|
||||||
|
assertSame("Should be same", EnumWithInnerClass.f, iteratorWithSubclass.next());
|
||||||
|
set = EnumSet.noneOf(EnumFoo.class);
|
||||||
|
iterator = set.iterator();
|
||||||
|
try {
|
||||||
|
iterator.next();
|
||||||
|
fail("Should throw NoSuchElementException");
|
||||||
|
} catch (NoSuchElementException e) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
set.add(EnumFoo.a);
|
||||||
|
iterator = set.iterator();
|
||||||
|
assertEquals("Should return EnumFoo.a", EnumFoo.a, iterator.next());
|
||||||
|
assertEquals("Size of set should be 1", 1, set.size());
|
||||||
|
iterator.remove();
|
||||||
|
assertEquals("Size of set should be 0", 0, set.size());
|
||||||
|
assertFalse("Should return false", set.contains(EnumFoo.a));
|
||||||
|
set.add(EnumFoo.a);
|
||||||
|
set.add(EnumFoo.b);
|
||||||
|
iterator = set.iterator();
|
||||||
|
assertEquals("Should be equals", EnumFoo.a, iterator.next());
|
||||||
|
iterator.remove();
|
||||||
|
try {
|
||||||
|
iterator.remove();
|
||||||
|
fail("Should throw IllegalStateException");
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
assertTrue("Should have next element", iterator.hasNext());
|
||||||
|
try {
|
||||||
|
iterator.remove();
|
||||||
|
fail("Should throw IllegalStateException");
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
assertEquals("Size of set should be 1", 1, set.size());
|
||||||
|
assertTrue("Should have next element", iterator.hasNext());
|
||||||
|
assertEquals("Should return EnumFoo.b", EnumFoo.b, iterator.next());
|
||||||
|
set.remove(EnumFoo.b);
|
||||||
|
assertEquals("Size of set should be 0", 0, set.size());
|
||||||
|
iterator.remove();
|
||||||
|
assertFalse("Should return false", set.contains(EnumFoo.a));
|
||||||
|
assertFalse("Should return false", set.contains(EnumFoo.b));
|
||||||
|
// test enum type with more than 64 elements
|
||||||
|
Set<HugeEnum> hugeSet = EnumSet.noneOf(HugeEnum.class);
|
||||||
|
hugeSet.add(HugeEnum.a);
|
||||||
|
hugeSet.add(HugeEnum.b);
|
||||||
|
Iterator<HugeEnum> hIterator = hugeSet.iterator();
|
||||||
|
Iterator<HugeEnum> anotherHugeIterator = hugeSet.iterator();
|
||||||
|
assertNotSame(hIterator, anotherHugeIterator);
|
||||||
|
try {
|
||||||
|
hIterator.remove();
|
||||||
|
fail("Should throw IllegalStateException");
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
assertTrue(hIterator.hasNext());
|
||||||
|
assertSame(HugeEnum.a, hIterator.next());
|
||||||
|
hIterator.remove();
|
||||||
|
assertTrue(hIterator.hasNext());
|
||||||
|
assertSame(HugeEnum.b, hIterator.next());
|
||||||
|
assertFalse(hIterator.hasNext());
|
||||||
|
assertFalse(hIterator.hasNext());
|
||||||
|
assertEquals(1, hugeSet.size());
|
||||||
|
try {
|
||||||
|
hIterator.next();
|
||||||
|
fail("Should throw NoSuchElementException");
|
||||||
|
} catch (NoSuchElementException e) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
Set<HugeEnumWithInnerClass> hugeSetWithSubclass = EnumSet
|
||||||
|
.allOf(HugeEnumWithInnerClass.class);
|
||||||
|
hugeSetWithSubclass.remove(HugeEnumWithInnerClass.e);
|
||||||
|
Iterator<HugeEnumWithInnerClass> hugeIteratorWithSubclass = hugeSetWithSubclass.iterator();
|
||||||
|
assertSame(HugeEnumWithInnerClass.a, hugeIteratorWithSubclass.next());
|
||||||
|
assertTrue(hugeIteratorWithSubclass.hasNext());
|
||||||
|
assertSame(HugeEnumWithInnerClass.b, hugeIteratorWithSubclass.next());
|
||||||
|
setWithSubclass.remove(HugeEnumWithInnerClass.c);
|
||||||
|
assertTrue(hugeIteratorWithSubclass.hasNext());
|
||||||
|
assertSame(HugeEnumWithInnerClass.c, hugeIteratorWithSubclass.next());
|
||||||
|
assertTrue(hugeIteratorWithSubclass.hasNext());
|
||||||
|
assertSame(HugeEnumWithInnerClass.d, hugeIteratorWithSubclass.next());
|
||||||
|
hugeSetWithSubclass.add(HugeEnumWithInnerClass.e);
|
||||||
|
assertTrue(hugeIteratorWithSubclass.hasNext());
|
||||||
|
assertSame(HugeEnumWithInnerClass.f, hugeIteratorWithSubclass.next());
|
||||||
|
hugeSet = EnumSet.noneOf(HugeEnum.class);
|
||||||
|
hIterator = hugeSet.iterator();
|
||||||
|
try {
|
||||||
|
hIterator.next();
|
||||||
|
fail("Should throw NoSuchElementException");
|
||||||
|
} catch (NoSuchElementException e) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
hugeSet.add(HugeEnum.a);
|
||||||
|
hIterator = hugeSet.iterator();
|
||||||
|
assertEquals(HugeEnum.a, hIterator.next());
|
||||||
|
assertEquals(1, hugeSet.size());
|
||||||
|
hIterator.remove();
|
||||||
|
assertEquals(0, hugeSet.size());
|
||||||
|
assertFalse(hugeSet.contains(HugeEnum.a));
|
||||||
|
hugeSet.add(HugeEnum.a);
|
||||||
|
hugeSet.add(HugeEnum.b);
|
||||||
|
hIterator = hugeSet.iterator();
|
||||||
|
hIterator.next();
|
||||||
|
hIterator.remove();
|
||||||
|
assertTrue(hIterator.hasNext());
|
||||||
|
try {
|
||||||
|
hIterator.remove();
|
||||||
|
fail("Should throw IllegalStateException");
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
assertEquals(1, hugeSet.size());
|
||||||
|
assertTrue(hIterator.hasNext());
|
||||||
|
assertEquals(HugeEnum.b, hIterator.next());
|
||||||
|
hugeSet.remove(HugeEnum.b);
|
||||||
|
assertEquals(0, hugeSet.size());
|
||||||
|
hIterator.remove();
|
||||||
|
assertFalse(hugeSet.contains(HugeEnum.a));
|
||||||
|
assertFalse("Should return false", set.contains(EnumFoo.b));
|
||||||
|
}
|
||||||
|
|
||||||
|
enum EnumWithInnerClass {
|
||||||
|
a, b, c, d, e, f {
|
||||||
|
},
|
||||||
|
}
|
||||||
|
enum EnumFoo {
|
||||||
|
a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z,
|
||||||
|
A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z,
|
||||||
|
aa, bb, cc, dd, ee, ff, gg, hh, ii, jj, kk, ll,
|
||||||
|
}
|
||||||
|
enum EmptyEnum {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
enum HugeEnumWithInnerClass {
|
||||||
|
a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z,
|
||||||
|
A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z,
|
||||||
|
aa, bb, cc, dd, ee, ff, gg, hh, ii, jj, kk, ll,
|
||||||
|
mm {
|
||||||
|
},
|
||||||
|
}
|
||||||
|
enum HugeEnum {
|
||||||
|
a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z,
|
||||||
|
A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z,
|
||||||
|
aa, bb, cc, dd, ee, ff, gg, hh, ii, jj, kk, ll, mm,
|
||||||
|
}
|
||||||
|
|
||||||
enum L {
|
enum L {
|
||||||
E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13, E14, E15, E16, E17, E18, E19, E20, E21, E22, E23,
|
E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13, E14, E15, E16, E17, E18, E19, E20, E21, E22, E23,
|
||||||
E24, E25, E26, E27, E28, E29, E30, E31, E32, E33, E34, E35, E36
|
E24, E25, E26, E27, E28, E29, E30, E31, E32, E33, E34, E35, E36
|
||||||
|
|
Loading…
Reference in New Issue
Block a user