• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2013, 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 /*
25  * @test
26  * @bug 8005698
27  * @run testng/othervm -Dtest.map.collisions.shortrun=true InPlaceOpsCollisions
28  * @summary Ensure overrides of in-place operations in Maps behave well with lots of collisions.
29  */
30 package test.java.util.Map;
31 
32 import java.util.Map;
33 import java.util.function.BiFunction;
34 import java.util.function.Function;
35 import java.util.function.Supplier;
36 
37 import org.testng.annotations.Test;
38 import static org.testng.Assert.assertTrue;
39 import static org.testng.Assert.assertFalse;
40 import static org.testng.Assert.assertEquals;
41 import static org.testng.Assert.assertNull;
42 
43 import android.platform.test.annotations.LargeTest;
44 
45 @LargeTest
46 public class InPlaceOpsCollisions extends MapWithCollisionsProviders {
47 
48     @Test(dataProvider = "mapsWithObjectsAndStrings")
testPutIfAbsent(String desc, Supplier<Map<Object, Object>> ms, Object val)49     public void testPutIfAbsent(String desc, Supplier<Map<Object, Object>> ms, Object val) {
50         Map<Object, Object> map = ms.get();
51         Object[] keys = map.keySet().toArray();
52         Object retVal;
53         removeOddKeys(map, keys);
54         for (int i = 0; i < keys.length; i++) {
55             retVal = map.putIfAbsent(keys[i], val);
56             if (i % 2 == 0) { // even: not absent, not put
57 
58                 assertEquals(retVal, keys[i],
59                         String.format("putIfAbsent: (%s[%d]) retVal", desc, i));
60                 assertEquals(keys[i], map.get(keys[i]),
61                         String.format("putIfAbsent: get(%s[%d])", desc, i));
62                 assertTrue(map.containsValue(keys[i]),
63                         String.format("putIfAbsent: containsValue(%s[%d])", desc, i));
64             } else { // odd: absent, was put
65                 assertNull(retVal,
66                         String.format("putIfAbsent: (%s[%d]) retVal", desc, i));
67                 assertEquals(val, map.get(keys[i]),
68                         String.format("putIfAbsent: get(%s[%d])", desc, i));
69                 assertFalse(map.containsValue(keys[i]),
70                         String.format("putIfAbsent: !containsValue(%s[%d])", desc, i));
71             }
72             assertTrue(map.containsKey(keys[i]),
73                     String.format("insertion: containsKey(%s[%d])", desc, i));
74         }
75         assertEquals(map.size(), keys.length,
76                 String.format("map expected size m%d != k%d", map.size(), keys.length));
77     }
78 
79     @Test(dataProvider = "mapsWithObjectsAndStrings")
testRemoveMapping(String desc, Supplier<Map<Object, Object>> ms, Object val)80     public void testRemoveMapping(String desc, Supplier<Map<Object, Object>> ms, Object val) {
81         Map<Object, Object> map = ms.get();
82         Object[] keys = map.keySet().toArray();
83         boolean removed;
84         int removes = 0;
85         remapOddKeys(map, keys, val);
86         for (int i = 0; i < keys.length; i++) {
87             removed = map.remove(keys[i], keys[i]);
88             if (i % 2 == 0) { // even: original mapping, should be removed
89                 assertTrue(removed,
90                         String.format("removeMapping: retVal(%s[%d])", desc, i));
91                 assertNull(map.get(keys[i]),
92                         String.format("removeMapping: get(%s[%d])", desc, i));
93                 assertFalse(map.containsKey(keys[i]),
94                         String.format("removeMapping: !containsKey(%s[%d])", desc, i));
95                 assertFalse(map.containsValue(keys[i]),
96                         String.format("removeMapping: !containsValue(%s[%d])", desc, i));
97                 removes++;
98             } else { // odd: new mapping, not removed
99                 assertFalse(removed,
100                         String.format("removeMapping: retVal(%s[%d])", desc, i));
101                 assertEquals(val, map.get(keys[i]),
102                         String.format("removeMapping: get(%s[%d])", desc, i));
103                 assertTrue(map.containsKey(keys[i]),
104                         String.format("removeMapping: containsKey(%s[%d])", desc, i));
105                 assertTrue(map.containsValue(val),
106                         String.format("removeMapping: containsValue(%s[%d])", desc, i));
107             }
108         }
109         assertEquals(map.size(), keys.length - removes,
110                 String.format("map expected size m%d != k%d", map.size(), keys.length - removes));
111     }
112 
113     @Test(dataProvider = "mapsWithObjectsAndStrings")
testReplaceOldValue(String desc, Supplier<Map<Object, Object>> ms, Object val)114     public void testReplaceOldValue(String desc, Supplier<Map<Object, Object>> ms, Object val) {
115         // remap odds to val
116         // call replace to replace for val, for all keys
117         // check that all keys map to value from keys array
118         Map<Object, Object> map = ms.get();
119         Object[] keys = map.keySet().toArray();
120         boolean replaced;
121         remapOddKeys(map, keys, val);
122 
123         for (int i = 0; i < keys.length; i++) {
124             replaced = map.replace(keys[i], val, keys[i]);
125             if (i % 2 == 0) { // even: original mapping, should not be replaced
126                 assertFalse(replaced,
127                         String.format("replaceOldValue: retVal(%s[%d])", desc, i));
128             } else { // odd: new mapping, should be replaced
129                 assertTrue(replaced,
130                         String.format("replaceOldValue: get(%s[%d])", desc, i));
131             }
132             assertEquals(keys[i], map.get(keys[i]),
133                     String.format("replaceOldValue: get(%s[%d])", desc, i));
134             assertTrue(map.containsKey(keys[i]),
135                     String.format("replaceOldValue: containsKey(%s[%d])", desc, i));
136             assertTrue(map.containsValue(keys[i]),
137                     String.format("replaceOldValue: containsValue(%s[%d])", desc, i));
138         }
139         assertFalse(map.containsValue(val),
140                 String.format("replaceOldValue: !containsValue(%s[%s])", desc, val));
141         assertEquals(map.size(), keys.length,
142                 String.format("map expected size m%d != k%d", map.size(), keys.length));
143     }
144 
145     @Test(dataProvider = "mapsWithObjectsAndStrings")
testReplaceIfMapped(String desc, Supplier<Map<Object, Object>> ms, Object val)146     public void testReplaceIfMapped(String desc, Supplier<Map<Object, Object>> ms, Object val) {
147         // remove odd keys
148         // call replace for all keys[]
149         // odd keys should remain absent, even keys should be mapped to EXTRA, no value from keys[] should be in map
150         Map<Object, Object> map = ms.get();
151         Object[] keys = map.keySet().toArray();
152         int expectedSize1 = 0;
153         removeOddKeys(map, keys);
154         int expectedSize2 = map.size();
155 
156         for (int i = 0; i < keys.length; i++) {
157             Object retVal = map.replace(keys[i], val);
158             if (i % 2 == 0) { // even: still in map, should be replaced
159                 assertEquals(retVal, keys[i],
160                         String.format("replaceIfMapped: retVal(%s[%d])", desc, i));
161                 assertEquals(val, map.get(keys[i]),
162                         String.format("replaceIfMapped: get(%s[%d])", desc, i));
163                 assertTrue(map.containsKey(keys[i]),
164                         String.format("replaceIfMapped: containsKey(%s[%d])", desc, i));
165                 expectedSize1++;
166             } else { // odd: was removed, should not be replaced
167                 assertNull(retVal,
168                         String.format("replaceIfMapped: retVal(%s[%d])", desc, i));
169                 assertNull(map.get(keys[i]),
170                         String.format("replaceIfMapped: get(%s[%d])", desc, i));
171                 assertFalse(map.containsKey(keys[i]),
172                         String.format("replaceIfMapped: containsKey(%s[%d])", desc, i));
173             }
174             assertFalse(map.containsValue(keys[i]),
175                     String.format("replaceIfMapped: !containsValue(%s[%d])", desc, i));
176         }
177         assertTrue(map.containsValue(val),
178                 String.format("replaceIfMapped: containsValue(%s[%s])", desc, val));
179         assertEquals(map.size(), expectedSize1,
180                 String.format("map expected size#1 m%d != k%d", map.size(), expectedSize1));
181         assertEquals(map.size(), expectedSize2,
182                 String.format("map expected size#2 m%d != k%d", map.size(), expectedSize2));
183 
184     }
185 
testComputeIfAbsent(Map<T, T> map, String desc, T[] keys, Function<T, T> mappingFunction)186     private static <T> void testComputeIfAbsent(Map<T, T> map, String desc, T[] keys,
187             Function<T, T> mappingFunction) {
188         // remove a third of the keys
189         // call computeIfAbsent for all keys, func returns EXTRA
190         // check that removed keys now -> EXTRA, other keys -> original val
191         T expectedVal = mappingFunction.apply(keys[0]);
192         T retVal;
193         int expectedSize = 0;
194         removeThirdKeys(map, keys);
195         for (int i = 0; i < keys.length; i++) {
196             retVal = map.computeIfAbsent(keys[i], mappingFunction);
197             if (i % 3 != 2) { // key present, not computed
198                 assertEquals(retVal, keys[i],
199                         String.format("computeIfAbsent: (%s[%d]) retVal", desc, i));
200                 assertEquals(keys[i], map.get(keys[i]),
201                         String.format("computeIfAbsent: get(%s[%d])", desc, i));
202                 assertTrue(map.containsValue(keys[i]),
203                         String.format("computeIfAbsent: containsValue(%s[%d])", desc, i));
204                 assertTrue(map.containsKey(keys[i]),
205                         String.format("insertion: containsKey(%s[%d])", desc, i));
206                 expectedSize++;
207             } else { // key absent, computed unless function return null
208                 assertEquals(retVal, expectedVal,
209                         String.format("computeIfAbsent: (%s[%d]) retVal", desc, i));
210                 assertEquals(expectedVal, map.get(keys[i]),
211                         String.format("computeIfAbsent: get(%s[%d])", desc, i));
212                 assertFalse(map.containsValue(keys[i]),
213                         String.format("computeIfAbsent: !containsValue(%s[%d])", desc, i));
214                 // mapping should not be added if function returns null
215                 assertTrue(map.containsKey(keys[i]) != (expectedVal == null),
216                         String.format("insertion: containsKey(%s[%d])", desc, i));
217                 if (expectedVal != null) {
218                     expectedSize++;
219                 }
220             }
221         }
222         if (expectedVal != null) {
223             assertTrue(map.containsValue(expectedVal),
224                     String.format("computeIfAbsent: containsValue(%s[%s])", desc, expectedVal));
225         }
226         assertEquals(map.size(), expectedSize,
227                 String.format("map expected size m%d != k%d", map.size(), expectedSize));
228     }
229 
230     @Test(dataProvider = "mapsWithObjectsAndStrings")
testComputeIfAbsentNonNull(String desc, Supplier<Map<Object, Object>> ms, Object val)231     public void testComputeIfAbsentNonNull(String desc, Supplier<Map<Object, Object>> ms, Object val) {
232         Map<Object, Object> map = ms.get();
233         Object[] keys = map.keySet().toArray();
234         testComputeIfAbsent(map, desc, keys, (k) -> val);
235     }
236 
237     @Test(dataProvider = "mapsWithObjectsAndStrings")
testComputeIfAbsentNull(String desc, Supplier<Map<Object, Object>> ms, Object val)238     public void testComputeIfAbsentNull(String desc, Supplier<Map<Object, Object>> ms, Object val) {
239         Map<Object, Object> map = ms.get();
240         Object[] keys = map.keySet().toArray();
241         testComputeIfAbsent(map, desc, keys, (k) -> null);
242     }
243 
testComputeIfPresent(Map<T, T> map, String desc, T[] keys, BiFunction<T, T, T> mappingFunction)244     private static <T> void testComputeIfPresent(Map<T, T> map, String desc, T[] keys,
245             BiFunction<T, T, T> mappingFunction) {
246         // remove a third of the keys
247         // call testComputeIfPresent for all keys[]
248         // removed keys should remain absent, even keys should be mapped to $RESULT
249         // no value from keys[] should be in map
250         T funcResult = mappingFunction.apply(keys[0], keys[0]);
251         int expectedSize1 = 0;
252         removeThirdKeys(map, keys);
253 
254         for (int i = 0; i < keys.length; i++) {
255             T retVal = map.computeIfPresent(keys[i], mappingFunction);
256             if (i % 3 != 2) { // key present
257                 if (funcResult == null) { // was removed
258                     assertFalse(map.containsKey(keys[i]),
259                             String.format("replaceIfMapped: containsKey(%s[%d])", desc, i));
260                 } else { // value was replaced
261                     assertTrue(map.containsKey(keys[i]),
262                             String.format("replaceIfMapped: containsKey(%s[%d])", desc, i));
263                     expectedSize1++;
264                 }
265                 assertEquals(retVal, funcResult,
266                         String.format("computeIfPresent: retVal(%s[%s])", desc, i));
267                 assertEquals(funcResult, map.get(keys[i]),
268                         String.format("replaceIfMapped: get(%s[%d])", desc, i));
269 
270             } else { // odd: was removed, should not be replaced
271                 assertNull(retVal,
272                         String.format("replaceIfMapped: retVal(%s[%d])", desc, i));
273                 assertNull(map.get(keys[i]),
274                         String.format("replaceIfMapped: get(%s[%d])", desc, i));
275                 assertFalse(map.containsKey(keys[i]),
276                         String.format("replaceIfMapped: containsKey(%s[%d])", desc, i));
277             }
278             assertFalse(map.containsValue(keys[i]),
279                     String.format("replaceIfMapped: !containsValue(%s[%d])", desc, i));
280         }
281         assertEquals(map.size(), expectedSize1,
282                 String.format("map expected size#1 m%d != k%d", map.size(), expectedSize1));
283     }
284 
285     @Test(dataProvider = "mapsWithObjectsAndStrings")
testComputeIfPresentNonNull(String desc, Supplier<Map<Object, Object>> ms, Object val)286     public void testComputeIfPresentNonNull(String desc, Supplier<Map<Object, Object>> ms, Object val) {
287         Map<Object, Object> map = ms.get();
288         Object[] keys = map.keySet().toArray();
289         testComputeIfPresent(map, desc, keys, (k, v) -> val);
290     }
291 
292     @Test(dataProvider = "mapsWithObjectsAndStrings")
testComputeIfPresentNull(String desc, Supplier<Map<Object, Object>> ms, Object val)293     public void testComputeIfPresentNull(String desc, Supplier<Map<Object, Object>> ms, Object val) {
294         Map<Object, Object> map = ms.get();
295         Object[] keys = map.keySet().toArray();
296         testComputeIfPresent(map, desc, keys, (k, v) -> null);
297     }
298 
299     @Test(dataProvider = "hashMapsWithObjects")
testComputeNonNull(String desc, Supplier<Map<IntKey, IntKey>> ms, IntKey val)300     public void testComputeNonNull(String desc, Supplier<Map<IntKey, IntKey>> ms, IntKey val) {
301         // remove a third of the keys
302         // call compute() for all keys[]
303         // all keys should be present: removed keys -> EXTRA, others to k-1
304         Map<IntKey, IntKey> map = ms.get();
305         IntKey[] keys = map.keySet().stream().sorted().toArray(IntKey[]::new);
306         BiFunction<IntKey, IntKey, IntKey> mappingFunction = (k, v) -> {
307             if (v == null) {
308                 return val;
309             } else {
310                 return keys[k.getValue() - 1];
311             }
312         };
313         removeThirdKeys(map, keys);
314         for (int i = 1; i < keys.length; i++) {
315             IntKey retVal = map.compute(keys[i], mappingFunction);
316             if (i % 3 != 2) { // key present, should be mapped to k-1
317                 assertEquals(retVal, keys[i - 1],
318                         String.format("compute: retVal(%s[%d])", desc, i));
319                 assertEquals(keys[i - 1], map.get(keys[i]),
320                         String.format("compute: get(%s[%d])", desc, i));
321             } else { // odd: was removed, should be replaced with EXTRA
322                 assertEquals(retVal, val,
323                         String.format("compute: retVal(%s[%d])", desc, i));
324                 assertEquals(val, map.get(keys[i]),
325                         String.format("compute: get(%s[%d])", desc, i));
326             }
327             assertTrue(map.containsKey(keys[i]),
328                     String.format("compute: containsKey(%s[%d])", desc, i));
329         }
330         assertEquals(map.size(), keys.length,
331                 String.format("map expected size#1 m%d != k%d", map.size(), keys.length));
332         assertTrue(map.containsValue(val),
333                 String.format("compute: containsValue(%s[%s])", desc, val));
334         assertFalse(map.containsValue(null),
335                 String.format("compute: !containsValue(%s,[null])", desc));
336     }
337 
338     @Test(dataProvider = "mapsWithObjectsAndStrings")
testComputeNull(String desc, Supplier<Map<Object, Object>> ms, Object val)339     public void testComputeNull(String desc, Supplier<Map<Object, Object>> ms, Object val) {
340         // remove a third of the keys
341         // call compute() for all keys[]
342         // removed keys should -> EXTRA
343         // for other keys: func returns null, should have no mapping
344         Map<Object, Object> map = ms.get();
345         Object[] keys = map.keySet().toArray();
346         BiFunction<Object, Object, Object> mappingFunction = (k, v) -> {
347             // if absent/null -> EXTRA
348             // if present -> null
349             if (v == null) {
350                 return val;
351             } else {
352                 return null;
353             }
354         };
355         int expectedSize = 0;
356         removeThirdKeys(map, keys);
357         for (int i = 0; i < keys.length; i++) {
358             Object retVal = map.compute(keys[i], mappingFunction);
359             if (i % 3 != 2) { // key present, func returned null, should be absent from map
360                 assertNull(retVal,
361                         String.format("compute: retVal(%s[%d])", desc, i));
362                 assertNull(map.get(keys[i]),
363                         String.format("compute: get(%s[%d])", desc, i));
364                 assertFalse(map.containsKey(keys[i]),
365                         String.format("compute: containsKey(%s[%d])", desc, i));
366                 assertFalse(map.containsValue(keys[i]),
367                         String.format("compute: containsValue(%s[%s])", desc, i));
368             } else { // odd: was removed, should now be mapped to EXTRA
369                 assertEquals(retVal, val,
370                         String.format("compute: retVal(%s[%d])", desc, i));
371                 assertEquals(val, map.get(keys[i]),
372                         String.format("compute: get(%s[%d])", desc, i));
373                 assertTrue(map.containsKey(keys[i]),
374                         String.format("compute: containsKey(%s[%d])", desc, i));
375                 expectedSize++;
376             }
377         }
378         assertTrue(map.containsValue(val),
379                 String.format("compute: containsValue(%s[%s])", desc, val));
380         assertEquals(map.size(), expectedSize,
381                 String.format("map expected size#1 m%d != k%d", map.size(), expectedSize));
382     }
383 
384     @Test(dataProvider = "hashMapsWithObjects")
testMergeNonNull(String desc, Supplier<Map<IntKey, IntKey>> ms, IntKey val)385     public void testMergeNonNull(String desc, Supplier<Map<IntKey, IntKey>> ms, IntKey val) {
386         // remove a third of the keys
387         // call merge() for all keys[]
388         // all keys should be present: removed keys now -> EXTRA, other keys -> k-1
389         Map<IntKey, IntKey> map = ms.get();
390         IntKey[] keys = map.keySet().stream().sorted().toArray(IntKey[]::new);
391 
392         // Map to preceding key
393         BiFunction<IntKey, IntKey, IntKey> mappingFunction
394                 = (k, v) -> keys[k.getValue() - 1];
395         removeThirdKeys(map, keys);
396         for (int i = 1; i < keys.length; i++) {
397             IntKey retVal = map.merge(keys[i], val, mappingFunction);
398             if (i % 3 != 2) { // key present, should be mapped to k-1
399                 assertEquals(retVal, keys[i - 1],
400                         String.format("compute: retVal(%s[%d])", desc, i));
401                 assertEquals(keys[i - 1], map.get(keys[i]),
402                         String.format("compute: get(%s[%d])", desc, i));
403             } else { // odd: was removed, should be replaced with EXTRA
404                 assertEquals(retVal, val,
405                         String.format("compute: retVal(%s[%d])", desc, i));
406                 assertEquals(val, map.get(keys[i]),
407                         String.format("compute: get(%s[%d])", desc, i));
408             }
409             assertTrue(map.containsKey(keys[i]),
410                     String.format("compute: containsKey(%s[%d])", desc, i));
411         }
412 
413         assertEquals(map.size(), keys.length,
414                 String.format("map expected size#1 m%d != k%d", map.size(), keys.length));
415         assertTrue(map.containsValue(val),
416                 String.format("compute: containsValue(%s[%s])", desc, val));
417         assertFalse(map.containsValue(null),
418                 String.format("compute: !containsValue(%s,[null])", desc));
419     }
420 
421     @Test(dataProvider = "mapsWithObjectsAndStrings")
testMergeNull(String desc, Supplier<Map<Object, Object>> ms, Object val)422     public void testMergeNull(String desc, Supplier<Map<Object, Object>> ms, Object val) {
423         // remove a third of the keys
424         // call merge() for all keys[]
425         // result: removed keys -> EXTRA, other keys absent
426 
427         Map<Object, Object> map = ms.get();
428         Object[] keys = map.keySet().toArray();
429         BiFunction<Object, Object, Object> mappingFunction = (k, v) -> null;
430         int expectedSize = 0;
431         removeThirdKeys(map, keys);
432         for (int i = 0; i < keys.length; i++) {
433             Object retVal = map.merge(keys[i], val, mappingFunction);
434             if (i % 3 != 2) { // key present, func returned null, should be absent from map
435                 assertNull(retVal,
436                         String.format("compute: retVal(%s[%d])", desc, i));
437                 assertNull(map.get(keys[i]),
438                         String.format("compute: get(%s[%d])", desc, i));
439                 assertFalse(map.containsKey(keys[i]),
440                         String.format("compute: containsKey(%s[%d])", desc, i));
441             } else { // odd: was removed, should now be mapped to EXTRA
442                 assertEquals(retVal, val,
443                         String.format("compute: retVal(%s[%d])", desc, i));
444                 assertEquals(val, map.get(keys[i]),
445                         String.format("compute: get(%s[%d])", desc, i));
446                 assertTrue(map.containsKey(keys[i]),
447                         String.format("compute: containsKey(%s[%d])", desc, i));
448                 expectedSize++;
449             }
450             assertFalse(map.containsValue(keys[i]),
451                     String.format("compute: containsValue(%s[%s])", desc, i));
452         }
453         assertTrue(map.containsValue(val),
454                 String.format("compute: containsValue(%s[%s])", desc, val));
455         assertEquals(map.size(), expectedSize,
456                 String.format("map expected size#1 m%d != k%d", map.size(), expectedSize));
457     }
458 
459     /*
460      * Remove half of the keys
461      */
removeOddKeys(Map<T, T> map, T[] keys)462     private static <T> void removeOddKeys(Map<T, T> map, /*String keys_desc, */ T[] keys) {
463         int removes = 0;
464         for (int i = 0; i < keys.length; i++) {
465             if (i % 2 != 0) {
466                 map.remove(keys[i]);
467                 removes++;
468             }
469         }
470         assertEquals(map.size(), keys.length - removes,
471                 String.format("map expected size m%d != k%d", map.size(), keys.length - removes));
472     }
473 
474     /*
475      * Remove every third key
476      * This will hopefully leave some removed keys in TreeBins for, e.g., computeIfAbsent
477      * w/ a func that returns null.
478      *
479      * TODO: consider using this in other tests (and maybe adding a remapThirdKeys)
480      */
removeThirdKeys(Map<T, T> map, T[] keys)481     private static <T> void removeThirdKeys(Map<T, T> map, /*String keys_desc, */ T[] keys) {
482         int removes = 0;
483         for (int i = 0; i < keys.length; i++) {
484             if (i % 3 == 2) {
485                 map.remove(keys[i]);
486                 removes++;
487             }
488         }
489         assertEquals(map.size(), keys.length - removes,
490                 String.format("map expected size m%d != k%d", map.size(), keys.length - removes));
491     }
492 
493     /*
494      * Re-map the odd-numbered keys to map to the EXTRA value
495      */
remapOddKeys(Map<T, T> map, T[] keys, T val)496     private static <T> void remapOddKeys(Map<T, T> map, T[] keys, T val) {
497         for (int i = 0; i < keys.length; i++) {
498             if (i % 2 != 0) {
499                 map.put(keys[i], val);
500             }
501         }
502     }
503 
504 }