Path: blob/master/test/jdk/java/util/IdentityHashMap/Capacity.java
41149 views
/*1* Copyright (c) 2014, 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*/2223import java.lang.reflect.Field;24import java.util.ArrayList;25import java.util.Collections;26import java.util.IdentityHashMap;27import java.util.List;28import java.util.Random;2930import org.testng.annotations.DataProvider;31import org.testng.annotations.Test;3233import static org.testng.Assert.*;3435/*36* @test37* @bug 690436738* @summary IdentityHashMap reallocates storage when inserting expected39* number of elements40* @modules java.base/java.util:open41* @run testng Capacity42* @key randomness43*/4445@Test46public class Capacity {47static final Field tableField;48static final Random random = new Random();49static final Object[][] sizesData;5051@DataProvider(name="sizes", parallel = true)52public Object[][] sizesToTest() { return sizesData; }5354static {55try {56tableField = IdentityHashMap.class.getDeclaredField("table");57tableField.setAccessible(true);58} catch (NoSuchFieldException e) {59throw new LinkageError("table", e);60}6162ArrayList<Object[]> sizes = new ArrayList<>();63for (int size = 0; size < 200; size++)64sizes.add(new Object[] { size });6566// some numbers known to demonstrate bug 690436767for (int size : new int[] {682, 683, 1365, 2730, 2731, 5461})68sizes.add(new Object[] { size });6970// a few more random sizes to try71for (int i = 0; i != 128; i++)72sizes.add(new Object[] { random.nextInt(5000) });7374sizesData = sizes.toArray(new Object[0][]);75}7677static int capacity(IdentityHashMap<?,?> map) {78try {79return ((Object[]) tableField.get(map)).length / 2;80} catch (Throwable t) {81throw new LinkageError("table", t);82}83}8485static void assertCapacity(IdentityHashMap<?,?> map,86int expectedCapacity) {87assertEquals(capacity(map), expectedCapacity);88}8990static void growUsingPut(IdentityHashMap<Object,Object> map,91int elementsToAdd) {92for (int i = 0; i < elementsToAdd; i++)93map.put(new Object(), new Object());94}9596static void growUsingPutAll(IdentityHashMap<Object,Object> map,97int elementsToAdd) {98IdentityHashMap<Object,Object> other = new IdentityHashMap<>();99growUsingPut(other, elementsToAdd);100map.putAll(other);101}102103static void growUsingRepeatedPutAll(IdentityHashMap<Object,Object> map,104int elementsToAdd) {105for (int i = 0; i < elementsToAdd; i++)106map.putAll(Collections.singletonMap(new Object(),107new Object()));108}109110/**111* Checks that expected number of items can be inserted into112* the map without resizing of the internal storage113*/114@Test(dataProvider = "sizes")115public void canInsertExpectedItemsWithoutResizing(int size)116throws Throwable {117// First try growing using put()118IdentityHashMap<Object,Object> m = new IdentityHashMap<>(size);119int initialCapacity = capacity(m);120growUsingPut(m, size);121assertCapacity(m, initialCapacity);122123// Doubling from the expected size will cause exactly one124// resize, except near minimum capacity.125if (size > 1) {126growUsingPut(m, size);127assertCapacity(m, 2 * initialCapacity);128}129130// Try again, growing with putAll()131m = new IdentityHashMap<>(size);132initialCapacity = capacity(m);133growUsingPutAll(m, size);134assertCapacity(m, initialCapacity);135136// Doubling from the expected size will cause exactly one137// resize, except near minimum capacity.138if (size > 1) {139growUsingPutAll(m, size);140assertCapacity(m, 2 * initialCapacity);141}142}143144/**145* Given the expected size, computes such a number N of items that146* inserting (N+1) items will trigger resizing of the internal storage147*/148static int threshold(int size) throws Throwable {149IdentityHashMap<Object,Object> m = new IdentityHashMap<>(size);150int initialCapacity = capacity(m);151while (capacity(m) == initialCapacity)152growUsingPut(m, 1);153return m.size() - 1;154}155156/**157* Checks that inserting (threshold+1) item causes resizing158* of the internal storage159*/160@Test(dataProvider = "sizes")161public void passingThresholdCausesResize(int size) throws Throwable {162final int threshold = threshold(size);163IdentityHashMap<Object,Object> m = new IdentityHashMap<>(threshold);164int initialCapacity = capacity(m);165166growUsingPut(m, threshold);167assertCapacity(m, initialCapacity);168169growUsingPut(m, 1);170assertCapacity(m, 2 * initialCapacity);171}172173/**174* Checks that 4 methods of requiring capacity lead to the same175* internal capacity, unless sized below default capacity.176*/177@Test(dataProvider = "sizes")178public void differentGrowthPatternsResultInSameCapacity(int size)179throws Throwable {180if (size < 21) // 21 is default maxExpectedSize181return;182183IdentityHashMap<Object,Object> m;184m = new IdentityHashMap<Object,Object>(size);185int capacity1 = capacity(m);186187m = new IdentityHashMap<>();188growUsingPut(m, size);189int capacity2 = capacity(m);190191m = new IdentityHashMap<>();192growUsingPutAll(m, size);193int capacity3 = capacity(m);194195m = new IdentityHashMap<>();196growUsingRepeatedPutAll(m, size);197int capacity4 = capacity(m);198199if (capacity1 != capacity2 ||200capacity2 != capacity3 ||201capacity3 != capacity4)202throw new AssertionError("Capacities not equal: "203+ capacity1 + " "204+ capacity2 + " "205+ capacity3 + " "206+ capacity4);207}208209public void defaultExpectedMaxSizeIs21() {210assertCapacity(new IdentityHashMap<Long,Long>(), 32);211assertCapacity(new IdentityHashMap<Long,Long>(21), 32);212}213214public void minimumCapacityIs4() {215assertCapacity(new IdentityHashMap<Long,Long>(0), 4);216assertCapacity(new IdentityHashMap<Long,Long>(1), 4);217assertCapacity(new IdentityHashMap<Long,Long>(2), 4);218assertCapacity(new IdentityHashMap<Long,Long>(3), 8);219}220221@Test(enabled = false)222/** needs too much memory to run normally */223public void maximumCapacityIs2ToThe29() {224assertCapacity(new IdentityHashMap<Long,Long>(Integer.MAX_VALUE),2251 << 29);226}227}228229230