/*
* 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;
}
}