Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,13 @@ public BucketSyncMap(final int initialCapacity, final float loadFactor) {
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public BucketSyncMap(final SpreadFunction spreadFunction, final int initialCapacity, final float loadFactor) {
requireNonNull(spreadFunction, "spreadFunction");

if(initialCapacity < 0) throw new IllegalArgumentException("Initial capacity must be non-negative");
if(loadFactor <= 0.0f || !Float.isFinite(loadFactor)) {
throw new IllegalArgumentException("Load factor must be positive and finite");
}

final int capacity = initialCapacity >= BucketSyncMap.MAXIMUM_CAPACITY
? BucketSyncMap.MAXIMUM_CAPACITY
: BucketSyncMap.tableSizeFor(initialCapacity);
Expand Down Expand Up @@ -532,9 +539,8 @@ public boolean containsKey(final Object key) {
}

@Override
public V getOrDefault(final Object key, final V defaultValue) {
public @Nullable V getOrDefault(final Object key, final @Nullable V defaultValue) {
requireNonNull(key, "key");
requireNonNull(defaultValue, "defaultValue");

Node<K, V>@UnknownNullability [] table = this.immutableTable;
int length = table.length;
Expand Down Expand Up @@ -733,7 +739,7 @@ public V getOrDefault(final Object key, final V defaultValue) {
long count = 0L;

Node<K, V>[] immutable;
Node<K, V>@org.jetbrains.annotations.Nullable [] mutable;
Node<K, V>@org.jetbrains.annotations.Nullable [] mutable = null;
int length;
Node<K, V> node;

Expand Down Expand Up @@ -776,10 +782,12 @@ public V getOrDefault(final Object key, final V defaultValue) {
}
}

if(!this.amended || (mutable = this.mutableTable) == null) return null;

final int index;
if((node = BucketSyncMap.getNode(mutable, index = (mutable.length - 1) & hash)) != null) {
if(!this.amended || (mutable == null && (mutable = this.mutableTable) == null) || (node = BucketSyncMap.getNode(mutable, index = (mutable.length - 1) & hash)) == null) {
return null;
} else if(node.hash == BucketSyncMap.NODE_MOVED) {
mutable = this.forward((ForwardingNode<K, V>) node);
} else {
synchronized(node) {
if(BucketSyncMap.getNodePlain(mutable, index) == node) {
for(Node<K, V> previousNode = null; ; ) {
Expand Down Expand Up @@ -1219,7 +1227,7 @@ private void amendNode(final int hash, final K key, final ObjectReference refere
Object previous;

Node<K, V>[] immutable;
Node<K, V>@org.jetbrains.annotations.Nullable [] mutable;
Node<K, V>@org.jetbrains.annotations.Nullable [] mutable = null;
int length;
Node<K, V> node;

Expand Down Expand Up @@ -1257,10 +1265,12 @@ private void amendNode(final int hash, final K key, final ObjectReference refere
}
}

if(!this.amended || (mutable = this.mutableTable) == null) return null;

final int index;
if((node = BucketSyncMap.getNode(mutable, index = (mutable.length - 1) & hash)) != null) {
if(!this.amended || (mutable == null && (mutable = this.mutableTable) == null) || (node = BucketSyncMap.getNode(mutable, index = (mutable.length - 1) & hash)) == null) {
return null;
} else if(node.hash == BucketSyncMap.NODE_MOVED) {
mutable = this.forward((ForwardingNode<K, V>) node);
} else {
synchronized(node) {
if(BucketSyncMap.getNodePlain(mutable, index) == node) {
for(Node<K, V> previousNode = null; ; ) {
Expand Down Expand Up @@ -1308,7 +1318,7 @@ public boolean remove(final Object key, final Object value) {
requireNonNull(value, "value");

Node<K, V>[] immutable;
Node<K, V>@org.jetbrains.annotations.Nullable [] mutable;
Node<K, V>@org.jetbrains.annotations.Nullable [] mutable = null;
int length;
Node<K, V> node;

Expand Down Expand Up @@ -1347,10 +1357,12 @@ public boolean remove(final Object key, final Object value) {
}
}

if(!this.amended || (mutable = this.mutableTable) == null) return false;

final int index;
if((node = BucketSyncMap.getNode(mutable, index = (mutable.length - 1) & hash)) != null) {
if(!this.amended || (mutable == null && (mutable = this.mutableTable) == null) || (node = BucketSyncMap.getNode(mutable, index = (mutable.length - 1) & hash)) == null) {
return false;
} else if(node.hash == BucketSyncMap.NODE_MOVED) {
mutable = this.forward((ForwardingNode<K, V>) node);
} else {
synchronized(node) {
if(BucketSyncMap.getNodePlain(mutable, index) == node) {
for(Node<K, V> previousNode = null; ; ) {
Expand Down Expand Up @@ -1402,7 +1414,7 @@ public boolean remove(final Object key, final Object value) {
Object previous;

Node<K, V>[] immutable;
Node<K, V>@org.jetbrains.annotations.Nullable [] mutable;
Node<K, V>@org.jetbrains.annotations.Nullable [] mutable = null;
int length;
Node<K, V> node;

Expand Down Expand Up @@ -1440,10 +1452,12 @@ public boolean remove(final Object key, final Object value) {
}
}

if(!this.amended || (mutable = this.mutableTable) == null) return null;

final int index;
if((node = BucketSyncMap.getNode(mutable, index = (mutable.length - 1) & hash)) != null) {
if(!this.amended || (mutable == null && (mutable = this.mutableTable) == null) || (node = BucketSyncMap.getNode(mutable, index = (mutable.length - 1) & hash)) == null) {
return null;
} else if(node.hash == BucketSyncMap.NODE_MOVED) {
mutable = this.forward((ForwardingNode<K, V>) node);
} else {
synchronized(node) {
if(BucketSyncMap.getNodePlain(mutable, index) == node) {
for(; ; ) {
Expand Down Expand Up @@ -1485,7 +1499,7 @@ public boolean replace(final K key, final V oldValue, final V newValue) {
Object previous;

Node<K, V>[] immutable;
Node<K, V>@org.jetbrains.annotations.Nullable [] mutable;
Node<K, V>@org.jetbrains.annotations.Nullable [] mutable = null;
int length;
Node<K, V> node;

Expand Down Expand Up @@ -1524,10 +1538,12 @@ public boolean replace(final K key, final V oldValue, final V newValue) {
}
}

if(!this.amended || (mutable = this.mutableTable) == null) return false;

final int index;
if((node = BucketSyncMap.getNode(mutable, index = (mutable.length - 1) & hash)) != null) {
if(!this.amended || (mutable == null && (mutable = this.mutableTable) == null) || (node = BucketSyncMap.getNode(mutable, index = (mutable.length - 1) & hash)) == null) {
return false;
} else if(node.hash == BucketSyncMap.NODE_MOVED) {
mutable = this.forward((ForwardingNode<K, V>) node);
} else {
synchronized(node) {
if(BucketSyncMap.getNodePlain(mutable, index) == node) {
for(; ; ) {
Expand Down Expand Up @@ -1599,7 +1615,7 @@ public void clear() {
final ObjectReference reference = node.referencePlain();
Object current = reference.get();
for(; ; ) {
if(current == null || current == BucketSyncMap.EXPUNGED) continue;
if(current == null || current == BucketSyncMap.EXPUNGED) break;

final Object witness = reference.compareAndExchange(current, null);
if(witness != current) {
Expand Down Expand Up @@ -1749,6 +1765,7 @@ private void resize() {
if(!this.amended
|| (source = this.mutableTable) == null
|| (length = source.length) <= 0
|| length >= BucketSyncMap.MAXIMUM_CAPACITY
|| this.size.sum() < ((long) length * this.loadFactor)) return;

operation = StampLock.operation(state);
Expand Down Expand Up @@ -2319,7 +2336,7 @@ private boolean valueExists() {
}

@SuppressWarnings("unchecked")
private <V> V valueOr(final V defaultValue) {
private <V> @Nullable V valueOr(final @Nullable V defaultValue) {
final Object value;
return ((value = ObjectReference.VALUE.getAcquire(this)) != null && value != BucketSyncMap.EXPUNGED) ? (V) value : defaultValue;
}
Expand Down Expand Up @@ -2493,7 +2510,7 @@ public K getKey() {

@Override
public int hashCode() {
return Objects.hash(this.key, this.value);
return Objects.hashCode(this.key) ^ Objects.hashCode(this.value);
}

@Override
Expand All @@ -2506,7 +2523,7 @@ public boolean equals(final @Nullable Object other) {

@Override
public String toString() {
return "SyncMap.Entry{key=" + this.key + ", value=" + this.value + "}";
return "BucketSyncMap.Entry{key=" + this.key + ", value=" + this.value + "}";
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,6 @@ public void test_getOrDefault_full() {
@Test
public void test_getOrDefault_nullKey() {
final Map<K, V> map = this.createMap();
assertThrows(NullPointerException.class, () -> map.getOrDefault(this.key(3), null), "Map should throw exception when given a null default value.");
assertThrows(NullPointerException.class, () -> map.getOrDefault(null, this.value(3)), "Map should throw exception when given a null key.");
}

Expand Down