Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/test/java/util/Map/Collisions.java
38821 views
/*1* Copyright (c) 2012, 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 712627726* @run main Collisions -shortrun27* @summary Ensure Maps behave well with lots of hashCode() collisions.28* @author Mike Duigou29*/30import java.util.*;31import java.util.concurrent.ConcurrentHashMap;32import java.util.concurrent.ConcurrentSkipListMap;3334public class Collisions {3536/**37* Number of elements per map.38*/39private static final int TEST_SIZE = 5000;4041final static class HashableInteger implements Comparable<HashableInteger> {4243final int value;44final int hashmask; //yes duplication4546HashableInteger(int value, int hashmask) {47this.value = value;48this.hashmask = hashmask;49}5051@Override52public boolean equals(Object obj) {53if (obj instanceof HashableInteger) {54HashableInteger other = (HashableInteger) obj;5556return other.value == value;57}5859return false;60}6162@Override63public int hashCode() {64return value % hashmask;65}6667@Override68public int compareTo(HashableInteger o) {69return value - o.value;70}7172@Override73public String toString() {74return Integer.toString(value);75}76}7778private static Object[][] makeTestData(int size) {79HashableInteger UNIQUE_OBJECTS[] = new HashableInteger[size];80HashableInteger COLLIDING_OBJECTS[] = new HashableInteger[size];81String UNIQUE_STRINGS[] = new String[size];82String COLLIDING_STRINGS[] = new String[size];8384for (int i = 0; i < size; i++) {85UNIQUE_OBJECTS[i] = new HashableInteger(i, Integer.MAX_VALUE);86COLLIDING_OBJECTS[i] = new HashableInteger(i, 10);87UNIQUE_STRINGS[i] = unhash(i);88COLLIDING_STRINGS[i] = (0 == i % 2)89? UNIQUE_STRINGS[i / 2]90: "\u0000\u0000\u0000\u0000\u0000" + COLLIDING_STRINGS[i - 1];91}9293return new Object[][] {94new Object[]{"Unique Objects", UNIQUE_OBJECTS},95new Object[]{"Colliding Objects", COLLIDING_OBJECTS},96new Object[]{"Unique Strings", UNIQUE_STRINGS},97new Object[]{"Colliding Strings", COLLIDING_STRINGS}98};99}100101/**102* Returns a string with a hash equal to the argument.103*104* @return string with a hash equal to the argument.105*/106public static String unhash(int target) {107StringBuilder answer = new StringBuilder();108if (target < 0) {109// String with hash of Integer.MIN_VALUE, 0x80000000110answer.append("\\u0915\\u0009\\u001e\\u000c\\u0002");111112if (target == Integer.MIN_VALUE) {113return answer.toString();114}115// Find target without sign bit set116target = target & Integer.MAX_VALUE;117}118119unhash0(answer, target);120return answer.toString();121}122123private static void unhash0(StringBuilder partial, int target) {124int div = target / 31;125int rem = target % 31;126127if (div <= Character.MAX_VALUE) {128if (div != 0) {129partial.append((char) div);130}131partial.append((char) rem);132} else {133unhash0(partial, div);134partial.append((char) rem);135}136}137138private static void realMain(String[] args) throws Throwable {139boolean shortRun = args.length > 0 && args[0].equals("-shortrun");140141Object[][] mapKeys = makeTestData(shortRun ? (TEST_SIZE / 2) : TEST_SIZE);142143// loop through data sets144for (Object[] keys_desc : mapKeys) {145Map<Object, Object>[] maps = (Map<Object, Object>[]) new Map[]{146new HashMap<>(),147new Hashtable<>(),148new IdentityHashMap<>(),149new LinkedHashMap<>(),150new TreeMap<>(),151new WeakHashMap<>(),152new ConcurrentHashMap<>(),153new ConcurrentSkipListMap<>()154};155156// for each map type.157for (Map<Object, Object> map : maps) {158String desc = (String) keys_desc[0];159Object[] keys = (Object[]) keys_desc[1];160try {161testMap(map, desc, keys);162} catch(Exception all) {163unexpected("Failed for " + map.getClass().getName() + " with " + desc, all);164}165}166}167}168169private static <T> void testMap(Map<T, T> map, String keys_desc, T[] keys) {170System.out.println(map.getClass() + " : " + keys_desc);171System.out.flush();172testInsertion(map, keys_desc, keys);173174if (keys[0] instanceof HashableInteger) {175testIntegerIteration((Map<HashableInteger, HashableInteger>) map, (HashableInteger[]) keys);176} else {177testStringIteration((Map<String, String>) map, (String[]) keys);178}179180testContainsKey(map, keys_desc, keys);181182testRemove(map, keys_desc, keys);183184map.clear();185testInsertion(map, keys_desc, keys);186testKeysIteratorRemove(map, keys_desc, keys);187188map.clear();189testInsertion(map, keys_desc, keys);190testValuesIteratorRemove(map, keys_desc, keys);191192map.clear();193testInsertion(map, keys_desc, keys);194testEntriesIteratorRemove(map, keys_desc, keys);195196check(map.isEmpty());197}198199private static <T> void testInsertion(Map<T, T> map, String keys_desc, T[] keys) {200check("map empty", (map.size() == 0) && map.isEmpty());201202for (int i = 0; i < keys.length; i++) {203check(String.format("insertion: map expected size m%d != i%d", map.size(), i),204map.size() == i);205check(String.format("insertion: put(%s[%d])", keys_desc, i), null == map.put(keys[i], keys[i]));206check(String.format("insertion: containsKey(%s[%d])", keys_desc, i), map.containsKey(keys[i]));207check(String.format("insertion: containsValue(%s[%d])", keys_desc, i), map.containsValue(keys[i]));208}209210check(String.format("map expected size m%d != k%d", map.size(), keys.length),211map.size() == keys.length);212}213214private static void testIntegerIteration(Map<HashableInteger, HashableInteger> map, HashableInteger[] keys) {215check(String.format("map expected size m%d != k%d", map.size(), keys.length),216map.size() == keys.length);217218BitSet all = new BitSet(keys.length);219for (Map.Entry<HashableInteger, HashableInteger> each : map.entrySet()) {220check("Iteration: key already seen", !all.get(each.getKey().value));221all.set(each.getKey().value);222}223224all.flip(0, keys.length);225check("Iteration: some keys not visited", all.isEmpty());226227for (HashableInteger each : map.keySet()) {228check("Iteration: key already seen", !all.get(each.value));229all.set(each.value);230}231232all.flip(0, keys.length);233check("Iteration: some keys not visited", all.isEmpty());234235int count = 0;236for (HashableInteger each : map.values()) {237count++;238}239240check(String.format("Iteration: value count matches size m%d != c%d", map.size(), count),241map.size() == count);242}243244private static void testStringIteration(Map<String, String> map, String[] keys) {245check(String.format("map expected size m%d != k%d", map.size(), keys.length),246map.size() == keys.length);247248BitSet all = new BitSet(keys.length);249for (Map.Entry<String, String> each : map.entrySet()) {250String key = each.getKey();251boolean longKey = key.length() > 5;252int index = key.hashCode() + (longKey ? keys.length / 2 : 0);253check("key already seen", !all.get(index));254all.set(index);255}256257all.flip(0, keys.length);258check("some keys not visited", all.isEmpty());259260for (String each : map.keySet()) {261boolean longKey = each.length() > 5;262int index = each.hashCode() + (longKey ? keys.length / 2 : 0);263check("key already seen", !all.get(index));264all.set(index);265}266267all.flip(0, keys.length);268check("some keys not visited", all.isEmpty());269270int count = 0;271for (String each : map.values()) {272count++;273}274275check(String.format("value count matches size m%d != k%d", map.size(), keys.length),276map.size() == keys.length);277}278279private static <T> void testContainsKey(Map<T, T> map, String keys_desc, T[] keys) {280for (int i = 0; i < keys.length; i++) {281T each = keys[i];282check("containsKey: " + keys_desc + "[" + i + "]" + each, map.containsKey(each));283}284}285286private static <T> void testRemove(Map<T, T> map, String keys_desc, T[] keys) {287check(String.format("remove: map expected size m%d != k%d", map.size(), keys.length),288map.size() == keys.length);289290for (int i = 0; i < keys.length; i++) {291T each = keys[i];292check("remove: " + keys_desc + "[" + i + "]" + each, null != map.remove(each));293}294295check(String.format("remove: map empty. size=%d", map.size()),296(map.size() == 0) && map.isEmpty());297}298299private static <T> void testKeysIteratorRemove(Map<T, T> map, String keys_desc, T[] keys) {300check(String.format("remove: map expected size m%d != k%d", map.size(), keys.length),301map.size() == keys.length);302303Iterator<T> each = map.keySet().iterator();304while (each.hasNext()) {305T t = each.next();306each.remove();307check("not removed: " + each, !map.containsKey(t) );308}309310check(String.format("remove: map empty. size=%d", map.size()),311(map.size() == 0) && map.isEmpty());312}313314private static <T> void testValuesIteratorRemove(Map<T, T> map, String keys_desc, T[] keys) {315check(String.format("remove: map expected size m%d != k%d", map.size(), keys.length),316map.size() == keys.length);317318Iterator<T> each = map.values().iterator();319while (each.hasNext()) {320T t = each.next();321each.remove();322check("not removed: " + each, !map.containsValue(t) );323}324325check(String.format("remove: map empty. size=%d", map.size()),326(map.size() == 0) && map.isEmpty());327}328329private static <T> void testEntriesIteratorRemove(Map<T, T> map, String keys_desc, T[] keys) {330check(String.format("remove: map expected size m%d != k%d", map.size(), keys.length),331map.size() == keys.length);332333Iterator<Map.Entry<T,T>> each = map.entrySet().iterator();334while (each.hasNext()) {335Map.Entry<T,T> t = each.next();336T key = t.getKey();337T value = t.getValue();338each.remove();339check("not removed: " + each, (map instanceof IdentityHashMap) || !map.entrySet().contains(t) );340check("not removed: " + each, !map.containsKey(key) );341check("not removed: " + each, !map.containsValue(value));342}343344check(String.format("remove: map empty. size=%d", map.size()),345(map.size() == 0) && map.isEmpty());346}347348//--------------------- Infrastructure ---------------------------349static volatile int passed = 0, failed = 0;350351static void pass() {352passed++;353}354355static void fail() {356failed++;357(new Error("Failure")).printStackTrace(System.err);358}359360static void fail(String msg) {361failed++;362(new Error("Failure: " + msg)).printStackTrace(System.err);363}364365static void abort() {366fail();367System.exit(1);368}369370static void abort(String msg) {371fail(msg);372System.exit(1);373}374375static void unexpected(String msg, Throwable t) {376System.err.println("Unexpected: " + msg);377unexpected(t);378}379380static void unexpected(Throwable t) {381failed++;382t.printStackTrace(System.err);383}384385static void check(boolean cond) {386if (cond) {387pass();388} else {389fail();390}391}392393static void check(String desc, boolean cond) {394if (cond) {395pass();396} else {397fail(desc);398}399}400401static void equal(Object x, Object y) {402if (Objects.equals(x, y)) {403pass();404} else {405fail(x + " not equal to " + y);406}407}408409public static void main(String[] args) throws Throwable {410Thread.currentThread().setName(Collisions.class.getName());411// Thread.currentThread().setPriority(Thread.MAX_PRIORITY);412try {413realMain(args);414} catch (Throwable t) {415unexpected(t);416}417418System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);419if (failed > 0) {420throw new Error("Some tests failed");421}422}423}424425426