From d2c7c151bc456ef3095f9f1725fae42a50e24cce Mon Sep 17 00:00:00 2001 From: Speiger Date: Tue, 12 Apr 2022 08:08:17 +0200 Subject: [PATCH] Implemented tests. -Added: ConcurrentHashMap test suite -Fixed: Bugs found in ConcurrentHashMaps with the iterator and clear function. --- .../concurrent/ConcurrentOpenHashMap.template | 46 ++++++++++++------- .../maps/impl/hash/LinkedOpenHashMap.template | 2 +- .../objects/map/ObjectMapTests.java | 2 + 3 files changed, 33 insertions(+), 17 deletions(-) diff --git a/src/builder/resources/speiger/assets/collections/templates/maps/impl/concurrent/ConcurrentOpenHashMap.template b/src/builder/resources/speiger/assets/collections/templates/maps/impl/concurrent/ConcurrentOpenHashMap.template index 3d67c02..ec69e61 100644 --- a/src/builder/resources/speiger/assets/collections/templates/maps/impl/concurrent/ConcurrentOpenHashMap.template +++ b/src/builder/resources/speiger/assets/collections/templates/maps/impl/concurrent/ConcurrentOpenHashMap.template @@ -550,7 +550,7 @@ public class CONCURRENT_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY for(int i = 0,m=segments.length;i Integer.MAX_VALUE ? Integer.MAX_VALUE : 0; + return size > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int)size; } @Override @@ -1288,16 +1288,16 @@ public class CONCURRENT_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY int currentSegment = -1; MapIterator() { - nextSegment = getFirstSegment(); - if(nextSegment != -1) next = segments[nextSegment].firstIndex; + currentSegment = getFirstSegment(); + if(currentSegment != -1) next = segments[currentSegment].firstIndex; } public boolean hasNext() { - return next != -1; + return next != -1 || nextSegment != -1; } public boolean hasPrevious() { - return previous != -1; + return previous != -1 || previousSegment != -1; } public int currentSegment() { @@ -1306,16 +1306,30 @@ public class CONCURRENT_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY public int previousEntry() { if(!hasPrevious()) throw new NoSuchElementException(); - next = current = previous; - nextSegment = currentSegment = previousSegment; + if(previousSegment != -1) { + nextSegment = currentSegment; + currentSegment = previousSegment; + previousSegment = -1; + next = current = segments[currentSegment].lastIndex; + } + else { + next = current = previous; + } findPreviousIndex(); return current; } public int nextEntry() { if(!hasNext()) throw new NoSuchElementException(); - previous = current = next; - previousSegment = currentSegment = nextSegment; + if(nextSegment != -1) { + previousSegment = currentSegment; + currentSegment = nextSegment; + nextSegment = -1; + previous = current = segments[currentSegment].firstIndex; + } + else { + previous = current = next; + } findNextIndex(); return current; } @@ -1328,15 +1342,14 @@ public class CONCURRENT_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY if(current == previous) findPreviousIndex(); else findNextIndex(); seg.size--; - if(previousSegment != currentSegment) seg.firstIndex = next; + if(previous == -1) seg.firstIndex = next; else seg.links[previous] ^= ((seg.links[previous] ^ (next & 0xFFFFFFFFL)) & 0xFFFFFFFFL); - if(nextSegment != currentSegment) seg.lastIndex = previous; + if(next == -1) seg.lastIndex = previous; else seg.links[next] ^= ((seg.links[next] ^ ((previous & 0xFFFFFFFFL) << 32)) & 0xFFFFFFFF00000000L); if(current == seg.nullIndex) { current = -1; - currentSegment = -1; seg.containsNull = false; seg.keys[seg.nullIndex] = EMPTY_KEY_VALUE; seg.values[seg.nullIndex] = EMPTY_VALUE; @@ -1344,7 +1357,6 @@ public class CONCURRENT_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY else { int slot, last, startPos = current; current = -1; - currentSegment = -1; KEY_TYPE current; while(true) { startPos = ((last = startPos) + 1) & seg.mask; @@ -1372,10 +1384,9 @@ public class CONCURRENT_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY } protected void findPreviousIndex() { - previous = (int)(segments[currentSegment].links[current] >> 32); + previous = (int)(segments[currentSegment].links[current] >>> 32); if(previous == -1) { previousSegment = findPreviousSegment(currentSegment-1); - if(previousSegment != -1) previous = segments[previousSegment].lastIndex; } } @@ -1383,7 +1394,6 @@ public class CONCURRENT_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY next = (int)(segments[currentSegment].links[current]); if(next == -1) { nextSegment = findNextSegment(currentSegment+1); - if(nextSegment != -1) next = segments[nextSegment].firstIndex; } } @@ -1926,6 +1936,8 @@ public class CONCURRENT_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY containsNull = false; Arrays.fill(keys, EMPTY_KEY_VALUE); Arrays.fill(values, EMPTY_VALUE); + firstIndex = -1; + lastIndex = -1; } finally { unlock(); @@ -1966,6 +1978,8 @@ public class CONCURRENT_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY values = NEW_VALUE_ARRAY(arraySize); links = new long[arraySize]; this.size = 0; + firstIndex = -1; + lastIndex = -1; containsNull = false; } finally { diff --git a/src/builder/resources/speiger/assets/collections/templates/maps/impl/hash/LinkedOpenHashMap.template b/src/builder/resources/speiger/assets/collections/templates/maps/impl/hash/LinkedOpenHashMap.template index eb31fd9..8245edd 100644 --- a/src/builder/resources/speiger/assets/collections/templates/maps/impl/hash/LinkedOpenHashMap.template +++ b/src/builder/resources/speiger/assets/collections/templates/maps/impl/hash/LinkedOpenHashMap.template @@ -1438,7 +1438,7 @@ public class LINKED_HASH_MAP KEY_VALUE_GENERIC_TYPE extends HASH_MAP KEY_VALUE_G if(previous == -1) firstIndex = next; else links[previous] ^= ((links[previous] ^ (next & 0xFFFFFFFFL)) & 0xFFFFFFFFL); - if (next == -1) lastIndex = previous; + if(next == -1) lastIndex = previous; else links[next] ^= ((links[next] ^ ((previous & 0xFFFFFFFFL) << 32)) & 0xFFFFFFFF00000000L); if(current == nullIndex) { current = -1; diff --git a/src/test/java/speiger/src/collections/objects/map/ObjectMapTests.java b/src/test/java/speiger/src/collections/objects/map/ObjectMapTests.java index e82d859..55a4a79 100644 --- a/src/test/java/speiger/src/collections/objects/map/ObjectMapTests.java +++ b/src/test/java/speiger/src/collections/objects/map/ObjectMapTests.java @@ -20,6 +20,7 @@ import com.google.common.collect.testing.features.MapFeature; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; +import speiger.src.collections.objects.maps.impl.concurrent.Object2ObjectConcurrentOpenHashMap; import speiger.src.collections.objects.maps.impl.customHash.Object2ObjectLinkedOpenCustomHashMap; import speiger.src.collections.objects.maps.impl.customHash.Object2ObjectOpenCustomHashMap; import speiger.src.collections.objects.maps.impl.hash.Object2ObjectLinkedOpenHashMap; @@ -42,6 +43,7 @@ public class ObjectMapTests extends TestCase suite.addTest(suite("LinkedHashMap", Object2ObjectLinkedOpenHashMap::new, true)); suite.addTest(suite("CustomHashMap", () -> new Object2ObjectOpenCustomHashMap<>(Strategy.INSTANCE), true)); suite.addTest(suite("LinkedCustomHashMap", () -> new Object2ObjectLinkedOpenCustomHashMap<>(Strategy.INSTANCE), true)); + suite.addTest(suite("ConcurrentHashMap", Object2ObjectConcurrentOpenHashMap::new, true)); suite.addTest(navigableSuite("RBTreeMap_NonNull", Object2ObjectRBTreeMap::new, false)); suite.addTest(navigableSuite("AVLTreeMap_NonNull", Object2ObjectAVLTreeMap::new, false)); suite.addTest(navigableSuite("RBTreeMap_Null", () -> new Object2ObjectRBTreeMap<>(new NullFriendlyComparator()), true));