Implemented tests.

-Added: ConcurrentHashMap test suite
-Fixed: Bugs found in ConcurrentHashMaps with the iterator and clear function.
This commit is contained in:
Speiger 2022-04-12 08:08:17 +02:00
parent 4448eca787
commit d2c7c151bc
3 changed files with 33 additions and 17 deletions

View File

@ -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<m;i++) { for(int i = 0,m=segments.length;i<m;i++) {
size += segments[i].size; size += segments[i].size;
} }
return size > Integer.MAX_VALUE ? Integer.MAX_VALUE : 0; return size > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int)size;
} }
@Override @Override
@ -1288,16 +1288,16 @@ public class CONCURRENT_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY
int currentSegment = -1; int currentSegment = -1;
MapIterator() { MapIterator() {
nextSegment = getFirstSegment(); currentSegment = getFirstSegment();
if(nextSegment != -1) next = segments[nextSegment].firstIndex; if(currentSegment != -1) next = segments[currentSegment].firstIndex;
} }
public boolean hasNext() { public boolean hasNext() {
return next != -1; return next != -1 || nextSegment != -1;
} }
public boolean hasPrevious() { public boolean hasPrevious() {
return previous != -1; return previous != -1 || previousSegment != -1;
} }
public int currentSegment() { public int currentSegment() {
@ -1306,16 +1306,30 @@ public class CONCURRENT_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY
public int previousEntry() { public int previousEntry() {
if(!hasPrevious()) throw new NoSuchElementException(); if(!hasPrevious()) throw new NoSuchElementException();
if(previousSegment != -1) {
nextSegment = currentSegment;
currentSegment = previousSegment;
previousSegment = -1;
next = current = segments[currentSegment].lastIndex;
}
else {
next = current = previous; next = current = previous;
nextSegment = currentSegment = previousSegment; }
findPreviousIndex(); findPreviousIndex();
return current; return current;
} }
public int nextEntry() { public int nextEntry() {
if(!hasNext()) throw new NoSuchElementException(); if(!hasNext()) throw new NoSuchElementException();
if(nextSegment != -1) {
previousSegment = currentSegment;
currentSegment = nextSegment;
nextSegment = -1;
previous = current = segments[currentSegment].firstIndex;
}
else {
previous = current = next; previous = current = next;
previousSegment = currentSegment = nextSegment; }
findNextIndex(); findNextIndex();
return current; return current;
} }
@ -1328,15 +1342,14 @@ public class CONCURRENT_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY
if(current == previous) findPreviousIndex(); if(current == previous) findPreviousIndex();
else findNextIndex(); else findNextIndex();
seg.size--; seg.size--;
if(previousSegment != currentSegment) seg.firstIndex = next; if(previous == -1) seg.firstIndex = next;
else seg.links[previous] ^= ((seg.links[previous] ^ (next & 0xFFFFFFFFL)) & 0xFFFFFFFFL); 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); else seg.links[next] ^= ((seg.links[next] ^ ((previous & 0xFFFFFFFFL) << 32)) & 0xFFFFFFFF00000000L);
if(current == seg.nullIndex) { if(current == seg.nullIndex) {
current = -1; current = -1;
currentSegment = -1;
seg.containsNull = false; seg.containsNull = false;
seg.keys[seg.nullIndex] = EMPTY_KEY_VALUE; seg.keys[seg.nullIndex] = EMPTY_KEY_VALUE;
seg.values[seg.nullIndex] = EMPTY_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 { else {
int slot, last, startPos = current; int slot, last, startPos = current;
current = -1; current = -1;
currentSegment = -1;
KEY_TYPE current; KEY_TYPE current;
while(true) { while(true) {
startPos = ((last = startPos) + 1) & seg.mask; 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() { protected void findPreviousIndex() {
previous = (int)(segments[currentSegment].links[current] >> 32); previous = (int)(segments[currentSegment].links[current] >>> 32);
if(previous == -1) { if(previous == -1) {
previousSegment = findPreviousSegment(currentSegment-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]); next = (int)(segments[currentSegment].links[current]);
if(next == -1) { if(next == -1) {
nextSegment = findNextSegment(currentSegment+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; containsNull = false;
Arrays.fill(keys, EMPTY_KEY_VALUE); Arrays.fill(keys, EMPTY_KEY_VALUE);
Arrays.fill(values, EMPTY_VALUE); Arrays.fill(values, EMPTY_VALUE);
firstIndex = -1;
lastIndex = -1;
} }
finally { finally {
unlock(); unlock();
@ -1966,6 +1978,8 @@ public class CONCURRENT_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY
values = NEW_VALUE_ARRAY(arraySize); values = NEW_VALUE_ARRAY(arraySize);
links = new long[arraySize]; links = new long[arraySize];
this.size = 0; this.size = 0;
firstIndex = -1;
lastIndex = -1;
containsNull = false; containsNull = false;
} }
finally { finally {

View File

@ -20,6 +20,7 @@ import com.google.common.collect.testing.features.MapFeature;
import junit.framework.Test; import junit.framework.Test;
import junit.framework.TestCase; import junit.framework.TestCase;
import junit.framework.TestSuite; 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.Object2ObjectLinkedOpenCustomHashMap;
import speiger.src.collections.objects.maps.impl.customHash.Object2ObjectOpenCustomHashMap; import speiger.src.collections.objects.maps.impl.customHash.Object2ObjectOpenCustomHashMap;
import speiger.src.collections.objects.maps.impl.hash.Object2ObjectLinkedOpenHashMap; 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("LinkedHashMap", Object2ObjectLinkedOpenHashMap::new, true));
suite.addTest(suite("CustomHashMap", () -> new Object2ObjectOpenCustomHashMap<>(Strategy.INSTANCE), true)); suite.addTest(suite("CustomHashMap", () -> new Object2ObjectOpenCustomHashMap<>(Strategy.INSTANCE), true));
suite.addTest(suite("LinkedCustomHashMap", () -> new Object2ObjectLinkedOpenCustomHashMap<>(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("RBTreeMap_NonNull", Object2ObjectRBTreeMap::new, false));
suite.addTest(navigableSuite("AVLTreeMap_NonNull", Object2ObjectAVLTreeMap::new, false)); suite.addTest(navigableSuite("AVLTreeMap_NonNull", Object2ObjectAVLTreeMap::new, false));
suite.addTest(navigableSuite("RBTreeMap_Null", () -> new Object2ObjectRBTreeMap<>(new NullFriendlyComparator()), true)); suite.addTest(navigableSuite("RBTreeMap_Null", () -> new Object2ObjectRBTreeMap<>(new NullFriendlyComparator()), true));