package org.lucares.collections; import java.util.Random; import java.util.stream.LongStream; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; public class LongLongHashMapTest { @Test public void testPutRemove() { putGetRemove(1); } @Test public void testNullValue() { putGetRemove(0); } private void putGetRemove(final long key) { final LongLongHashMap map = new LongLongHashMap(); final long valueA = 2L; final long valueB = 3L; // value does not exist Assertions.assertFalse(map.containsKey(key)); Assertions.assertEquals(0, map.size()); // add value and check it is in the map map.put(key, valueA); Assertions.assertTrue(map.containsKey(key)); Assertions.assertEquals(valueA, map.get(key)); Assertions.assertEquals(1, map.size()); // overwrite value map.put(key, valueB); Assertions.assertEquals(valueB, map.get(key)); Assertions.assertEquals(1, map.size()); // remove value and check it is gone map.remove(key); Assertions.assertFalse(map.containsKey(key)); Assertions.assertEquals(0, map.size()); } @Test public void testComputeZeroKey() { final LongLongHashMap map = new LongLongHashMap(); final long key = 1; map.compute(key, 6, l -> l + 1); Assertions.assertEquals(7, map.get(key), "initialValueIfAbsent is used when there is no mapping for the key"); map.compute(key, 6, l -> l + 1); Assertions.assertEquals(8, map.get(key), "update function is called when 'zeroKey' is set"); } @Test public void testCompute() { final LongLongHashMap map = new LongLongHashMap(); final long key = 1; map.compute(key, 6, l -> l + 1); Assertions.assertEquals(7, map.get(key), "initialValueIfAbsent is used when there is no mapping for the key"); map.compute(key, 6, l -> l + 1); Assertions.assertEquals(8, map.get(key), "update function is called when key is set"); } @Test public void testGrowMap() { final LongLongHashMap map = new LongLongHashMap(4, 0.75); final int numEntries = 12; final Random rand = new Random(12345); final LongList entries = LongList.of(LongStream.generate(rand::nextLong).limit(numEntries).toArray()); entries.stream().forEachOrdered(l -> { map.put(l, l); }); entries.stream().forEachOrdered(l -> { Assertions.assertEquals(l, map.get(l)); }); Assertions.assertEquals(16, map.getCapacity(), "capacity after adding 12 entries must be a the smallest number " + "that satisfies initialCapacity * 2^n >= entries/fillFactor"); } @Test public void testMultipleValuesOnSamePosition() { final int initialCapacity = 20; final LongLongHashMap map = new LongLongHashMap(initialCapacity, 0.75); // find to values that yield the same 'spread' (position in the table) final LongList keysWithSameSpread = findKeysWithSameSpread(map); Assertions.assertTrue(keysWithSameSpread.size() > 5); keysWithSameSpread.stream().forEach(l -> map.put(l, l)); Assertions.assertEquals(keysWithSameSpread.size(), map.size()); keysWithSameSpread.stream().forEach(l -> Assertions.assertEquals(l, map.get(l))); } @Test public void testForEach() { final LongLongHashMap map = new LongLongHashMap(); final Random rand = new Random(6789); final LongList entries = LongList.of(LongStream.generate(rand::nextLong).limit(15).toArray()); entries.stream().forEachOrdered(l -> { map.put(l, 2 * l); }); map.forEach((k, v) -> { Assertions.assertEquals(k * 2, v, "value is key*2"); Assertions.assertTrue(entries.indexOf(k) >= 0, "value " + k + " in entries: " + entries); }); } @Test public void testForEachOrdered() { final LongLongHashMap map = new LongLongHashMap(); final Random rand = new Random(6789); final LongList entries = LongList.of(LongStream.generate(rand::nextLong).limit(15).toArray()); entries.stream().forEachOrdered(l -> { map.put(l, 2 * l); }); final LongList actualOrderOfKeys = new LongList(); map.forEachOrdered((k, v) -> { Assertions.assertEquals(k * 2, v, "value is key*2"); Assertions.assertTrue(entries.indexOf(k) >= 0, "value " + k + " in entries: " + entries); actualOrderOfKeys.add(k); }); Assertions.assertTrue(actualOrderOfKeys.isSorted(), "keys are sorted"); Assertions.assertEquals(LongList.intersection(actualOrderOfKeys, entries).size(), entries.size(), "all keys were visited"); final LongList additionalKeys = new LongList(actualOrderOfKeys); additionalKeys.removeAll(entries); Assertions.assertEquals(additionalKeys, LongList.of(), "no additional keys were visited"); } @Test public void testForEachOrderedOnlyNegativeValues() { final LongLongHashMap map = new LongLongHashMap(); final LongList entries = LongList.of(LongStream.range(-20, -5).toArray()); entries.stream().forEachOrdered(l -> { map.put(l, 2 * l); }); final LongList actualOrderOfKeys = new LongList(); map.forEachOrdered((k, v) -> { Assertions.assertEquals(k * 2, v, "value is key*2"); Assertions.assertTrue(entries.indexOf(k) >= 0, "value " + k + " in entries: " + entries); actualOrderOfKeys.add(k); }); Assertions.assertTrue(actualOrderOfKeys.isSorted(), "keys are sorted"); Assertions.assertEquals(LongList.intersection(actualOrderOfKeys, entries).size(), entries.size(), "all keys were visited"); final LongList additionalKeys = new LongList(actualOrderOfKeys); additionalKeys.removeAll(entries); Assertions.assertEquals(additionalKeys, LongList.of(), "no additional keys were visited"); } @Test public void testForEachOrderedOnlyNegativeValues2() { final LongLongHashMap map = new LongLongHashMap(); final LongList entries = LongList.of(LongStream.range(-20, -5).toArray()); entries.stream().forEachOrdered(l -> { map.put(l, 2 * l); }); final LongList actualOrderOfKeys = new LongList(); map.forEachOrdered((k, v) -> { Assertions.assertEquals(k * 2, v, "value is key*2"); Assertions.assertTrue(entries.indexOf(k) >= 0, "value " + k + " in entries: " + entries); actualOrderOfKeys.add(k); }); Assertions.assertTrue(actualOrderOfKeys.isSorted(), "keys are sorted"); } @Test public void testFindPositionOfFirstPositiveKey() { Assertions.assertEquals(-1, LongLongHashMap.findPosOfFirstPositiveKey(new long[] {})); Assertions.assertEquals(-1, LongLongHashMap.findPosOfFirstPositiveKey(new long[] { 0 })); Assertions.assertEquals(0, LongLongHashMap.findPosOfFirstPositiveKey(new long[] { 1 })); Assertions.assertEquals(1, LongLongHashMap.findPosOfFirstPositiveKey(new long[] { 0, 1 })); Assertions.assertEquals(0, LongLongHashMap.findPosOfFirstPositiveKey(new long[] { 1, 1 })); Assertions.assertEquals(2, LongLongHashMap.findPosOfFirstPositiveKey(new long[] { -1, 0, 1 })); Assertions.assertEquals(0, LongLongHashMap.findPosOfFirstPositiveKey(new long[] { 1, 1, 1, 1, 1, 1, 1, 1, 1 })); Assertions.assertEquals(0, LongLongHashMap.findPosOfFirstPositiveKey(new long[] { 1, 1, 1, 1, 1, 1, 1, 1 })); Assertions.assertEquals(4, LongLongHashMap.findPosOfFirstPositiveKey(new long[] { -1, -1, -1, -1, 1, 1, 1, 1, 1 })); Assertions.assertEquals(4, LongLongHashMap.findPosOfFirstPositiveKey(new long[] { -1, -1, -1, -1, 1, 1, 1, 1 })); Assertions.assertEquals(3, LongLongHashMap.findPosOfFirstPositiveKey(new long[] { -1, -1, -1, 1, 1, 1, 1, 1, 1 })); Assertions.assertEquals(3, LongLongHashMap.findPosOfFirstPositiveKey(new long[] { -1, -1, -1, 1, 1, 1, 1, 1 })); Assertions.assertEquals(-1, LongLongHashMap.findPosOfFirstPositiveKey(new long[] { 0, 0, 0, 0, 0 })); Assertions.assertEquals(-1, LongLongHashMap.findPosOfFirstPositiveKey(new long[] { 0, 0, 0, 0, 0, 0 })); Assertions.assertEquals(4, LongLongHashMap.findPosOfFirstPositiveKey(new long[] { 0, 0, 0, 0, 1, 1, 1, 1 })); Assertions.assertEquals(5, LongLongHashMap.findPosOfFirstPositiveKey(new long[] { 0, 0, 0, 0, 0, 1, 1, 1 })); Assertions.assertEquals(6, LongLongHashMap.findPosOfFirstPositiveKey(new long[] { 0, 0, 0, 0, 0, 0, 1, 1 })); Assertions.assertEquals(4, LongLongHashMap.findPosOfFirstPositiveKey(new long[] { 0, 0, 0, 0, 1, 1, 1 })); Assertions.assertEquals(5, LongLongHashMap.findPosOfFirstPositiveKey(new long[] { 0, 0, 0, 0, 0, 1, 1 })); Assertions.assertEquals(6, LongLongHashMap.findPosOfFirstPositiveKey(new long[] { 0, 0, 0, 0, 0, 0, 1 })); Assertions.assertEquals(4, LongLongHashMap.findPosOfFirstPositiveKey(new long[] { -1, 0, 0, 0, 1, 1, 1 })); Assertions.assertEquals(5, LongLongHashMap.findPosOfFirstPositiveKey(new long[] { -1, 0, 0, 0, 0, 1, 1 })); Assertions.assertEquals(6, LongLongHashMap.findPosOfFirstPositiveKey(new long[] { -1, 0, 0, 0, 0, 0, 1 })); } private LongList findKeysWithSameSpread(final LongLongHashMap map) { final LongList result = new LongList(); final int spread = map.spread(1); result.add(1); for (long l = 2; l < 10000; l++) { final int s = map.spread(l); if (s == spread) { result.add(l); if (result.size() > 10) { break; } } } return result; } }