/* * Copyright 2015 Goldman Sachs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.gs.collections.impl.map.mutable.primitive; import java.util.Random; import com.gs.collections.api.list.primitive.MutableIntList; import com.gs.collections.api.map.primitive.MutableIntIntMap; import com.gs.collections.api.set.primitive.MutableIntSet; import com.gs.collections.impl.SpreadFunctions; import com.gs.collections.impl.list.mutable.primitive.IntArrayList; import com.gs.collections.impl.set.mutable.primitive.IntHashSet; import org.junit.Assert; import org.junit.Test; public class IntIntMapProbeTest { private static final int SMALL_COLLIDING_KEY_COUNT = 500; private static final int LARGE_COLLIDING_KEY_COUNT = 40000; private int smallMask(int spread) { return spread & ((1 << 11) - 1); } private int largeMask(int spread) { return spread & ((1 << 20) - 1); } @Test public void randomNumbers_get() { MutableIntIntMap intIntSmallNonPresized = new IntIntHashMap(); this.testRandomGet(intIntSmallNonPresized, SMALL_COLLIDING_KEY_COUNT); MutableIntIntMap intIntSmallPresized = new IntIntHashMap(1_000); this.testRandomGet(intIntSmallPresized, SMALL_COLLIDING_KEY_COUNT); MutableIntIntMap intIntLargeNonPresized = new IntIntHashMap(); this.testRandomGet(intIntLargeNonPresized, LARGE_COLLIDING_KEY_COUNT); MutableIntIntMap intIntLargePresized = new IntIntHashMap(1_000_000); this.testRandomGet(intIntLargePresized, LARGE_COLLIDING_KEY_COUNT); } @Test public void nonRandomNumbers_get() { MutableIntIntMap intIntMapSmall = new IntIntHashMap(1_000); int[] intKeysForSmallMap = this.getSmallCollidingNumbers().toArray(); this.testNonRandomGet(intIntMapSmall, SMALL_COLLIDING_KEY_COUNT, intKeysForSmallMap); MutableIntIntMap intIntMapLarge = new IntIntHashMap(1_000_000); int[] intKeysForLargeMap = this.getLargeCollidingNumbers().toArray(); this.testNonRandomGet(intIntMapLarge, LARGE_COLLIDING_KEY_COUNT, intKeysForLargeMap); } @Test public void nonRandomNumbers_remove() { MutableIntIntMap intIntMapSmallNonPresized = new IntIntHashMap(); int[] intKeysForMap = this.getSmallCollidingNumbers().toArray(); this.testNonRandomRemove(intIntMapSmallNonPresized, SMALL_COLLIDING_KEY_COUNT, intKeysForMap); MutableIntIntMap intIntMapSmallPresized = new IntIntHashMap(1_000); int[] intKeysForMap2 = this.getSmallCollidingNumbers().toArray(); this.testNonRandomRemove(intIntMapSmallPresized, SMALL_COLLIDING_KEY_COUNT, intKeysForMap2); MutableIntIntMap intIntMapLargeNonPresized = new IntIntHashMap(); int[] intKeysForMap3 = this.getLargeCollidingNumbers().toArray(); this.testNonRandomRemove(intIntMapLargeNonPresized, LARGE_COLLIDING_KEY_COUNT, intKeysForMap3); MutableIntIntMap intIntMapLargePresized = new IntIntHashMap(1_000_000); int[] intKeysForMap4 = this.getLargeCollidingNumbers().toArray(); this.testNonRandomRemove(intIntMapLargePresized, LARGE_COLLIDING_KEY_COUNT, intKeysForMap4); } @Test public void randomNumbers_remove() { MutableIntIntMap intIntMapSmallNonPresized = new IntIntHashMap(); this.testRandomRemove(intIntMapSmallNonPresized, SMALL_COLLIDING_KEY_COUNT); MutableIntIntMap intIntMapSmallPresized = new IntIntHashMap(1_000); this.testRandomRemove(intIntMapSmallPresized, SMALL_COLLIDING_KEY_COUNT); MutableIntIntMap intIntMapLargeNonPresized = new IntIntHashMap(); this.testRandomRemove(intIntMapLargeNonPresized, LARGE_COLLIDING_KEY_COUNT); MutableIntIntMap intIntMapLargePresized = new IntIntHashMap(1_000_000); this.testRandomRemove(intIntMapLargePresized, LARGE_COLLIDING_KEY_COUNT); } private void testNonRandomGet(MutableIntIntMap intIntMap, int keyCount, int[] intKeysForMap) { Random random = new Random(0x123456789ABCDL); this.shuffle(intKeysForMap, random); for (int i = 0; i < keyCount; i++) { intIntMap.put(intKeysForMap[i], intKeysForMap[i] * 10); } for (int i = 0; i < intIntMap.size(); i++) { Assert.assertEquals((long) (intKeysForMap[i] * 10), intIntMap.get(intKeysForMap[i])); } } private void testRandomGet(MutableIntIntMap intIntMap, int keyCount) { Random random = new Random(0x123456789ABCDL); MutableIntSet set = new IntHashSet(keyCount); while (set.size() < keyCount) { set.add(random.nextInt()); } int[] randomNumbersForMap = set.toArray(); this.shuffle(randomNumbersForMap, random); for (int i = 0; i < keyCount; i++) { intIntMap.put(randomNumbersForMap[i], randomNumbersForMap[i] * 10); } for (int i = 0; i < intIntMap.size(); i++) { Assert.assertEquals((long) (randomNumbersForMap[i] * 10), intIntMap.get(randomNumbersForMap[i])); } } private void testNonRandomRemove(MutableIntIntMap intIntMap, int keyCount, int[] intKeysForMap) { Random random = new Random(0x123456789ABCDL); this.shuffle(intKeysForMap, random); for (int i = 0; i < keyCount; i++) { intIntMap.put(intKeysForMap[i], intKeysForMap[i] * 10); } this.shuffle(intKeysForMap, random); for (int i = 0; i < intKeysForMap.length; i++) { intIntMap.remove(intKeysForMap[i]); for (int j = i + 1; j < intKeysForMap.length; j++) { Assert.assertEquals((long) (intKeysForMap[j] * 10), intIntMap.get(intKeysForMap[j])); } } } private void testRandomRemove(MutableIntIntMap intIntMap, int keyCount) { Random random = new Random(0x123456789ABCDL); MutableIntSet set = new IntHashSet(keyCount); while (set.size() < keyCount) { set.add(random.nextInt()); } int[] intKeysForMap = set.toArray(); this.shuffle(intKeysForMap, random); for (int i = 0; i < keyCount; i++) { intIntMap.put(intKeysForMap[i], intKeysForMap[i] * 10); } this.shuffle(intKeysForMap, random); for (int i = 0; i < intKeysForMap.length; i++) { intIntMap.remove(intKeysForMap[i]); for (int j = i + 1; j < intKeysForMap.length; j++) { Assert.assertEquals((long) (intKeysForMap[j] * 10), intIntMap.get(intKeysForMap[j])); } } } private MutableIntList getSmallCollidingNumbers() { int lower = Integer.MIN_VALUE; int upper = Integer.MAX_VALUE; MutableIntList collidingNumbers = new IntArrayList(); int numberOne = this.smallMask(SpreadFunctions.intSpreadOne(0xABCDEF1)); int numberTwo = this.smallMask(SpreadFunctions.intSpreadTwo(0xABCDEF1)); for (int i = lower; i < upper && collidingNumbers.size() < SMALL_COLLIDING_KEY_COUNT; i++) { if (this.smallMask(SpreadFunctions.intSpreadOne(i)) == numberOne && this.smallMask(SpreadFunctions.intSpreadTwo(i)) == numberTwo) { collidingNumbers.add(i); } } return collidingNumbers; } private MutableIntList getLargeCollidingNumbers() { int lower = Integer.MIN_VALUE; int upper = Integer.MAX_VALUE; int number = 23; MutableIntList collidingNumbers = new IntArrayList(); for (int i = lower; i < upper && collidingNumbers.size() < LARGE_COLLIDING_KEY_COUNT; i++) { int index = this.largeMask(SpreadFunctions.intSpreadOne(i)); if (index >= number && index <= number + 100) { collidingNumbers.add(i); } } return collidingNumbers; } public void shuffle(int[] array, Random rnd) { for (int i = array.length; i > 1; i--) { IntIntMapProbeTest.swap(array, i - 1, rnd.nextInt(i)); } } private static void swap(int[] arr, int i, int j) { int tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; } }