1 /* 2 * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 import java.util.ArrayList; 25 import java.util.Collection; 26 import java.util.HashMap; 27 import java.util.Hashtable; 28 import java.util.IdentityHashMap; 29 import java.util.Iterator; 30 import java.util.LinkedHashMap; 31 import java.util.Map; 32 import java.util.TreeMap; 33 import java.util.WeakHashMap; 34 import java.util.concurrent.ConcurrentHashMap; 35 import java.util.concurrent.ConcurrentSkipListMap; 36 import java.util.function.Supplier; 37 38 import org.testng.annotations.DataProvider; 39 import static org.testng.Assert.assertTrue; 40 import static org.testng.Assert.assertEquals; 41 42 public class MapWithCollisionsProviders { 43 44 private static final int TEST_SIZE 45 = Boolean.valueOf(System.getProperty("test.map.collisions.shortrun")) 46 ? 2500 47 : 5000; 48 49 private static final IntKey EXTRA_INTKEY_VAL 50 = new IntKey(TEST_SIZE, Integer.MAX_VALUE); 51 52 private static final String EXTRA_STRING_VAL = "Extra Value"; 53 54 public static final class IntKey implements Comparable<IntKey> { 55 56 private final int value; 57 private final int hashmask; //yes duplication 58 59 IntKey(int value, int hashmask) { 60 this.value = value; 61 this.hashmask = hashmask; 62 } 63 64 @Override 65 public boolean equals(Object obj) { 66 if (obj instanceof IntKey) { 67 IntKey other = (IntKey) obj; 68 69 return other.value == value; 70 } 71 72 return false; 73 } 74 75 @Override 76 public int hashCode() { 77 return value % hashmask; 78 } 79 80 @Override 81 public int compareTo(IntKey o) { 82 return value - o.value; 83 } 84 85 @Override 86 public String toString() { 87 return Integer.toString(value); 88 } 89 90 public int getValue() { 91 return value; 92 } 93 } 94 95 private static Object[] createUniqueObjectKeys() { 96 IntKey UNIQUE_OBJECTS[] = new IntKey[TEST_SIZE]; 97 for (int i = 0; i < TEST_SIZE; i++) { 98 UNIQUE_OBJECTS[i] = new IntKey(i, Integer.MAX_VALUE); 99 } 100 return UNIQUE_OBJECTS; 101 } 102 103 private static Object[] createUniqueStringKeys() { 104 String UNIQUE_STRINGS[] = new String[TEST_SIZE]; 105 for (int i = 0; i < TEST_SIZE; i++) { 106 UNIQUE_STRINGS[i] = unhash(i); 107 } 108 return UNIQUE_STRINGS; 109 } 110 111 private static Object[] createCollidingObjectKeys() { 112 IntKey COLLIDING_OBJECTS[] = new IntKey[TEST_SIZE]; 113 for (int i = 0; i < TEST_SIZE; i++) { 114 COLLIDING_OBJECTS[i] = new IntKey(i, 10); 115 } 116 return COLLIDING_OBJECTS; 117 } 118 119 private static Object[] createCollidingStringKeys() { 120 String COLLIDING_STRINGS[] = new String[TEST_SIZE]; 121 String UNIQUE_STRINGS[] = new String[TEST_SIZE]; 122 for (int i = 0; i < TEST_SIZE; i++) { 123 UNIQUE_STRINGS[i] = unhash(i); 124 COLLIDING_STRINGS[i] = (0 == i % 2) 125 ? UNIQUE_STRINGS[i / 2] 126 : "\u0000\u0000\u0000\u0000\u0000" + COLLIDING_STRINGS[i - 1]; 127 } 128 return COLLIDING_STRINGS; 129 } 130 131 /** 132 * Returns a string with a hash equal to the argument. 133 * 134 * @return string with a hash equal to the argument. 135 */ 136 private static String unhash(int target) { 137 StringBuilder answer = new StringBuilder(); 138 if (target < 0) { 139 // String with hash of Integer.MIN_VALUE, 0x80000000 140 answer.append("\\u0915\\u0009\\u001e\\u000c\\u0002"); 141 142 if (target == Integer.MIN_VALUE) { 143 return answer.toString(); 144 } 145 // Find target without sign bit set 146 target = target & Integer.MAX_VALUE; 147 } 148 149 unhash0(answer, target); 150 return answer.toString(); 151 } 152 153 private static void unhash0(StringBuilder partial, int target) { 154 int div = target / 31; 155 int rem = target % 31; 156 157 if (div <= Character.MAX_VALUE) { 158 if (div != 0) { 159 partial.append((char) div); 160 } 161 partial.append((char) rem); 162 } else { 163 unhash0(partial, div); 164 partial.append((char) rem); 165 } 166 } 167 168 private static <T> Map<T, T> fillMap(Map<T, T> m, T[] keys) { 169 for (T k : keys) { 170 m.put(k, k); 171 assertTrue(m.containsKey(k)); 172 assertTrue(m.containsValue(k)); 173 } 174 assertEquals(m.size(), keys.length); 175 return m; 176 } 177 178 private static <T> Supplier<Map<T, T>> createMap(Map<T, T> m, T[] keys) { 179 return () -> fillMap(m, keys); 180 } 181 182 private static <T> Object[] createCase(String desc, Map<T, T> m, T[] keys, T val) { 183 return new Object[]{desc, createMap(m, keys), val}; 184 } 185 186 private static <T> Collection<Object[]> makeMapsMoreTypes(String desc, 187 T[] keys, 188 T val) { 189 Collection<Object[]> cases = new ArrayList<>(); 190 cases.add(createCase("Hashtable with " + desc, 191 new Hashtable<>(), keys, val)); 192 cases.add(createCase("IdentityHashMap with " + desc, 193 new IdentityHashMap<>(), keys, val)); 194 cases.add(createCase("TreeMap with " + desc, 195 new TreeMap<>(), keys, val)); 196 cases.add(createCase("WeakHashMap with " + desc, 197 new WeakHashMap<>(), keys, val)); 198 cases.add(createCase("ConcurrentHashMap with " + desc, 199 new ConcurrentHashMap<>(), keys, val)); 200 cases.add(createCase("ConcurrentSkipListMap with " + desc, 201 new ConcurrentSkipListMap<>(), keys, val)); 202 return cases; 203 } 204 205 private static <T> Collection<Object[]> makeMapsHashMap(String desc, 206 T[] keys, 207 T val) { 208 Collection<Object[]> cases = new ArrayList<>(); 209 cases.add(createCase("HashMap with " + desc, 210 new HashMap<>(), keys, val)); 211 cases.add(createCase("LinkedHashMap with " + desc, 212 new LinkedHashMap<>(), keys, val)); 213 return cases; 214 } 215 216 private static <T> Collection<Object[]> makeMaps(String desc, T[] keys, T val) { 217 Collection<Object[]> cases = new ArrayList<>(); 218 cases.addAll(makeMapsHashMap(desc, keys, val)); 219 cases.addAll(makeMapsMoreTypes(desc, keys, val)); 220 return cases; 221 } 222 223 private static <T> Collection<Object[]> makeObjectsCases(String desc, T[] keys) { 224 return makeMaps(desc, keys, EXTRA_INTKEY_VAL); 225 } 226 227 private static <T> Collection<Object[]> makeStringsCases(String desc, 228 T[] keys) { 229 return makeMaps(desc, keys, EXTRA_STRING_VAL); 230 } 231 232 private static final Collection<Object[]> mapsWithObjectsCases 233 = new ArrayList<>() { 234 { 235 addAll(makeObjectsCases("unique objects", createUniqueObjectKeys())); 236 addAll(makeObjectsCases("colliding objects", createCollidingObjectKeys())); 237 } 238 }; 239 240 private static final Collection<Object[]> mapsWithStringsCases 241 = new ArrayList<>() { 242 { 243 addAll(makeStringsCases("unique strings", createUniqueStringKeys())); 244 addAll(makeStringsCases("colliding strings", createCollidingStringKeys())); 245 } 246 }; 247 248 private static final Collection<Object[]> mapsWithObjectsAndStringsCases 249 = new ArrayList<>() { 250 { 251 addAll(mapsWithObjectsCases); 252 addAll(mapsWithStringsCases); 253 } 254 }; 255 256 private static final Collection<Object[]> hashMapsWithObjectsCases 257 = new ArrayList<>() { 258 { 259 addAll(makeMapsHashMap("unique objects", 260 createUniqueObjectKeys(), EXTRA_INTKEY_VAL)); 261 addAll(makeMapsHashMap("collisions objects", 262 createCollidingObjectKeys(), EXTRA_INTKEY_VAL)); 263 } 264 }; 265 266 @DataProvider 267 public Iterator<Object[]> mapsWithObjects() { 268 return mapsWithObjectsCases.iterator(); 269 } 270 271 @DataProvider 272 public Iterator<Object[]> mapsWithStrings() { 273 return mapsWithStringsCases.iterator(); 274 } 275 276 @DataProvider 277 public Iterator<Object[]> mapsWithObjectsAndStrings() { 278 return mapsWithObjectsAndStringsCases.iterator(); 279 } 280 281 @DataProvider 282 public Iterator<Object[]> hashMapsWithObjects() { 283 return hashMapsWithObjectsCases.iterator(); 284 } 285 286 }