Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/test/java/util/Map/InPlaceOpsCollisions.java
38811 views
/*1* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/*24* @test25* @bug 800569826* @run main InPlaceOpsCollisions -shortrun27* @summary Ensure overrides of in-place operations in Maps behave well with lots of collisions.28* @author Brent Christian29*/30import java.util.*;31import java.util.function.*;3233public class InPlaceOpsCollisions {3435/**36* Number of elements per map.37*/38private static final int TEST_SIZE = 5000;3940final static class HashableInteger implements Comparable<HashableInteger> {4142final int value;43final int hashmask; //yes duplication4445HashableInteger(int value, int hashmask) {46this.value = value;47this.hashmask = hashmask;48}4950@Override51public boolean equals(Object obj) {52if (obj instanceof HashableInteger) {53HashableInteger other = (HashableInteger) obj;5455return other.value == value;56}5758return false;59}6061@Override62public int hashCode() {63return value % hashmask;64}6566@Override67public int compareTo(HashableInteger o) {68return value - o.value;69}7071@Override72public String toString() {73return Integer.toString(value);74}75}7677static HashableInteger EXTRA_INT_VAL;78static String EXTRA_STRING_VAL;7980private static Object[][] makeTestData(int size) {81HashableInteger UNIQUE_OBJECTS[] = new HashableInteger[size];82HashableInteger COLLIDING_OBJECTS[] = new HashableInteger[size];83String UNIQUE_STRINGS[] = new String[size];84String COLLIDING_STRINGS[] = new String[size];8586for (int i = 0; i < size; i++) {87UNIQUE_OBJECTS[i] = new HashableInteger(i, Integer.MAX_VALUE);88COLLIDING_OBJECTS[i] = new HashableInteger(i, 10);89UNIQUE_STRINGS[i] = unhash(i);90COLLIDING_STRINGS[i] = (0 == i % 2)91? UNIQUE_STRINGS[i / 2]92: "\u0000\u0000\u0000\u0000\u0000" + COLLIDING_STRINGS[i - 1];93}94EXTRA_INT_VAL = new HashableInteger(size, Integer.MAX_VALUE);95EXTRA_STRING_VAL = new String ("Extra Value");9697return new Object[][] {98new Object[]{"Unique Objects", UNIQUE_OBJECTS},99new Object[]{"Colliding Objects", COLLIDING_OBJECTS},100new Object[]{"Unique Strings", UNIQUE_STRINGS},101new Object[]{"Colliding Strings", COLLIDING_STRINGS}102};103}104105/**106* Returns a string with a hash equal to the argument.107*108* @return string with a hash equal to the argument.109*/110public static String unhash(int target) {111StringBuilder answer = new StringBuilder();112if (target < 0) {113// String with hash of Integer.MIN_VALUE, 0x80000000114answer.append("\\u0915\\u0009\\u001e\\u000c\\u0002");115116if (target == Integer.MIN_VALUE) {117return answer.toString();118}119// Find target without sign bit set120target = target & Integer.MAX_VALUE;121}122123unhash0(answer, target);124return answer.toString();125}126127private static void unhash0(StringBuilder partial, int target) {128int div = target / 31;129int rem = target % 31;130131if (div <= Character.MAX_VALUE) {132if (div != 0) {133partial.append((char) div);134}135partial.append((char) rem);136} else {137unhash0(partial, div);138partial.append((char) rem);139}140}141142private static void realMain(String[] args) throws Throwable {143boolean shortRun = args.length > 0 && args[0].equals("-shortrun");144145Object[][] mapKeys = makeTestData(shortRun ? (TEST_SIZE / 2) : TEST_SIZE);146147// loop through data sets148for (Object[] keys_desc : mapKeys) {149Map<Object, Object>[] maps = (Map<Object, Object>[]) new Map[]{150new HashMap<>(),151new LinkedHashMap<>(),152};153154// for each map type.155for (Map<Object, Object> map : maps) {156String desc = (String) keys_desc[0];157Object[] keys = (Object[]) keys_desc[1];158try {159testInPlaceOps(map, desc, keys);160} catch(Exception all) {161unexpected("Failed for " + map.getClass().getName() + " with " + desc, all);162}163}164}165}166167private static <T> void testInsertion(Map<T, T> map, String keys_desc, T[] keys) {168check("map empty", (map.size() == 0) && map.isEmpty());169170for (int i = 0; i < keys.length; i++) {171check(String.format("insertion: map expected size m%d != i%d", map.size(), i),172map.size() == i);173check(String.format("insertion: put(%s[%d])", keys_desc, i), null == map.put(keys[i], keys[i]));174check(String.format("insertion: containsKey(%s[%d])", keys_desc, i), map.containsKey(keys[i]));175check(String.format("insertion: containsValue(%s[%d])", keys_desc, i), map.containsValue(keys[i]));176}177178check(String.format("map expected size m%d != k%d", map.size(), keys.length),179map.size() == keys.length);180}181182183private static <T> void testInPlaceOps(Map<T, T> map, String keys_desc, T[] keys) {184System.out.println(map.getClass() + " : " + keys_desc + ", testInPlaceOps");185System.out.flush();186187testInsertion(map, keys_desc, keys);188testPutIfAbsent(map, keys_desc, keys);189190map.clear();191testInsertion(map, keys_desc, keys);192testRemoveMapping(map, keys_desc, keys);193194map.clear();195testInsertion(map, keys_desc, keys);196testReplaceOldValue(map, keys_desc, keys);197198map.clear();199testInsertion(map, keys_desc, keys);200testReplaceIfMapped(map, keys_desc, keys);201202map.clear();203testInsertion(map, keys_desc, keys);204testComputeIfAbsent(map, keys_desc, keys, (k) -> getExtraVal(keys[0]));205206map.clear();207testInsertion(map, keys_desc, keys);208testComputeIfAbsent(map, keys_desc, keys, (k) -> null);209210map.clear();211testInsertion(map, keys_desc, keys);212testComputeIfPresent(map, keys_desc, keys, (k, v) -> getExtraVal(keys[0]));213214map.clear();215testInsertion(map, keys_desc, keys);216testComputeIfPresent(map, keys_desc, keys, (k, v) -> null);217218if (!keys_desc.contains("Strings")) { // avoid parseInt() number format error219map.clear();220testInsertion(map, keys_desc, keys);221testComputeNonNull(map, keys_desc, keys);222}223224map.clear();225testInsertion(map, keys_desc, keys);226testComputeNull(map, keys_desc, keys);227228if (!keys_desc.contains("Strings")) { // avoid parseInt() number format error229map.clear();230testInsertion(map, keys_desc, keys);231testMergeNonNull(map, keys_desc, keys);232}233234map.clear();235testInsertion(map, keys_desc, keys);236testMergeNull(map, keys_desc, keys);237}238239240241private static <T> void testPutIfAbsent(Map<T, T> map, String keys_desc, T[] keys) {242T extraVal = getExtraVal(keys[0]);243T retVal;244removeOddKeys(map, keys);245for (int i = 0; i < keys.length; i++) {246retVal = map.putIfAbsent(keys[i], extraVal);247if (i % 2 == 0) { // even: not absent, not put248check(String.format("putIfAbsent: (%s[%d]) retVal", keys_desc, i), retVal == keys[i]);249check(String.format("putIfAbsent: get(%s[%d])", keys_desc, i), keys[i] == map.get(keys[i]));250check(String.format("putIfAbsent: containsValue(%s[%d])", keys_desc, i), map.containsValue(keys[i]));251} else { // odd: absent, was put252check(String.format("putIfAbsent: (%s[%d]) retVal", keys_desc, i), retVal == null);253check(String.format("putIfAbsent: get(%s[%d])", keys_desc, i), extraVal == map.get(keys[i]));254check(String.format("putIfAbsent: !containsValue(%s[%d])", keys_desc, i), !map.containsValue(keys[i]));255}256check(String.format("insertion: containsKey(%s[%d])", keys_desc, i), map.containsKey(keys[i]));257}258check(String.format("map expected size m%d != k%d", map.size(), keys.length),259map.size() == keys.length);260}261262private static <T> void testRemoveMapping(Map<T, T> map, String keys_desc, T[] keys) {263T extraVal = getExtraVal(keys[0]);264boolean removed;265int removes = 0;266remapOddKeys(map, keys);267for (int i = 0; i < keys.length; i++) {268removed = map.remove(keys[i], keys[i]);269if (i % 2 == 0) { // even: original mapping, should be removed270check(String.format("removeMapping: retVal(%s[%d])", keys_desc, i), removed);271check(String.format("removeMapping: get(%s[%d])", keys_desc, i), null == map.get(keys[i]));272check(String.format("removeMapping: !containsKey(%s[%d])", keys_desc, i), !map.containsKey(keys[i]));273check(String.format("removeMapping: !containsValue(%s[%d])", keys_desc, i), !map.containsValue(keys[i]));274removes++;275} else { // odd: new mapping, not removed276check(String.format("removeMapping: retVal(%s[%d])", keys_desc, i), !removed);277check(String.format("removeMapping: get(%s[%d])", keys_desc, i), extraVal == map.get(keys[i]));278check(String.format("removeMapping: containsKey(%s[%d])", keys_desc, i), map.containsKey(keys[i]));279check(String.format("removeMapping: containsValue(%s[%d])", keys_desc, i), map.containsValue(extraVal));280}281}282check(String.format("map expected size m%d != k%d", map.size(), keys.length - removes),283map.size() == keys.length - removes);284}285286private static <T> void testReplaceOldValue(Map<T, T> map, String keys_desc, T[] keys) {287// remap odds to extraVal288// call replace to replace for extraVal, for all keys289// check that all keys map to value from keys array290T extraVal = getExtraVal(keys[0]);291boolean replaced;292remapOddKeys(map, keys);293294for (int i = 0; i < keys.length; i++) {295replaced = map.replace(keys[i], extraVal, keys[i]);296if (i % 2 == 0) { // even: original mapping, should not be replaced297check(String.format("replaceOldValue: retVal(%s[%d])", keys_desc, i), !replaced);298} else { // odd: new mapping, should be replaced299check(String.format("replaceOldValue: get(%s[%d])", keys_desc, i), replaced);300}301check(String.format("replaceOldValue: get(%s[%d])", keys_desc, i), keys[i] == map.get(keys[i]));302check(String.format("replaceOldValue: containsKey(%s[%d])", keys_desc, i), map.containsKey(keys[i]));303check(String.format("replaceOldValue: containsValue(%s[%d])", keys_desc, i), map.containsValue(keys[i]));304// removes++;305}306check(String.format("replaceOldValue: !containsValue(%s[%s])", keys_desc, extraVal.toString()), !map.containsValue(extraVal));307check(String.format("map expected size m%d != k%d", map.size(), keys.length),308map.size() == keys.length);309}310311// TODO: Test case for key mapped to null value312private static <T> void testReplaceIfMapped(Map<T, T> map, String keys_desc, T[] keys) {313// remove odd keys314// call replace for all keys[]315// odd keys should remain absent, even keys should be mapped to EXTRA, no value from keys[] should be in map316T extraVal = getExtraVal(keys[0]);317int expectedSize1 = 0;318removeOddKeys(map, keys);319int expectedSize2 = map.size();320321for (int i = 0; i < keys.length; i++) {322T retVal = map.replace(keys[i], extraVal);323if (i % 2 == 0) { // even: still in map, should be replaced324check(String.format("replaceIfMapped: retVal(%s[%d])", keys_desc, i), retVal == keys[i]);325check(String.format("replaceIfMapped: get(%s[%d])", keys_desc, i), extraVal == map.get(keys[i]));326check(String.format("replaceIfMapped: containsKey(%s[%d])", keys_desc, i), map.containsKey(keys[i]));327expectedSize1++;328} else { // odd: was removed, should not be replaced329check(String.format("replaceIfMapped: retVal(%s[%d])", keys_desc, i), retVal == null);330check(String.format("replaceIfMapped: get(%s[%d])", keys_desc, i), null == map.get(keys[i]));331check(String.format("replaceIfMapped: containsKey(%s[%d])", keys_desc, i), !map.containsKey(keys[i]));332}333check(String.format("replaceIfMapped: !containsValue(%s[%d])", keys_desc, i), !map.containsValue(keys[i]));334}335check(String.format("replaceIfMapped: containsValue(%s[%s])", keys_desc, extraVal.toString()), map.containsValue(extraVal));336check(String.format("map expected size#1 m%d != k%d", map.size(), expectedSize1),337map.size() == expectedSize1);338check(String.format("map expected size#2 m%d != k%d", map.size(), expectedSize2),339map.size() == expectedSize2);340341}342343private static <T> void testComputeIfAbsent(Map<T, T> map, String keys_desc, T[] keys,344Function<T,T> mappingFunction) {345// remove a third of the keys346// call computeIfAbsent for all keys, func returns EXTRA347// check that removed keys now -> EXTRA, other keys -> original val348T expectedVal = mappingFunction.apply(keys[0]);349T retVal;350int expectedSize = 0;351removeThirdKeys(map, keys);352for (int i = 0; i < keys.length; i++) {353retVal = map.computeIfAbsent(keys[i], mappingFunction);354if (i % 3 != 2) { // key present, not computed355check(String.format("computeIfAbsent: (%s[%d]) retVal", keys_desc, i), retVal == keys[i]);356check(String.format("computeIfAbsent: get(%s[%d])", keys_desc, i), keys[i] == map.get(keys[i]));357check(String.format("computeIfAbsent: containsValue(%s[%d])", keys_desc, i), map.containsValue(keys[i]));358check(String.format("insertion: containsKey(%s[%d])", keys_desc, i), map.containsKey(keys[i]));359expectedSize++;360} else { // key absent, computed unless function return null361check(String.format("computeIfAbsent: (%s[%d]) retVal", keys_desc, i), retVal == expectedVal);362check(String.format("computeIfAbsent: get(%s[%d])", keys_desc, i), expectedVal == map.get(keys[i]));363check(String.format("computeIfAbsent: !containsValue(%s[%d])", keys_desc, i), !map.containsValue(keys[i]));364// mapping should not be added if function returns null365check(String.format("insertion: containsKey(%s[%d])", keys_desc, i), map.containsKey(keys[i]) != (expectedVal == null));366if (expectedVal != null) { expectedSize++; }367}368}369if (expectedVal != null) {370check(String.format("computeIfAbsent: containsValue(%s[%s])", keys_desc, expectedVal), map.containsValue(expectedVal));371}372check(String.format("map expected size m%d != k%d", map.size(), expectedSize),373map.size() == expectedSize);374}375376private static <T> void testComputeIfPresent(Map<T, T> map, String keys_desc, T[] keys,377BiFunction<T,T,T> mappingFunction) {378// remove a third of the keys379// call testComputeIfPresent for all keys[]380// removed keys should remain absent, even keys should be mapped to $RESULT381// no value from keys[] should be in map382T funcResult = mappingFunction.apply(keys[0], keys[0]);383int expectedSize1 = 0;384removeThirdKeys(map, keys);385386for (int i = 0; i < keys.length; i++) {387T retVal = map.computeIfPresent(keys[i], mappingFunction);388if (i % 3 != 2) { // key present389if (funcResult == null) { // was removed390check(String.format("replaceIfMapped: containsKey(%s[%d])", keys_desc, i), !map.containsKey(keys[i]));391} else { // value was replaced392check(String.format("replaceIfMapped: containsKey(%s[%d])", keys_desc, i), map.containsKey(keys[i]));393expectedSize1++;394}395check(String.format("computeIfPresent: retVal(%s[%s])", keys_desc, i), retVal == funcResult);396check(String.format("replaceIfMapped: get(%s[%d])", keys_desc, i), funcResult == map.get(keys[i]));397398} else { // odd: was removed, should not be replaced399check(String.format("replaceIfMapped: retVal(%s[%d])", keys_desc, i), retVal == null);400check(String.format("replaceIfMapped: get(%s[%d])", keys_desc, i), null == map.get(keys[i]));401check(String.format("replaceIfMapped: containsKey(%s[%d])", keys_desc, i), !map.containsKey(keys[i]));402}403check(String.format("replaceIfMapped: !containsValue(%s[%d])", keys_desc, i), !map.containsValue(keys[i]));404}405check(String.format("map expected size#1 m%d != k%d", map.size(), expectedSize1),406map.size() == expectedSize1);407}408409private static <T> void testComputeNonNull(Map<T, T> map, String keys_desc, T[] keys) {410// remove a third of the keys411// call compute() for all keys[]412// all keys should be present: removed keys -> EXTRA, others to k-1413BiFunction<T,T,T> mappingFunction = (k, v) -> {414if (v == null) {415return getExtraVal(keys[0]);416} else {417return keys[Integer.parseInt(k.toString()) - 1];418}419};420T extraVal = getExtraVal(keys[0]);421removeThirdKeys(map, keys);422for (int i = 1; i < keys.length; i++) {423T retVal = map.compute(keys[i], mappingFunction);424if (i % 3 != 2) { // key present, should be mapped to k-1425check(String.format("compute: retVal(%s[%d])", keys_desc, i), retVal == keys[i-1]);426check(String.format("compute: get(%s[%d])", keys_desc, i), keys[i-1] == map.get(keys[i]));427} else { // odd: was removed, should be replaced with EXTRA428check(String.format("compute: retVal(%s[%d])", keys_desc, i), retVal == extraVal);429check(String.format("compute: get(%s[%d])", keys_desc, i), extraVal == map.get(keys[i]));430}431check(String.format("compute: containsKey(%s[%d])", keys_desc, i), map.containsKey(keys[i]));432}433check(String.format("map expected size#1 m%d != k%d", map.size(), keys.length),434map.size() == keys.length);435check(String.format("compute: containsValue(%s[%s])", keys_desc, extraVal.toString()), map.containsValue(extraVal));436check(String.format("compute: !containsValue(%s,[null])", keys_desc), !map.containsValue(null));437}438439private static <T> void testComputeNull(Map<T, T> map, String keys_desc, T[] keys) {440// remove a third of the keys441// call compute() for all keys[]442// removed keys should -> EXTRA443// for other keys: func returns null, should have no mapping444BiFunction<T,T,T> mappingFunction = (k, v) -> {445// if absent/null -> EXTRA446// if present -> null447if (v == null) {448return getExtraVal(keys[0]);449} else {450return null;451}452};453T extraVal = getExtraVal(keys[0]);454int expectedSize = 0;455removeThirdKeys(map, keys);456for (int i = 0; i < keys.length; i++) {457T retVal = map.compute(keys[i], mappingFunction);458if (i % 3 != 2) { // key present, func returned null, should be absent from map459check(String.format("compute: retVal(%s[%d])", keys_desc, i), retVal == null);460check(String.format("compute: get(%s[%d])", keys_desc, i), null == map.get(keys[i]));461check(String.format("compute: containsKey(%s[%d])", keys_desc, i), !map.containsKey(keys[i]));462check(String.format("compute: containsValue(%s[%s])", keys_desc, i), !map.containsValue(keys[i]));463} else { // odd: was removed, should now be mapped to EXTRA464check(String.format("compute: retVal(%s[%d])", keys_desc, i), retVal == extraVal);465check(String.format("compute: get(%s[%d])", keys_desc, i), extraVal == map.get(keys[i]));466check(String.format("compute: containsKey(%s[%d])", keys_desc, i), map.containsKey(keys[i]));467expectedSize++;468}469}470check(String.format("compute: containsValue(%s[%s])", keys_desc, extraVal.toString()), map.containsValue(extraVal));471check(String.format("map expected size#1 m%d != k%d", map.size(), expectedSize),472map.size() == expectedSize);473}474475private static <T> void testMergeNonNull(Map<T, T> map, String keys_desc, T[] keys) {476// remove a third of the keys477// call merge() for all keys[]478// all keys should be present: removed keys now -> EXTRA, other keys -> k-1479480// Map to preceding key481BiFunction<T,T,T> mappingFunction = (k, v) -> keys[Integer.parseInt(k.toString()) - 1];482T extraVal = getExtraVal(keys[0]);483removeThirdKeys(map, keys);484for (int i = 1; i < keys.length; i++) {485T retVal = map.merge(keys[i], extraVal, mappingFunction);486if (i % 3 != 2) { // key present, should be mapped to k-1487check(String.format("compute: retVal(%s[%d])", keys_desc, i), retVal == keys[i-1]);488check(String.format("compute: get(%s[%d])", keys_desc, i), keys[i-1] == map.get(keys[i]));489} else { // odd: was removed, should be replaced with EXTRA490check(String.format("compute: retVal(%s[%d])", keys_desc, i), retVal == extraVal);491check(String.format("compute: get(%s[%d])", keys_desc, i), extraVal == map.get(keys[i]));492}493check(String.format("compute: containsKey(%s[%d])", keys_desc, i), map.containsKey(keys[i]));494}495496check(String.format("map expected size#1 m%d != k%d", map.size(), keys.length),497map.size() == keys.length);498check(String.format("compute: containsValue(%s[%s])", keys_desc, extraVal.toString()), map.containsValue(extraVal));499check(String.format("compute: !containsValue(%s,[null])", keys_desc), !map.containsValue(null));500501}502503private static <T> void testMergeNull(Map<T, T> map, String keys_desc, T[] keys) {504// remove a third of the keys505// call merge() for all keys[]506// result: removed keys -> EXTRA, other keys absent507508BiFunction<T,T,T> mappingFunction = (k, v) -> null;509T extraVal = getExtraVal(keys[0]);510int expectedSize = 0;511removeThirdKeys(map, keys);512for (int i = 0; i < keys.length; i++) {513T retVal = map.merge(keys[i], extraVal, mappingFunction);514if (i % 3 != 2) { // key present, func returned null, should be absent from map515check(String.format("compute: retVal(%s[%d])", keys_desc, i), retVal == null);516check(String.format("compute: get(%s[%d])", keys_desc, i), null == map.get(keys[i]));517check(String.format("compute: containsKey(%s[%d])", keys_desc, i), !map.containsKey(keys[i]));518} else { // odd: was removed, should now be mapped to EXTRA519check(String.format("compute: retVal(%s[%d])", keys_desc, i), retVal == extraVal);520check(String.format("compute: get(%s[%d])", keys_desc, i), extraVal == map.get(keys[i]));521check(String.format("compute: containsKey(%s[%d])", keys_desc, i), map.containsKey(keys[i]));522expectedSize++;523}524check(String.format("compute: containsValue(%s[%s])", keys_desc, i), !map.containsValue(keys[i]));525}526check(String.format("compute: containsValue(%s[%s])", keys_desc, extraVal.toString()), map.containsValue(extraVal));527check(String.format("map expected size#1 m%d != k%d", map.size(), expectedSize),528map.size() == expectedSize);529}530531/*532* Return the EXTRA val for the key type being used533*/534private static <T> T getExtraVal(T key) {535if (key instanceof HashableInteger) {536return (T)EXTRA_INT_VAL;537} else {538return (T)EXTRA_STRING_VAL;539}540}541542/*543* Remove half of the keys544*/545private static <T> void removeOddKeys(Map<T, T> map, /*String keys_desc, */ T[] keys) {546int removes = 0;547for (int i = 0; i < keys.length; i++) {548if (i % 2 != 0) {549map.remove(keys[i]);550removes++;551}552}553check(String.format("map expected size m%d != k%d", map.size(), keys.length - removes),554map.size() == keys.length - removes);555}556557/*558* Remove every third key559* This will hopefully leave some removed keys in TreeBins for, e.g., computeIfAbsent560* w/ a func that returns null.561*562* TODO: consider using this in other tests (and maybe adding a remapThirdKeys)563*/564private static <T> void removeThirdKeys(Map<T, T> map, /*String keys_desc, */ T[] keys) {565int removes = 0;566for (int i = 0; i < keys.length; i++) {567if (i % 3 == 2) {568map.remove(keys[i]);569removes++;570}571}572check(String.format("map expected size m%d != k%d", map.size(), keys.length - removes),573map.size() == keys.length - removes);574}575576/*577* Re-map the odd-numbered keys to map to the EXTRA value578*/579private static <T> void remapOddKeys(Map<T, T> map, /*String keys_desc, */ T[] keys) {580T extraVal = getExtraVal(keys[0]);581for (int i = 0; i < keys.length; i++) {582if (i % 2 != 0) {583map.put(keys[i], extraVal);584}585}586}587588//--------------------- Infrastructure ---------------------------589static volatile int passed = 0, failed = 0;590591static void pass() {592passed++;593}594595static void fail() {596failed++;597(new Error("Failure")).printStackTrace(System.err);598}599600static void fail(String msg) {601failed++;602(new Error("Failure: " + msg)).printStackTrace(System.err);603}604605static void abort() {606fail();607System.exit(1);608}609610static void abort(String msg) {611fail(msg);612System.exit(1);613}614615static void unexpected(String msg, Throwable t) {616System.err.println("Unexpected: " + msg);617unexpected(t);618}619620static void unexpected(Throwable t) {621failed++;622t.printStackTrace(System.err);623}624625static void check(boolean cond) {626if (cond) {627pass();628} else {629fail();630}631}632633static void check(String desc, boolean cond) {634if (cond) {635pass();636} else {637fail(desc);638}639}640641static void equal(Object x, Object y) {642if (Objects.equals(x, y)) {643pass();644} else {645fail(x + " not equal to " + y);646}647}648649public static void main(String[] args) throws Throwable {650Thread.currentThread().setName(Collisions.class.getName());651// Thread.currentThread().setPriority(Thread.MAX_PRIORITY);652try {653realMain(args);654} catch (Throwable t) {655unexpected(t);656}657658System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);659if (failed > 0) {660throw new Error("Some tests failed");661}662}663}664665666