8247605: Avoid array allocation when concatenating with empty string
Reviewed-by: redestad, plevart
This commit is contained in:
parent
8e687450d6
commit
55e381b32f
@ -1790,6 +1790,42 @@ public class TreeMap<K,V>
|
|||||||
return m.put(key, value);
|
return m.put(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public V putIfAbsent(K key, V value) {
|
||||||
|
if (!inRange(key))
|
||||||
|
throw new IllegalArgumentException("key out of range");
|
||||||
|
return m.putIfAbsent(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
|
||||||
|
if (!inRange(key))
|
||||||
|
throw new IllegalArgumentException("key out of range");
|
||||||
|
return m.merge(key, value, remappingFunction);
|
||||||
|
}
|
||||||
|
|
||||||
|
public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
|
||||||
|
if (!inRange(key)) {
|
||||||
|
// Do not throw if mapping function returns null
|
||||||
|
// to preserve compatibility with default computeIfAbsent implementation
|
||||||
|
if (mappingFunction.apply(key) == null) return null;
|
||||||
|
throw new IllegalArgumentException("key out of range");
|
||||||
|
}
|
||||||
|
return m.computeIfAbsent(key, mappingFunction);
|
||||||
|
}
|
||||||
|
|
||||||
|
public V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
|
||||||
|
if (!inRange(key)) {
|
||||||
|
// Do not throw if remapping function returns null
|
||||||
|
// to preserve compatibility with default computeIfAbsent implementation
|
||||||
|
if (remappingFunction.apply(key, null) == null) return null;
|
||||||
|
throw new IllegalArgumentException("key out of range");
|
||||||
|
}
|
||||||
|
return m.compute(key, remappingFunction);
|
||||||
|
}
|
||||||
|
|
||||||
|
public V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
|
||||||
|
return !inRange(key) ? null : m.computeIfPresent(key, remappingFunction);
|
||||||
|
}
|
||||||
|
|
||||||
public final V get(Object key) {
|
public final V get(Object key) {
|
||||||
return !inRange(key) ? null : m.get(key);
|
return !inRange(key) ? null : m.get(key);
|
||||||
}
|
}
|
||||||
|
@ -523,7 +523,8 @@ public class InPlaceOpsCollisions extends MapWithCollisionsProviders {
|
|||||||
new Object[]{"HashMap", (Supplier<Map<?, ?>>) HashMap::new},
|
new Object[]{"HashMap", (Supplier<Map<?, ?>>) HashMap::new},
|
||||||
new Object[]{"LinkedHashMap", (Supplier<Map<?, ?>>) LinkedHashMap::new},
|
new Object[]{"LinkedHashMap", (Supplier<Map<?, ?>>) LinkedHashMap::new},
|
||||||
new Object[]{"TreeMap", (Supplier<Map<?, ?>>) TreeMap::new},
|
new Object[]{"TreeMap", (Supplier<Map<?, ?>>) TreeMap::new},
|
||||||
new Object[]{"TreeMap(cmp)", (Supplier<Map<?, ?>>) () -> new TreeMap<>(Comparator.reverseOrder())}
|
new Object[]{"TreeMap(cmp)", (Supplier<Map<?, ?>>) () -> new TreeMap<>(Comparator.reverseOrder())},
|
||||||
|
new Object[]{"TreeMap.descendingMap", (Supplier<Map<?, ?>>) () -> new TreeMap<>().descendingMap()}
|
||||||
).iterator();
|
).iterator();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -193,6 +193,8 @@ public class MapWithCollisionsProviders {
|
|||||||
new IdentityHashMap<>(), keys, val));
|
new IdentityHashMap<>(), keys, val));
|
||||||
cases.add(createCase("TreeMap with " + desc,
|
cases.add(createCase("TreeMap with " + desc,
|
||||||
new TreeMap<>(), keys, val));
|
new TreeMap<>(), keys, val));
|
||||||
|
cases.add(createCase("Descending TreeMap with " + desc,
|
||||||
|
new TreeMap<>().descendingMap(), keys, val));
|
||||||
cases.add(createCase("WeakHashMap with " + desc,
|
cases.add(createCase("WeakHashMap with " + desc,
|
||||||
new WeakHashMap<>(), keys, val));
|
new WeakHashMap<>(), keys, val));
|
||||||
cases.add(createCase("ConcurrentHashMap with " + desc,
|
cases.add(createCase("ConcurrentHashMap with " + desc,
|
||||||
|
@ -46,11 +46,11 @@ import java.util.Collections;
|
|||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.NavigableMap;
|
import java.util.NavigableMap;
|
||||||
import java.util.NavigableSet;
|
import java.util.NavigableSet;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
@ -79,26 +79,26 @@ public class LockStep {
|
|||||||
static void realMain(String[] args) {
|
static void realMain(String[] args) {
|
||||||
size = intArg(args, 0, DEFAULT_SIZE);
|
size = intArg(args, 0, DEFAULT_SIZE);
|
||||||
|
|
||||||
lockSteps(new TreeMap(),
|
lockSteps(new TreeMap<>(),
|
||||||
new ConcurrentSkipListMap());
|
new ConcurrentSkipListMap<>());
|
||||||
lockSteps(new TreeMap(),
|
lockSteps(new TreeMap<>(),
|
||||||
Collections.checkedNavigableMap(new TreeMap(), Integer.class, Integer.class));
|
Collections.checkedNavigableMap(new TreeMap<>(), Integer.class, Integer.class));
|
||||||
lockSteps(new TreeMap(),
|
lockSteps(new TreeMap<>(),
|
||||||
Collections.synchronizedNavigableMap(new TreeMap()));
|
Collections.synchronizedNavigableMap(new TreeMap<>()));
|
||||||
lockSteps(new TreeMap(reverseOrder()),
|
lockSteps(new TreeMap<>(reverseOrder()),
|
||||||
new ConcurrentSkipListMap(reverseOrder()));
|
new ConcurrentSkipListMap<>(reverseOrder()));
|
||||||
|
|
||||||
lockSteps(new TreeSet(),
|
lockSteps(new TreeSet<>(),
|
||||||
new ConcurrentSkipListSet());
|
new ConcurrentSkipListSet<>());
|
||||||
lockSteps(new TreeSet(),
|
lockSteps(new TreeSet<>(),
|
||||||
Collections.checkedNavigableSet(new TreeSet(), Integer.class));
|
Collections.checkedNavigableSet(new TreeSet<>(), Integer.class));
|
||||||
lockSteps(new TreeSet(),
|
lockSteps(new TreeSet<>(),
|
||||||
Collections.synchronizedNavigableSet(new TreeSet()));
|
Collections.synchronizedNavigableSet(new TreeSet<>()));
|
||||||
lockSteps(new TreeSet(reverseOrder()),
|
lockSteps(new TreeSet<>(reverseOrder()),
|
||||||
new ConcurrentSkipListSet(reverseOrder()));
|
new ConcurrentSkipListSet<>(reverseOrder()));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lockSteps(NavigableMap m1, NavigableMap m2) {
|
static void lockSteps(NavigableMap<Integer, Integer> m1, NavigableMap<Integer, Integer> m2) {
|
||||||
if (maybe(4)) m1 = serialClone(m1);
|
if (maybe(4)) m1 = serialClone(m1);
|
||||||
if (maybe(4)) m2 = serialClone(m2);
|
if (maybe(4)) m2 = serialClone(m2);
|
||||||
lockStep(m1,
|
lockStep(m1,
|
||||||
@ -119,7 +119,7 @@ public class LockStep {
|
|||||||
fullTailMap(m2.descendingMap()));
|
fullTailMap(m2.descendingMap()));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lockSteps(NavigableSet s1, NavigableSet s2) {
|
static void lockSteps(NavigableSet<Integer> s1, NavigableSet<Integer> s2) {
|
||||||
if (maybe(4)) s1 = serialClone(s1);
|
if (maybe(4)) s1 = serialClone(s1);
|
||||||
if (maybe(4)) s2 = serialClone(s2);
|
if (maybe(4)) s2 = serialClone(s2);
|
||||||
lockStep(s1,
|
lockStep(s1,
|
||||||
@ -140,47 +140,47 @@ public class LockStep {
|
|||||||
fullTailSet(s2.descendingSet()));
|
fullTailSet(s2.descendingSet()));
|
||||||
}
|
}
|
||||||
|
|
||||||
static boolean isAscending(NavigableMap m) {
|
static boolean isAscending(NavigableMap<Integer, Integer> m) {
|
||||||
Comparator cmp = m.comparator();
|
var cmp = m.comparator();
|
||||||
return (cmp == null || cmp.compare(1, 2) < 0);
|
return (cmp == null || cmp.compare(1, 2) < 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static NavigableMap fullSubMap(NavigableMap m) {
|
static NavigableMap<Integer, Integer> fullSubMap(NavigableMap<Integer, Integer> m) {
|
||||||
return isAscending(m)
|
return isAscending(m)
|
||||||
? m.subMap(Integer.MIN_VALUE, true, Integer.MAX_VALUE, true)
|
? m.subMap(Integer.MIN_VALUE, true, Integer.MAX_VALUE, true)
|
||||||
: m.subMap(Integer.MAX_VALUE, true, Integer.MIN_VALUE, true);
|
: m.subMap(Integer.MAX_VALUE, true, Integer.MIN_VALUE, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static NavigableMap fullHeadMap(NavigableMap m) {
|
static NavigableMap<Integer, Integer> fullHeadMap(NavigableMap<Integer, Integer> m) {
|
||||||
return isAscending(m)
|
return isAscending(m)
|
||||||
? m.headMap(Integer.MAX_VALUE, true)
|
? m.headMap(Integer.MAX_VALUE, true)
|
||||||
: m.headMap(Integer.MIN_VALUE, true);
|
: m.headMap(Integer.MIN_VALUE, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static NavigableMap fullTailMap(NavigableMap m) {
|
static NavigableMap<Integer, Integer> fullTailMap(NavigableMap<Integer, Integer> m) {
|
||||||
return isAscending(m)
|
return isAscending(m)
|
||||||
? m.tailMap(Integer.MIN_VALUE, true)
|
? m.tailMap(Integer.MIN_VALUE, true)
|
||||||
: m.tailMap(Integer.MAX_VALUE, true);
|
: m.tailMap(Integer.MAX_VALUE, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static boolean isAscending(NavigableSet s) {
|
static boolean isAscending(NavigableSet<Integer> s) {
|
||||||
Comparator cmp = s.comparator();
|
var cmp = s.comparator();
|
||||||
return (cmp == null || cmp.compare(1, 2) < 0);
|
return (cmp == null || cmp.compare(1, 2) < 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static NavigableSet fullSubSet(NavigableSet s) {
|
static NavigableSet<Integer> fullSubSet(NavigableSet<Integer> s) {
|
||||||
return isAscending(s)
|
return isAscending(s)
|
||||||
? s.subSet(Integer.MIN_VALUE, true, Integer.MAX_VALUE, true)
|
? s.subSet(Integer.MIN_VALUE, true, Integer.MAX_VALUE, true)
|
||||||
: s.subSet(Integer.MAX_VALUE, true, Integer.MIN_VALUE, true);
|
: s.subSet(Integer.MAX_VALUE, true, Integer.MIN_VALUE, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static NavigableSet fullHeadSet(NavigableSet s) {
|
static NavigableSet<Integer> fullHeadSet(NavigableSet<Integer> s) {
|
||||||
return isAscending(s)
|
return isAscending(s)
|
||||||
? s.headSet(Integer.MAX_VALUE, true)
|
? s.headSet(Integer.MAX_VALUE, true)
|
||||||
: s.headSet(Integer.MIN_VALUE, true);
|
: s.headSet(Integer.MIN_VALUE, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static NavigableSet fullTailSet(NavigableSet s) {
|
static NavigableSet<Integer> fullTailSet(NavigableSet<Integer> s) {
|
||||||
return isAscending(s)
|
return isAscending(s)
|
||||||
? s.tailSet(Integer.MIN_VALUE, true)
|
? s.tailSet(Integer.MIN_VALUE, true)
|
||||||
: s.tailSet(Integer.MAX_VALUE, true);
|
: s.tailSet(Integer.MAX_VALUE, true);
|
||||||
@ -231,21 +231,17 @@ public class LockStep {
|
|||||||
equal(it.next(), expected);
|
equal(it.next(), expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Comparator comparator(NavigableSet s) {
|
static Comparator<? super Integer> comparator(NavigableSet<Integer> s) {
|
||||||
Comparator cmp = s.comparator();
|
var cmp = s.comparator();
|
||||||
return cmp != null ? cmp : new Comparator() {
|
return cmp != null ? cmp : Comparator.naturalOrder();
|
||||||
public int compare(Object o1, Object o2) {
|
|
||||||
return ((Comparable) o1).compareTo(o2); }};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Comparator comparator(NavigableMap m) {
|
static Comparator<? super Integer> comparator(NavigableMap<Integer, Integer> m) {
|
||||||
Comparator cmp = m.comparator();
|
var cmp = m.comparator();
|
||||||
return cmp != null ? cmp : new Comparator() {
|
return cmp != null ? cmp : Comparator.naturalOrder();
|
||||||
public int compare(Object o1, Object o2) {
|
|
||||||
return ((Comparable) o1).compareTo(o2); }};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void checkNavigableSet(final NavigableSet s) {
|
static void checkNavigableSet(final NavigableSet<Integer> s) {
|
||||||
if (s.comparator() == null)
|
if (s.comparator() == null)
|
||||||
check(s.descendingSet().descendingSet().comparator() == null);
|
check(s.descendingSet().descendingSet().comparator() == null);
|
||||||
equal(s.isEmpty(), s.size() == 0);
|
equal(s.isEmpty(), s.size() == 0);
|
||||||
@ -259,7 +255,7 @@ public class LockStep {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Comparator cmp = comparator(s);
|
var cmp = comparator(s);
|
||||||
if (s.isEmpty()) {
|
if (s.isEmpty()) {
|
||||||
THROWS(NoSuchElementException.class,
|
THROWS(NoSuchElementException.class,
|
||||||
() -> s.first(),
|
() -> s.first(),
|
||||||
@ -269,8 +265,8 @@ public class LockStep {
|
|||||||
equal(null, s.ceiling(1));
|
equal(null, s.ceiling(1));
|
||||||
equal(null, s.higher(1));
|
equal(null, s.higher(1));
|
||||||
} else {
|
} else {
|
||||||
Object a = s.first();
|
Integer a = s.first();
|
||||||
Object z = s.last();
|
Integer z = s.last();
|
||||||
equal(s.lower(a), null);
|
equal(s.lower(a), null);
|
||||||
equal(s.higher(z), null);
|
equal(s.higher(z), null);
|
||||||
equal2(s, s.tailSet(a));
|
equal2(s, s.tailSet(a));
|
||||||
@ -285,28 +281,27 @@ public class LockStep {
|
|||||||
equal2(s.headSet(a, true), singleton(a));
|
equal2(s.headSet(a, true), singleton(a));
|
||||||
equal2(s.tailSet(z, true), singleton(z));
|
equal2(s.tailSet(z, true), singleton(z));
|
||||||
}
|
}
|
||||||
Iterator[] its = new Iterator[] {
|
Iterator<?>[] its = new Iterator[] {
|
||||||
s.iterator(),
|
s.iterator(),
|
||||||
s.descendingSet().descendingSet().iterator(),
|
s.descendingSet().descendingSet().iterator(),
|
||||||
};
|
};
|
||||||
for (final Iterator it : its)
|
for (final Iterator<?> it : its)
|
||||||
if (maybe(4))
|
if (maybe(4))
|
||||||
THROWS(IllegalStateException.class, () -> it.remove());
|
THROWS(IllegalStateException.class, () -> it.remove());
|
||||||
Object prev = null;
|
Integer prev = null;
|
||||||
for (Object e : s) {
|
for (final Integer e : s) {
|
||||||
check(s.contains(e));
|
check(s.contains(e));
|
||||||
for (Iterator it : its) equalNext(it, e);
|
for (Iterator<?> it : its) equalNext(it, e);
|
||||||
equal(e, s.ceiling(e));
|
equal(e, s.ceiling(e));
|
||||||
equal(e, s.floor(e));
|
equal(e, s.floor(e));
|
||||||
check(s.higher(e) == null || cmp.compare(e, s.higher(e)) < 0);
|
check(s.higher(e) == null || cmp.compare(e, s.higher(e)) < 0);
|
||||||
equal(s.lower(e), prev);
|
equal(s.lower(e), prev);
|
||||||
if (prev == null) {
|
if (prev != null) {
|
||||||
} else {
|
|
||||||
check(cmp.compare(prev, e) < 0);
|
check(cmp.compare(prev, e) < 0);
|
||||||
}
|
}
|
||||||
prev = e;
|
prev = e;
|
||||||
}
|
}
|
||||||
for (final Iterator it : its) {
|
for (final Iterator<?> it : its) {
|
||||||
if (maybe(2))
|
if (maybe(2))
|
||||||
check(! it.hasNext());
|
check(! it.hasNext());
|
||||||
Fun fun = () -> it.next();
|
Fun fun = () -> it.next();
|
||||||
@ -324,7 +319,7 @@ public class LockStep {
|
|||||||
check(! it2.hasNext());
|
check(! it2.hasNext());
|
||||||
}
|
}
|
||||||
|
|
||||||
static void equalSetsLeaf(final Set s1, final Set s2) {
|
static void equalSetsLeaf(final Set<?> s1, final Set<?> s2) {
|
||||||
equal2(s1, s2);
|
equal2(s1, s2);
|
||||||
equal( s1.size(), s2.size());
|
equal( s1.size(), s2.size());
|
||||||
equal( s1.isEmpty(), s2.isEmpty());
|
equal( s1.isEmpty(), s2.isEmpty());
|
||||||
@ -333,8 +328,8 @@ public class LockStep {
|
|||||||
equal( s1.containsAll(s2), s2.containsAll(s1));
|
equal( s1.containsAll(s2), s2.containsAll(s1));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void equalNavigableSetsLeaf(final NavigableSet s1,
|
static void equalNavigableSetsLeaf(final NavigableSet<Integer> s1,
|
||||||
final NavigableSet s2) {
|
final NavigableSet<Integer> s2) {
|
||||||
equal2(s1, s2);
|
equal2(s1, s2);
|
||||||
equal( s1.size(), s2.size());
|
equal( s1.size(), s2.size());
|
||||||
equal( s1.isEmpty(), s2.isEmpty());
|
equal( s1.isEmpty(), s2.isEmpty());
|
||||||
@ -350,16 +345,16 @@ public class LockStep {
|
|||||||
checkNavigableSet(s2);
|
checkNavigableSet(s2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void equalNavigableSets(final NavigableSet s1,
|
static void equalNavigableSets(final NavigableSet<Integer> s1,
|
||||||
final NavigableSet s2) {
|
final NavigableSet<Integer> s2) {
|
||||||
equalNavigableSetsLeaf(s1, s2);
|
equalNavigableSetsLeaf(s1, s2);
|
||||||
equalNavigableSetsLeaf(s1.descendingSet(), s2.descendingSet());
|
equalNavigableSetsLeaf(s1.descendingSet(), s2.descendingSet());
|
||||||
equalNavigableSetsLeaf(s1.descendingSet().descendingSet(), s2);
|
equalNavigableSetsLeaf(s1.descendingSet().descendingSet(), s2);
|
||||||
Object min = s1.isEmpty() ? Integer.MIN_VALUE : s1.first();
|
Integer min = s1.isEmpty() ? Integer.MIN_VALUE : s1.first();
|
||||||
Object max = s2.isEmpty() ? Integer.MAX_VALUE : s2.last();
|
Integer max = s2.isEmpty() ? Integer.MAX_VALUE : s2.last();
|
||||||
if (s1.comparator() != null &&
|
if (s1.comparator() != null &&
|
||||||
s1.comparator().compare(min, max) > 0) {
|
s1.comparator().compare(min, max) > 0) {
|
||||||
Object tmp = min; min = max; max = tmp;
|
Integer tmp = min; min = max; max = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
equalNavigableSetsLeaf(s1.subSet(min, true, max, true),
|
equalNavigableSetsLeaf(s1.subSet(min, true, max, true),
|
||||||
@ -368,31 +363,29 @@ public class LockStep {
|
|||||||
s2.tailSet(min, true));
|
s2.tailSet(min, true));
|
||||||
equalNavigableSetsLeaf(s1.headSet(max, true),
|
equalNavigableSetsLeaf(s1.headSet(max, true),
|
||||||
s2.headSet(max, true));
|
s2.headSet(max, true));
|
||||||
equalNavigableSetsLeaf((NavigableSet) s1.subSet(min, max),
|
equalNavigableSetsLeaf((NavigableSet<Integer>) s1.subSet(min, max),
|
||||||
(NavigableSet) s2.subSet(min, max));
|
(NavigableSet<Integer>) s2.subSet(min, max));
|
||||||
equalNavigableSetsLeaf((NavigableSet) s1.tailSet(min),
|
equalNavigableSetsLeaf((NavigableSet<Integer>) s1.tailSet(min),
|
||||||
(NavigableSet) s2.tailSet(min));
|
(NavigableSet<Integer>) s2.tailSet(min));
|
||||||
equalNavigableSetsLeaf((NavigableSet) s1.headSet(max),
|
equalNavigableSetsLeaf((NavigableSet<Integer>) s1.headSet(max),
|
||||||
(NavigableSet) s2.headSet(max));
|
(NavigableSet<Integer>) s2.headSet(max));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destined for a Collections.java near you?
|
// Destined for a Collections.java near you?
|
||||||
static <T> T[] concat(T[]... arrays) {
|
static <T> T[] concat(T[]... arrays) {
|
||||||
int len = 0;
|
int len = 0;
|
||||||
for (int i = 0; i < arrays.length; i++)
|
for (T[] arr : arrays) len += arr.length;
|
||||||
len += arrays[i].length;
|
|
||||||
T[] a = (T[])java.lang.reflect.Array
|
T[] a = (T[])java.lang.reflect.Array
|
||||||
.newInstance(arrays[0].getClass().getComponentType(), len);
|
.newInstance(arrays[0].getClass().getComponentType(), len);
|
||||||
int k = 0;
|
int k = 0;
|
||||||
for (int i = 0; i < arrays.length; i++) {
|
for (T[] arr : arrays) {
|
||||||
T[] array = arrays[i];
|
System.arraycopy(arr, 0, a, k, arr.length);
|
||||||
System.arraycopy(array, 0, a, k, array.length);
|
k += arr.length;
|
||||||
k += array.length;
|
|
||||||
}
|
}
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void checkNavigableMap(final NavigableMap m) {
|
static void checkNavigableMap(final NavigableMap<Integer, Integer> m) {
|
||||||
if (m.comparator() == null) {
|
if (m.comparator() == null) {
|
||||||
check(m.descendingMap().descendingMap().comparator() == null);
|
check(m.descendingMap().descendingMap().comparator() == null);
|
||||||
check(m.descendingKeySet().descendingSet().comparator() == null);
|
check(m.descendingKeySet().descendingSet().comparator() == null);
|
||||||
@ -402,7 +395,7 @@ public class LockStep {
|
|||||||
if (maybe(4))
|
if (maybe(4))
|
||||||
equal2(m, serialClone(m));
|
equal2(m, serialClone(m));
|
||||||
equal2(m.keySet(), m.descendingKeySet());
|
equal2(m.keySet(), m.descendingKeySet());
|
||||||
Comparator cmp = comparator(m);
|
var cmp = comparator(m);
|
||||||
if (m.isEmpty()) {
|
if (m.isEmpty()) {
|
||||||
THROWS(NoSuchElementException.class,
|
THROWS(NoSuchElementException.class,
|
||||||
() -> m.firstKey(),
|
() -> m.firstKey(),
|
||||||
@ -420,8 +413,8 @@ public class LockStep {
|
|||||||
equal(null, m.ceilingEntry(1));
|
equal(null, m.ceilingEntry(1));
|
||||||
equal(null, m.higherEntry(1));
|
equal(null, m.higherEntry(1));
|
||||||
} else {
|
} else {
|
||||||
Object a = m.firstKey();
|
Integer a = m.firstKey();
|
||||||
Object z = m.lastKey();
|
Integer z = m.lastKey();
|
||||||
equal(m.lowerKey(a), null);
|
equal(m.lowerKey(a), null);
|
||||||
equal(m.higherKey(z), null);
|
equal(m.higherKey(z), null);
|
||||||
equal(a, m.firstEntry().getKey());
|
equal(a, m.firstEntry().getKey());
|
||||||
@ -439,32 +432,32 @@ public class LockStep {
|
|||||||
equal2(m.tailMap(z, true), singletonMap(z, m.get(z)));
|
equal2(m.tailMap(z, true), singletonMap(z, m.get(z)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Iterator[] kits = new Iterator[] {
|
Iterator<?>[] kits = new Iterator[] {
|
||||||
m.keySet().iterator(),
|
m.keySet().iterator(),
|
||||||
m.descendingMap().descendingKeySet().iterator(),
|
m.descendingMap().descendingKeySet().iterator(),
|
||||||
m.descendingKeySet().descendingSet().iterator(),
|
m.descendingKeySet().descendingSet().iterator(),
|
||||||
};
|
};
|
||||||
Iterator[] vits = new Iterator[] {
|
Iterator<?>[] vits = new Iterator[] {
|
||||||
m.values().iterator(),
|
m.values().iterator(),
|
||||||
m.descendingMap().descendingMap().values().iterator(),
|
m.descendingMap().descendingMap().values().iterator(),
|
||||||
};
|
};
|
||||||
Iterator[] eits = new Iterator[] {
|
Iterator<?>[] eits = new Iterator[] {
|
||||||
m.entrySet().iterator(),
|
m.entrySet().iterator(),
|
||||||
m.descendingMap().descendingMap().entrySet().iterator(),
|
m.descendingMap().descendingMap().entrySet().iterator(),
|
||||||
};
|
};
|
||||||
Iterator[] its = concat(kits, vits, eits);
|
Iterator<?>[] its = concat(kits, vits, eits);
|
||||||
for (final Iterator it : its)
|
for (final Iterator<?> it : its)
|
||||||
if (maybe(4))
|
if (maybe(4))
|
||||||
THROWS(IllegalStateException.class, () -> it.remove());
|
THROWS(IllegalStateException.class, () -> it.remove());
|
||||||
Map.Entry prev = null;
|
Map.Entry<Integer, Integer> prev = null;
|
||||||
for (Map.Entry e : (Set<Map.Entry>) m.entrySet()) {
|
for (var e : m.entrySet()) {
|
||||||
Object k = e.getKey();
|
Integer k = e.getKey();
|
||||||
Object v = e.getValue();
|
Integer v = e.getValue();
|
||||||
check(m.containsKey(k));
|
check(m.containsKey(k));
|
||||||
check(m.containsValue(v));
|
check(m.containsValue(v));
|
||||||
for (Iterator kit : kits) equalNext(kit, k);
|
for (var kit : kits) equalNext(kit, k);
|
||||||
for (Iterator vit : vits) equalNext(vit, v);
|
for (var vit : vits) equalNext(vit, v);
|
||||||
for (Iterator eit : eits) equalNext(eit, e);
|
for (var eit : eits) equalNext(eit, e);
|
||||||
equal(k, m.ceilingKey(k));
|
equal(k, m.ceilingKey(k));
|
||||||
equal(k, m.ceilingEntry(k).getKey());
|
equal(k, m.ceilingEntry(k).getKey());
|
||||||
equal(k, m.floorKey(k));
|
equal(k, m.floorKey(k));
|
||||||
@ -480,7 +473,7 @@ public class LockStep {
|
|||||||
}
|
}
|
||||||
prev = e;
|
prev = e;
|
||||||
}
|
}
|
||||||
for (final Iterator it : its) {
|
for (final var it : its) {
|
||||||
if (maybe(2))
|
if (maybe(2))
|
||||||
check(! it.hasNext());
|
check(! it.hasNext());
|
||||||
Fun fun = () -> it.next();
|
Fun fun = () -> it.next();
|
||||||
@ -488,8 +481,8 @@ public class LockStep {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void equalNavigableMapsLeaf(final NavigableMap m1,
|
static void equalNavigableMapsLeaf(final NavigableMap<Integer, Integer> m1,
|
||||||
final NavigableMap m2) {
|
final NavigableMap<Integer, Integer> m2) {
|
||||||
equal2(m1, m2);
|
equal2(m1, m2);
|
||||||
equal( m1.size(), m2.size());
|
equal( m1.size(), m2.size());
|
||||||
equal( m1.isEmpty(), m2.isEmpty());
|
equal( m1.isEmpty(), m2.isEmpty());
|
||||||
@ -501,8 +494,8 @@ public class LockStep {
|
|||||||
checkNavigableMap(m2);
|
checkNavigableMap(m2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void equalNavigableMaps(NavigableMap m1,
|
static void equalNavigableMaps(NavigableMap<Integer, Integer> m1,
|
||||||
NavigableMap m2) {
|
NavigableMap<Integer, Integer> m2) {
|
||||||
equalNavigableMapsLeaf(m1, m2);
|
equalNavigableMapsLeaf(m1, m2);
|
||||||
equalSetsLeaf(m1.keySet(), m2.keySet());
|
equalSetsLeaf(m1.keySet(), m2.keySet());
|
||||||
equalNavigableSets(m1.navigableKeySet(),
|
equalNavigableSets(m1.navigableKeySet(),
|
||||||
@ -515,8 +508,8 @@ public class LockStep {
|
|||||||
m2.descendingMap());
|
m2.descendingMap());
|
||||||
equalNavigableMapsLeaf(m1.descendingMap().descendingMap(),
|
equalNavigableMapsLeaf(m1.descendingMap().descendingMap(),
|
||||||
m2);
|
m2);
|
||||||
equalNavigableSetsLeaf((NavigableSet) m1.descendingMap().keySet(),
|
equalNavigableSetsLeaf((NavigableSet<Integer>) m1.descendingMap().keySet(),
|
||||||
(NavigableSet) m2.descendingMap().keySet());
|
(NavigableSet<Integer>) m2.descendingMap().keySet());
|
||||||
equalNavigableSetsLeaf(m1.descendingMap().descendingKeySet(),
|
equalNavigableSetsLeaf(m1.descendingMap().descendingKeySet(),
|
||||||
m2.descendingMap().descendingKeySet());
|
m2.descendingMap().descendingKeySet());
|
||||||
equal2(m1.descendingMap().entrySet(),
|
equal2(m1.descendingMap().entrySet(),
|
||||||
@ -525,11 +518,11 @@ public class LockStep {
|
|||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
// submaps
|
// submaps
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
Object min = Integer.MIN_VALUE;
|
Integer min = Integer.MIN_VALUE;
|
||||||
Object max = Integer.MAX_VALUE;
|
Integer max = Integer.MAX_VALUE;
|
||||||
if (m1.comparator() != null
|
if (m1.comparator() != null
|
||||||
&& m1.comparator().compare(min, max) > 0) {
|
&& m1.comparator().compare(min, max) > 0) {
|
||||||
Object tmp = min; min = max; max = tmp;
|
Integer tmp = min; min = max; max = tmp;
|
||||||
}
|
}
|
||||||
switch (rnd.nextInt(6)) {
|
switch (rnd.nextInt(6)) {
|
||||||
case 0:
|
case 0:
|
||||||
@ -545,107 +538,119 @@ public class LockStep {
|
|||||||
m2.headMap(max, true));
|
m2.headMap(max, true));
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
equalNavigableMapsLeaf((NavigableMap) m1.subMap(min, max),
|
equalNavigableMapsLeaf((NavigableMap<Integer, Integer>) m1.subMap(min, max),
|
||||||
(NavigableMap) m2.subMap(min, max));
|
(NavigableMap<Integer, Integer>) m2.subMap(min, max));
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
equalNavigableMapsLeaf((NavigableMap) m1.tailMap(min),
|
equalNavigableMapsLeaf((NavigableMap<Integer, Integer>) m1.tailMap(min),
|
||||||
(NavigableMap) m2.tailMap(min));
|
(NavigableMap<Integer, Integer>) m2.tailMap(min));
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
equalNavigableMapsLeaf((NavigableMap) m1.headMap(max),
|
equalNavigableMapsLeaf((NavigableMap<Integer, Integer>) m1.headMap(max),
|
||||||
(NavigableMap) m2.headMap(max));
|
(NavigableMap<Integer, Integer>) m2.headMap(max));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract static class MapFrobber { abstract void frob(NavigableMap m); }
|
interface MapFrobber { void frob(NavigableMap<Integer, Integer> m); }
|
||||||
abstract static class SetFrobber { abstract void frob(NavigableSet m); }
|
interface SetFrobber { void frob(NavigableSet<Integer> m); }
|
||||||
|
|
||||||
static MapFrobber randomAdder(NavigableMap m) {
|
static MapFrobber randomAdder(NavigableMap<Integer, Integer> m) {
|
||||||
final Integer k = unusedKey(m);
|
final Integer k = unusedKey(m);
|
||||||
final MapFrobber[] randomAdders = {
|
final MapFrobber[] randomAdders = {
|
||||||
new MapFrobber() {void frob(NavigableMap m) {
|
map -> {
|
||||||
equal(m.put(k, k+1), null);
|
equal(map.put(k, k + 1), null);
|
||||||
equal(m.get(k), k+1);
|
equal(map.get(k), k + 1);
|
||||||
if (maybe(4)) {
|
if (maybe(4)) {
|
||||||
equal(m.put(k, k+1), k+1);
|
equal(map.put(k, k + 1), k + 1);
|
||||||
equal(m.get(k), k+1);}}},
|
equal(map.get(k), k + 1);}},
|
||||||
new MapFrobber() {void frob(NavigableMap m) {
|
map -> {
|
||||||
m.descendingMap().put(k, k+1);
|
map.descendingMap().put(k, k + 1);
|
||||||
equal(m.get(k), k+1);}},
|
equal(map.get(k), k + 1);},
|
||||||
new MapFrobber() {void frob(NavigableMap m) {
|
map -> map.tailMap(k,true).headMap(k,true).put(k, k + 1),
|
||||||
m.tailMap(k,true).headMap(k,true).put(k,k+1);}},
|
map -> {
|
||||||
new MapFrobber() {void frob(NavigableMap m) {
|
equal(map.tailMap(k,true).headMap(k,true).putIfAbsent(k, k + 1), null);
|
||||||
m.tailMap(k,true).headMap(k,true).descendingMap().put(k,k+1);}}
|
equal(map.tailMap(k,true).headMap(k,true).putIfAbsent(k, k + 1), k + 1);},
|
||||||
|
map -> {
|
||||||
|
equal(map.tailMap(k,true).headMap(k,true).merge(k,k,Integer::sum), k);
|
||||||
|
equal(map.tailMap(k,true).headMap(k,true).merge(k,1,Integer::sum), k+1);},
|
||||||
|
map -> equal(map.subMap(k,true, k, true).computeIfAbsent(k, key -> key + 1), k + 1),
|
||||||
|
map -> {
|
||||||
|
equal(map.subMap(k,true, k, true).computeIfPresent(k, (key, val) -> 1), null);
|
||||||
|
equal(map.tailMap(k,true).compute(k, (key, val) -> {
|
||||||
|
equal(val, null);
|
||||||
|
return 1;
|
||||||
|
}), 1);
|
||||||
|
equal(map.headMap(k, true).computeIfPresent(k, (key, val) -> val + key), k + 1);
|
||||||
|
equal(map.tailMap(k, false).computeIfPresent(k, (key, val) -> 1), null);
|
||||||
|
equal(map.headMap(k, false).compute(k, (key, val) -> null), null);
|
||||||
|
equal(map.tailMap(k, false).computeIfAbsent(k, key -> null), null);
|
||||||
|
},
|
||||||
|
map -> map.tailMap(k,true).headMap(k,true).descendingMap().put(k, k + 1)
|
||||||
};
|
};
|
||||||
return new MapFrobber() {void frob(NavigableMap m) {
|
return map -> {
|
||||||
randomAdders[rnd.nextInt(randomAdders.length)].frob(m);
|
randomAdders[rnd.nextInt(randomAdders.length)].frob(map);
|
||||||
if (maybe(2)) equal(m.get(k), k+1);
|
if (maybe(2)) equal(map.get(k), k + 1);
|
||||||
if (maybe(4)) {
|
if (maybe(4)) {
|
||||||
equal(m.put(k, k+1), k+1);
|
equal(map.put(k, k + 1), k + 1);
|
||||||
equal(m.get(k), k+1);}}};
|
equal(map.get(k), k + 1);}};
|
||||||
}
|
}
|
||||||
|
|
||||||
static SetFrobber randomAdder(NavigableSet s) {
|
static SetFrobber randomAdder(NavigableSet<Integer> s) {
|
||||||
final Integer e = unusedElt(s);
|
final Integer e = unusedElt(s);
|
||||||
final SetFrobber[] randomAdders = {
|
final SetFrobber[] randomAdders = {
|
||||||
new SetFrobber() {void frob(NavigableSet s) {
|
set -> check(set.add(e)),
|
||||||
check(s.add(e));}},
|
set -> set.descendingSet().add(e),
|
||||||
new SetFrobber() {void frob(NavigableSet s) {
|
set -> set.tailSet(e,true).headSet(e,true).add(e),
|
||||||
s.descendingSet().add(e);}},
|
set -> set.descendingSet().tailSet(e,true).headSet(e,true).add(e)
|
||||||
new SetFrobber() {void frob(NavigableSet s) {
|
|
||||||
s.tailSet(e,true).headSet(e,true).add(e);}},
|
|
||||||
new SetFrobber() {void frob(NavigableSet s) {
|
|
||||||
s.descendingSet().tailSet(e,true).headSet(e,true).add(e);}}
|
|
||||||
};
|
};
|
||||||
return new SetFrobber() {void frob(NavigableSet s) {
|
return set -> {
|
||||||
if (maybe(2)) check(! s.contains(e));
|
if (maybe(2)) check(! set.contains(e));
|
||||||
randomAdders[rnd.nextInt(randomAdders.length)].frob(s);
|
randomAdders[rnd.nextInt(randomAdders.length)].frob(set);
|
||||||
if (maybe(2)) check(! s.add(e));
|
if (maybe(2)) check(! set.add(e));
|
||||||
if (maybe(2)) check(s.contains(e));}};
|
if (maybe(2)) check(set.contains(e));};
|
||||||
}
|
}
|
||||||
|
|
||||||
static Integer unusedElt(NavigableSet s) {
|
static Integer unusedElt(NavigableSet<Integer> s) {
|
||||||
Integer e;
|
Integer e;
|
||||||
do { e = rnd.nextInt(1024); }
|
do { e = rnd.nextInt(1024); }
|
||||||
while (s.contains(e));
|
while (s.contains(e));
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Integer unusedKey(NavigableMap m) {
|
static Integer unusedKey(NavigableMap<Integer, Integer> m) {
|
||||||
Integer k;
|
Integer k;
|
||||||
do { k = rnd.nextInt(1024); }
|
do { k = rnd.nextInt(1024); }
|
||||||
while (m.containsKey(k));
|
while (m.containsKey(k));
|
||||||
return k;
|
return k;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Integer usedKey(NavigableMap m) {
|
static Integer usedKey(NavigableMap<Integer, Integer> m) {
|
||||||
Integer x = rnd.nextInt(1024);
|
Integer x = rnd.nextInt(1024);
|
||||||
Integer floor = (Integer) m.floorKey(x);
|
Integer floor = m.floorKey(x);
|
||||||
Integer ceiling = (Integer) m.ceilingKey(x);
|
Integer ceiling = m.ceilingKey(x);
|
||||||
if (floor != null) return floor;
|
if (floor != null) return floor;
|
||||||
check(ceiling != null);
|
check(ceiling != null);
|
||||||
return ceiling;
|
return ceiling;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Integer usedElt(NavigableSet s) {
|
static Integer usedElt(NavigableSet<Integer> s) {
|
||||||
Integer x = rnd.nextInt(1024);
|
Integer x = rnd.nextInt(1024);
|
||||||
Integer floor = (Integer) s.floor(x);
|
Integer floor = s.floor(x);
|
||||||
Integer ceiling = (Integer) s.ceiling(x);
|
Integer ceiling = s.ceiling(x);
|
||||||
if (floor != null) return floor;
|
if (floor != null) return floor;
|
||||||
check(ceiling != null);
|
check(ceiling != null);
|
||||||
return ceiling;
|
return ceiling;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void checkUnusedKey(NavigableMap m, Object k) {
|
static void checkUnusedKey(NavigableMap<Integer, Integer> m, Integer k) {
|
||||||
check(! m.containsKey(k));
|
check(! m.containsKey(k));
|
||||||
equal(m.get(k), null);
|
equal(m.get(k), null);
|
||||||
if (maybe(2))
|
if (maybe(2))
|
||||||
equal(m.remove(k), null);
|
equal(m.remove(k), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void checkUnusedElt(NavigableSet s, Object e) {
|
static void checkUnusedElt(NavigableSet<Integer> s, Integer e) {
|
||||||
if (maybe(2))
|
if (maybe(2))
|
||||||
check(! s.contains(e));
|
check(! s.contains(e));
|
||||||
if (maybe(2)) {
|
if (maybe(2)) {
|
||||||
@ -656,32 +661,32 @@ public class LockStep {
|
|||||||
check(! s.remove(e));
|
check(! s.remove(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
static Fun remover(final Iterator it) {
|
static Fun remover(final Iterator<?> it) {
|
||||||
return () -> it.remove();
|
return () -> it.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
static MapFrobber randomRemover(NavigableMap m) {
|
static MapFrobber randomRemover(NavigableMap<Integer, Integer> m) {
|
||||||
final Integer k = usedKey(m);
|
final Integer k = usedKey(m);
|
||||||
final MapFrobber[] randomRemovers = {
|
final MapFrobber[] randomRemovers = {
|
||||||
new MapFrobber() {void frob(NavigableMap m) {
|
map -> {
|
||||||
Map.Entry e = m.firstEntry();
|
var e = map.firstEntry();
|
||||||
equal(m.pollFirstEntry(), e);
|
equal(map.pollFirstEntry(), e);
|
||||||
checkUnusedKey(m, e.getKey());}},
|
checkUnusedKey(map, e.getKey());},
|
||||||
new MapFrobber() {void frob(NavigableMap m) {
|
map -> {
|
||||||
Map.Entry e = m.lastEntry();
|
var e = map.lastEntry();
|
||||||
equal(m.pollLastEntry(), e);
|
equal(map.pollLastEntry(), e);
|
||||||
checkUnusedKey(m, e.getKey());}},
|
checkUnusedKey(map, e.getKey());},
|
||||||
new MapFrobber() {void frob(NavigableMap m) {
|
map -> {
|
||||||
check(m.remove(k) != null);
|
check(map.remove(k) != null);
|
||||||
checkUnusedKey(m, k);}},
|
checkUnusedKey(map, k);},
|
||||||
new MapFrobber() {void frob(NavigableMap m) {
|
map -> {
|
||||||
m.subMap(k, true, k, true).clear();
|
map.subMap(k, true, k, true).clear();
|
||||||
checkUnusedKey(m, k);}},
|
checkUnusedKey(map, k);},
|
||||||
new MapFrobber() {void frob(NavigableMap m) {
|
map -> {
|
||||||
m.descendingMap().subMap(k, true, k, true).clear();
|
map.descendingMap().subMap(k, true, k, true).clear();
|
||||||
checkUnusedKey(m, k);}},
|
checkUnusedKey(map, k);},
|
||||||
new MapFrobber() {void frob(NavigableMap m) {
|
map -> {
|
||||||
final Iterator it = m.keySet().iterator();
|
final var it = map.keySet().iterator();
|
||||||
while (it.hasNext())
|
while (it.hasNext())
|
||||||
if (it.next().equals(k)) {
|
if (it.next().equals(k)) {
|
||||||
it.remove();
|
it.remove();
|
||||||
@ -689,9 +694,9 @@ public class LockStep {
|
|||||||
THROWS(IllegalStateException.class,
|
THROWS(IllegalStateException.class,
|
||||||
() -> it.remove());
|
() -> it.remove());
|
||||||
}
|
}
|
||||||
checkUnusedKey(m, k);}},
|
checkUnusedKey(map, k);},
|
||||||
new MapFrobber() {void frob(NavigableMap m) {
|
map -> {
|
||||||
final Iterator it = m.navigableKeySet().descendingIterator();
|
final var it = map.navigableKeySet().descendingIterator();
|
||||||
while (it.hasNext())
|
while (it.hasNext())
|
||||||
if (it.next().equals(k)) {
|
if (it.next().equals(k)) {
|
||||||
it.remove();
|
it.remove();
|
||||||
@ -699,44 +704,44 @@ public class LockStep {
|
|||||||
THROWS(IllegalStateException.class,
|
THROWS(IllegalStateException.class,
|
||||||
() -> it.remove());
|
() -> it.remove());
|
||||||
}
|
}
|
||||||
checkUnusedKey(m, k);}},
|
checkUnusedKey(map, k);},
|
||||||
new MapFrobber() {void frob(NavigableMap m) {
|
map -> {
|
||||||
final Iterator<Map.Entry> it = m.entrySet().iterator();
|
final var it = map.entrySet().iterator();
|
||||||
while (it.hasNext())
|
while (it.hasNext())
|
||||||
if (it.next().getKey().equals(k)) {
|
if (it.next().getKey().equals(k)) {
|
||||||
it.remove();
|
it.remove();
|
||||||
if (maybe(2))
|
if (maybe(2))
|
||||||
THROWS(IllegalStateException.class, remover(it));
|
THROWS(IllegalStateException.class, remover(it));
|
||||||
}
|
}
|
||||||
checkUnusedKey(m, k);}},
|
checkUnusedKey(map, k);},
|
||||||
};
|
};
|
||||||
|
|
||||||
return randomRemovers[rnd.nextInt(randomRemovers.length)];
|
return randomRemovers[rnd.nextInt(randomRemovers.length)];
|
||||||
}
|
}
|
||||||
|
|
||||||
static SetFrobber randomRemover(NavigableSet s) {
|
static SetFrobber randomRemover(NavigableSet<Integer> s) {
|
||||||
final Integer e = usedElt(s);
|
final Integer e = usedElt(s);
|
||||||
|
|
||||||
final SetFrobber[] randomRemovers = {
|
final SetFrobber[] randomRemovers = {
|
||||||
new SetFrobber() {void frob(NavigableSet s) {
|
set -> {
|
||||||
Object e = s.first();
|
var fst = set.first();
|
||||||
equal(s.pollFirst(), e);
|
equal(set.pollFirst(), fst);
|
||||||
checkUnusedElt(s, e);}},
|
checkUnusedElt(set, fst);},
|
||||||
new SetFrobber() {void frob(NavigableSet s) {
|
set -> {
|
||||||
Object e = s.last();
|
var lst = set.last();
|
||||||
equal(s.pollLast(), e);
|
equal(set.pollLast(), lst);
|
||||||
checkUnusedElt(s, e);}},
|
checkUnusedElt(set, lst);},
|
||||||
new SetFrobber() {void frob(NavigableSet s) {
|
set -> {
|
||||||
check(s.remove(e));
|
check(set.remove(e));
|
||||||
checkUnusedElt(s, e);}},
|
checkUnusedElt(set, e);},
|
||||||
new SetFrobber() {void frob(NavigableSet s) {
|
set -> {
|
||||||
s.subSet(e, true, e, true).clear();
|
set.subSet(e, true, e, true).clear();
|
||||||
checkUnusedElt(s, e);}},
|
checkUnusedElt(set, e);},
|
||||||
new SetFrobber() {void frob(NavigableSet s) {
|
set -> {
|
||||||
s.descendingSet().subSet(e, true, e, true).clear();
|
set.descendingSet().subSet(e, true, e, true).clear();
|
||||||
checkUnusedElt(s, e);}},
|
checkUnusedElt(set, e);},
|
||||||
new SetFrobber() {void frob(NavigableSet s) {
|
set -> {
|
||||||
final Iterator it = s.iterator();
|
final var it = set.iterator();
|
||||||
while (it.hasNext())
|
while (it.hasNext())
|
||||||
if (it.next().equals(e)) {
|
if (it.next().equals(e)) {
|
||||||
it.remove();
|
it.remove();
|
||||||
@ -744,9 +749,9 @@ public class LockStep {
|
|||||||
THROWS(IllegalStateException.class,
|
THROWS(IllegalStateException.class,
|
||||||
() -> it.remove());
|
() -> it.remove());
|
||||||
}
|
}
|
||||||
checkUnusedElt(s, e);}},
|
checkUnusedElt(set, e);},
|
||||||
new SetFrobber() {void frob(NavigableSet s) {
|
set -> {
|
||||||
final Iterator it = s.descendingSet().iterator();
|
final var it = set.descendingSet().iterator();
|
||||||
while (it.hasNext())
|
while (it.hasNext())
|
||||||
if (it.next().equals(e)) {
|
if (it.next().equals(e)) {
|
||||||
it.remove();
|
it.remove();
|
||||||
@ -754,9 +759,9 @@ public class LockStep {
|
|||||||
THROWS(IllegalStateException.class,
|
THROWS(IllegalStateException.class,
|
||||||
() -> it.remove());
|
() -> it.remove());
|
||||||
}
|
}
|
||||||
checkUnusedElt(s, e);}},
|
checkUnusedElt(set, e);},
|
||||||
new SetFrobber() {void frob(NavigableSet s) {
|
set -> {
|
||||||
final Iterator it = s.descendingIterator();
|
final var it = set.descendingIterator();
|
||||||
while (it.hasNext())
|
while (it.hasNext())
|
||||||
if (it.next().equals(e)) {
|
if (it.next().equals(e)) {
|
||||||
it.remove();
|
it.remove();
|
||||||
@ -764,94 +769,96 @@ public class LockStep {
|
|||||||
THROWS(IllegalStateException.class,
|
THROWS(IllegalStateException.class,
|
||||||
() -> it.remove());
|
() -> it.remove());
|
||||||
}
|
}
|
||||||
checkUnusedElt(s, e);}}
|
checkUnusedElt(set, e);}
|
||||||
};
|
};
|
||||||
|
|
||||||
return randomRemovers[rnd.nextInt(randomRemovers.length)];
|
return randomRemovers[rnd.nextInt(randomRemovers.length)];
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lockStep(NavigableMap m1,
|
static void lockStep(NavigableMap<Integer, Integer> m1,
|
||||||
NavigableMap m2) {
|
NavigableMap<Integer, Integer> m2) {
|
||||||
if (! (thorough || maybe(3))) return;
|
if (! (thorough || maybe(3))) return;
|
||||||
if (maybe(4)) m1 = serialClone(m1);
|
if (maybe(4)) m1 = serialClone(m1);
|
||||||
if (maybe(4)) m2 = serialClone(m2);
|
if (maybe(4)) m2 = serialClone(m2);
|
||||||
|
|
||||||
List<NavigableMap> maps = Arrays.asList(m1, m2);
|
var maps = Arrays.asList(m1, m2);
|
||||||
for (NavigableMap m : maps) testEmptyMap(m);
|
for (var m : maps) testEmptyMap(m);
|
||||||
final Set<Integer> ints = new HashSet<>();
|
final Set<Integer> ints = new HashSet<>();
|
||||||
while (ints.size() < size)
|
while (ints.size() < size)
|
||||||
ints.add(rnd.nextInt(1024));
|
ints.add(rnd.nextInt(1024));
|
||||||
final Integer[] elts = ints.toArray(new Integer[size]);
|
final Integer[] elts = ints.toArray(new Integer[size]);
|
||||||
|
equal(elts.length, size);
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
MapFrobber adder = randomAdder(m1);
|
MapFrobber adder = randomAdder(m1);
|
||||||
for (final NavigableMap m : maps) {
|
for (var m : maps) {
|
||||||
adder.frob(m);
|
adder.frob(m);
|
||||||
equal(m.size(), i+1);
|
equal(m.size(), i+1);
|
||||||
}
|
}
|
||||||
equalNavigableMaps(m1, m2);
|
equalNavigableMaps(m1, m2);
|
||||||
}
|
}
|
||||||
for (final NavigableMap m : maps) {
|
for (var m : maps) {
|
||||||
final Object e = usedKey(m);
|
final var e = usedKey(m);
|
||||||
THROWS(IllegalArgumentException.class,
|
THROWS(IllegalArgumentException.class,
|
||||||
() -> {m.subMap(e,true,e,false)
|
() -> m.subMap(e,true,e,false).subMap(e,true,e,true),
|
||||||
.subMap(e,true,e,true);},
|
() -> m.subMap(e,false,e,true).subMap(e,true,e,true),
|
||||||
() -> {m.subMap(e,false,e,true)
|
|
||||||
.subMap(e,true,e,true);},
|
|
||||||
() -> m.tailMap(e,false).tailMap(e,true),
|
() -> m.tailMap(e,false).tailMap(e,true),
|
||||||
() -> m.headMap(e,false).headMap(e,true));
|
() -> m.headMap(e,false).headMap(e,true),
|
||||||
|
() -> m.headMap(e, false).put(e, 0),
|
||||||
|
() -> m.tailMap(e, false).putIfAbsent(e, 0),
|
||||||
|
() -> m.headMap(e, false).computeIfAbsent(e, k -> 1),
|
||||||
|
() -> m.tailMap(e, false).compute(e, (k, v) -> 0));
|
||||||
}
|
}
|
||||||
//System.out.printf("%s%n", m1);
|
//System.out.printf("%s%n", m1);
|
||||||
for (int i = size; i > 0; i--) {
|
for (int i = size; i > 0; i--) {
|
||||||
MapFrobber remover = randomRemover(m1);
|
MapFrobber remover = randomRemover(m1);
|
||||||
for (final NavigableMap m : maps) {
|
for (var m : maps) {
|
||||||
remover.frob(m);
|
remover.frob(m);
|
||||||
equal(m.size(), i-1);
|
equal(m.size(), i-1);
|
||||||
}
|
}
|
||||||
equalNavigableMaps(m1, m2);
|
equalNavigableMaps(m1, m2);
|
||||||
}
|
}
|
||||||
for (NavigableMap m : maps) testEmptyMap(m);
|
for (var m : maps) testEmptyMap(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lockStep(NavigableSet s1,
|
static void lockStep(NavigableSet<Integer> s1,
|
||||||
NavigableSet s2) {
|
NavigableSet<Integer> s2) {
|
||||||
if (! (thorough || maybe(3))) return;
|
if (! (thorough || maybe(3))) return;
|
||||||
if (maybe(4)) s1 = serialClone(s1);
|
if (maybe(4)) s1 = serialClone(s1);
|
||||||
if (maybe(4)) s2 = serialClone(s2);
|
if (maybe(4)) s2 = serialClone(s2);
|
||||||
|
|
||||||
List<NavigableSet> sets = Arrays.asList(s1, s2);
|
var sets = Arrays.asList(s1, s2);
|
||||||
for (NavigableSet s : sets) testEmptySet(s);
|
for (var s : sets) testEmptySet(s);
|
||||||
final Set<Integer> ints = new HashSet<>();
|
final Set<Integer> ints = new HashSet<>();
|
||||||
while (ints.size() < size)
|
while (ints.size() < size)
|
||||||
ints.add(rnd.nextInt(1024));
|
ints.add(rnd.nextInt(1024));
|
||||||
final Integer[] elts = ints.toArray(new Integer[size]);
|
final Integer[] elts = ints.toArray(new Integer[size]);
|
||||||
|
equal(elts.length, size);
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
SetFrobber adder = randomAdder(s1);
|
SetFrobber adder = randomAdder(s1);
|
||||||
for (final NavigableSet s : sets) {
|
for (var s : sets) {
|
||||||
adder.frob(s);
|
adder.frob(s);
|
||||||
equal(s.size(), i+1);
|
equal(s.size(), i+1);
|
||||||
}
|
}
|
||||||
equalNavigableSets(s1, s2);
|
equalNavigableSets(s1, s2);
|
||||||
}
|
}
|
||||||
for (final NavigableSet s : sets) {
|
for (var s : sets) {
|
||||||
final Object e = usedElt(s);
|
final Integer e = usedElt(s);
|
||||||
THROWS(IllegalArgumentException.class,
|
THROWS(IllegalArgumentException.class,
|
||||||
() -> {s.subSet(e,true,e,false)
|
() -> s.subSet(e,true,e,false).subSet(e,true,e,true),
|
||||||
.subSet(e,true,e,true);},
|
() -> s.subSet(e,false,e,true).subSet(e,true,e,true),
|
||||||
() -> {s.subSet(e,false,e,true)
|
|
||||||
.subSet(e,true,e,true);},
|
|
||||||
() -> s.tailSet(e,false).tailSet(e,true),
|
() -> s.tailSet(e,false).tailSet(e,true),
|
||||||
() -> s.headSet(e,false).headSet(e,true));
|
() -> s.headSet(e,false).headSet(e,true));
|
||||||
}
|
}
|
||||||
//System.out.printf("%s%n", s1);
|
//System.out.printf("%s%n", s1);
|
||||||
for (int i = size; i > 0; i--) {
|
for (int i = size; i > 0; i--) {
|
||||||
SetFrobber remover = randomRemover(s1);
|
SetFrobber remover = randomRemover(s1);
|
||||||
for (final NavigableSet s : sets) {
|
for (var s : sets) {
|
||||||
remover.frob(s);
|
remover.frob(s);
|
||||||
equal(s.size(), i-1);
|
equal(s.size(), i-1);
|
||||||
}
|
}
|
||||||
equalNavigableSets(s1, s2);
|
equalNavigableSets(s1, s2);
|
||||||
}
|
}
|
||||||
for (NavigableSet s : sets) testEmptySet(s);
|
for (var s : sets) testEmptySet(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------- Infrastructure ---------------------------
|
//--------------------- Infrastructure ---------------------------
|
||||||
@ -862,7 +869,7 @@ public class LockStep {
|
|||||||
static void unexpected(Throwable t) { failed++; t.printStackTrace(); }
|
static void unexpected(Throwable t) { failed++; t.printStackTrace(); }
|
||||||
static void check(boolean cond) { if (cond) pass(); else fail(); }
|
static void check(boolean cond) { if (cond) pass(); else fail(); }
|
||||||
static void equal(Object x, Object y) {
|
static void equal(Object x, Object y) {
|
||||||
if (x == null ? y == null : x.equals(y)) pass();
|
if (Objects.equals(x, y)) pass();
|
||||||
else {System.out.println(x + " not equal to " + y); fail();}}
|
else {System.out.println(x + " not equal to " + y); fail();}}
|
||||||
static void equal2(Object x, Object y) {equal(x, y); equal(y, x);}
|
static void equal2(Object x, Object y) {equal(x, y); equal(y, x);}
|
||||||
public static void main(String[] args) throws Throwable {
|
public static void main(String[] args) throws Throwable {
|
||||||
|
@ -39,11 +39,13 @@ import java.util.Arrays;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.NavigableMap;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
import java.util.function.UnaryOperator;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.IntStream;
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
@ -54,6 +56,9 @@ import java.util.stream.IntStream;
|
|||||||
@Fork(3)
|
@Fork(3)
|
||||||
@State(Scope.Thread)
|
@State(Scope.Thread)
|
||||||
public class TreeMapUpdate {
|
public class TreeMapUpdate {
|
||||||
|
@Param({"TreeMap", "descendingMap", "tailMap"})
|
||||||
|
public String mode;
|
||||||
|
|
||||||
@Param({"10", "1000", "100000"})
|
@Param({"10", "1000", "100000"})
|
||||||
public int size;
|
public int size;
|
||||||
|
|
||||||
@ -68,10 +73,25 @@ public class TreeMapUpdate {
|
|||||||
|
|
||||||
private Supplier<TreeMap<Integer, Integer>> supplier;
|
private Supplier<TreeMap<Integer, Integer>> supplier;
|
||||||
|
|
||||||
|
private UnaryOperator<NavigableMap<Integer, Integer>> transformer;
|
||||||
|
|
||||||
private Integer[] keys;
|
private Integer[] keys;
|
||||||
|
|
||||||
@Setup
|
@Setup
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
|
switch(mode) {
|
||||||
|
case "TreeMap":
|
||||||
|
transformer = map -> map;
|
||||||
|
break;
|
||||||
|
case "descendingMap":
|
||||||
|
transformer = map -> map.descendingMap();
|
||||||
|
break;
|
||||||
|
case "tailMap":
|
||||||
|
transformer = map -> map.tailMap(0, true);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException(mode);
|
||||||
|
}
|
||||||
supplier = comparator ? () -> new TreeMap<>(Comparator.reverseOrder()) : TreeMap::new;
|
supplier = comparator ? () -> new TreeMap<>(Comparator.reverseOrder()) : TreeMap::new;
|
||||||
keys = IntStream.range(0, size).boxed().toArray(Integer[]::new);
|
keys = IntStream.range(0, size).boxed().toArray(Integer[]::new);
|
||||||
Random rnd = seed == 0 ? new Random() : new Random(seed);
|
Random rnd = seed == 0 ? new Random() : new Random(seed);
|
||||||
@ -86,12 +106,12 @@ public class TreeMapUpdate {
|
|||||||
@Benchmark
|
@Benchmark
|
||||||
public Map<Integer, Integer> baseline() {
|
public Map<Integer, Integer> baseline() {
|
||||||
// Just create map (empty or pre-filled)
|
// Just create map (empty or pre-filled)
|
||||||
return supplier.get();
|
return transformer.apply(supplier.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Benchmark
|
@Benchmark
|
||||||
public Map<Integer, Integer> put(Blackhole bh) {
|
public Map<Integer, Integer> put(Blackhole bh) {
|
||||||
Map<Integer, Integer> map = supplier.get();
|
Map<Integer, Integer> map = transformer.apply(supplier.get());
|
||||||
Integer[] keys = this.keys;
|
Integer[] keys = this.keys;
|
||||||
for (Integer key : keys) {
|
for (Integer key : keys) {
|
||||||
bh.consume(map.put(key, key));
|
bh.consume(map.put(key, key));
|
||||||
@ -101,7 +121,7 @@ public class TreeMapUpdate {
|
|||||||
|
|
||||||
@Benchmark
|
@Benchmark
|
||||||
public Map<Integer, Integer> putIfAbsent(Blackhole bh) {
|
public Map<Integer, Integer> putIfAbsent(Blackhole bh) {
|
||||||
Map<Integer, Integer> map = supplier.get();
|
Map<Integer, Integer> map = transformer.apply(supplier.get());
|
||||||
Integer[] keys = this.keys;
|
Integer[] keys = this.keys;
|
||||||
for (Integer key : keys) {
|
for (Integer key : keys) {
|
||||||
bh.consume(map.putIfAbsent(key, key));
|
bh.consume(map.putIfAbsent(key, key));
|
||||||
@ -111,7 +131,7 @@ public class TreeMapUpdate {
|
|||||||
|
|
||||||
@Benchmark
|
@Benchmark
|
||||||
public Map<Integer, Integer> computeIfAbsent(Blackhole bh) {
|
public Map<Integer, Integer> computeIfAbsent(Blackhole bh) {
|
||||||
Map<Integer, Integer> map = supplier.get();
|
Map<Integer, Integer> map = transformer.apply(supplier.get());
|
||||||
Integer[] keys = this.keys;
|
Integer[] keys = this.keys;
|
||||||
for (Integer key : keys) {
|
for (Integer key : keys) {
|
||||||
bh.consume(map.computeIfAbsent(key, k -> k));
|
bh.consume(map.computeIfAbsent(key, k -> k));
|
||||||
@ -121,7 +141,7 @@ public class TreeMapUpdate {
|
|||||||
|
|
||||||
@Benchmark
|
@Benchmark
|
||||||
public Map<Integer, Integer> compute(Blackhole bh) {
|
public Map<Integer, Integer> compute(Blackhole bh) {
|
||||||
Map<Integer, Integer> map = supplier.get();
|
Map<Integer, Integer> map = transformer.apply(supplier.get());
|
||||||
Integer[] keys = this.keys;
|
Integer[] keys = this.keys;
|
||||||
for (Integer key : keys) {
|
for (Integer key : keys) {
|
||||||
bh.consume(map.compute(key, (k, old) -> k));
|
bh.consume(map.compute(key, (k, old) -> k));
|
||||||
@ -131,7 +151,7 @@ public class TreeMapUpdate {
|
|||||||
|
|
||||||
@Benchmark
|
@Benchmark
|
||||||
public Map<Integer, Integer> computeIfPresent(Blackhole bh) {
|
public Map<Integer, Integer> computeIfPresent(Blackhole bh) {
|
||||||
Map<Integer, Integer> map = supplier.get();
|
Map<Integer, Integer> map = transformer.apply(supplier.get());
|
||||||
Integer[] keys = this.keys;
|
Integer[] keys = this.keys;
|
||||||
for (Integer key : keys) {
|
for (Integer key : keys) {
|
||||||
bh.consume(map.computeIfPresent(key, (k, old) -> k));
|
bh.consume(map.computeIfPresent(key, (k, old) -> k));
|
||||||
@ -141,7 +161,7 @@ public class TreeMapUpdate {
|
|||||||
|
|
||||||
@Benchmark
|
@Benchmark
|
||||||
public Map<Integer, Integer> merge(Blackhole bh) {
|
public Map<Integer, Integer> merge(Blackhole bh) {
|
||||||
Map<Integer, Integer> map = supplier.get();
|
Map<Integer, Integer> map = transformer.apply(supplier.get());
|
||||||
Integer[] keys = this.keys;
|
Integer[] keys = this.keys;
|
||||||
for (Integer key : keys) {
|
for (Integer key : keys) {
|
||||||
bh.consume(map.merge(key, key, (k1, k2) -> k1));
|
bh.consume(map.merge(key, key, (k1, k2) -> k1));
|
||||||
|
Loading…
Reference in New Issue
Block a user