Skip to content

Commit 9ace126

Browse files
committed
IntLongMap
1 parent 1dc4860 commit 9ace126

File tree

6 files changed

+508
-0
lines changed

6 files changed

+508
-0
lines changed
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
package com.trivago.fastutilconcurrentwrapper.intkey;
2+
3+
import it.unimi.dsi.fastutil.ints.Int2LongFunction;
4+
5+
import java.util.concurrent.locks.Lock;
6+
import java.util.function.BiFunction;
7+
8+
public class ConcurrentBusyWaitingIntLongMap extends ConcurrentIntLongMap {
9+
public ConcurrentBusyWaitingIntLongMap (
10+
int numBuckets,
11+
int initialCapacity,
12+
float loadFactor,
13+
long defaultValue
14+
){
15+
super(numBuckets, initialCapacity, loadFactor, defaultValue);
16+
}
17+
18+
@Override
19+
public boolean containsKey (int key) {
20+
int bucket = getBucket(key);
21+
Lock readLock = readLock(bucket);
22+
23+
while (true){
24+
if (readLock.tryLock()){
25+
try {
26+
return maps[bucket].containsKey(key);
27+
} finally {
28+
readLock.unlock();
29+
}
30+
}
31+
Thread.onSpinWait();
32+
}
33+
}
34+
35+
@Override
36+
public long get (int intKey) {
37+
int bucket = getBucket(intKey);
38+
Lock readLock = readLock(bucket);
39+
40+
while (true){
41+
if (readLock.tryLock()){
42+
try {
43+
return maps[bucket].getOrDefault(intKey, defaultValue);
44+
} finally {
45+
readLock.unlock();
46+
}
47+
}
48+
Thread.onSpinWait();
49+
}
50+
}
51+
52+
@Override
53+
public long put (int key, long value) {
54+
int bucket = getBucket(key);
55+
Lock writeLock = writeLock(bucket);
56+
57+
while (true){
58+
if (writeLock.tryLock()){
59+
try {
60+
return maps[bucket].put(key, value);
61+
} finally {
62+
writeLock.unlock();
63+
}
64+
}
65+
Thread.onSpinWait();
66+
}
67+
}
68+
69+
@Override
70+
public long remove (int key) {
71+
int bucket = getBucket(key);
72+
Lock writeLock = writeLock(bucket);
73+
74+
while (true){
75+
if (writeLock.tryLock()){
76+
try {
77+
return maps[bucket].remove(key);
78+
} finally {
79+
writeLock.unlock();
80+
}
81+
}
82+
Thread.onSpinWait();
83+
}
84+
}
85+
86+
@Override
87+
public boolean remove (int key, long value) {
88+
int bucket = getBucket(key);
89+
Lock writeLock = writeLock(bucket);
90+
91+
while (true){
92+
if (writeLock.tryLock()){
93+
try {
94+
return maps[bucket].remove(key, value);
95+
} finally {
96+
writeLock.unlock();
97+
}
98+
}
99+
Thread.onSpinWait();
100+
}
101+
}
102+
103+
@Override
104+
public long computeIfAbsent (int key, Int2LongFunction mappingFunction) {
105+
int bucket = getBucket(key);
106+
Lock writeLock = writeLock(bucket);
107+
108+
while (true){
109+
if (writeLock.tryLock()){
110+
try {
111+
return maps[bucket].computeIfAbsent(key, mappingFunction);
112+
} finally {
113+
writeLock.unlock();
114+
}
115+
}
116+
Thread.onSpinWait();
117+
}
118+
}
119+
120+
@Override
121+
public long computeIfPresent(int key, BiFunction<Integer, Long, Long> mappingFunction) {
122+
int bucket = getBucket(key);
123+
Lock writeLock = writeLock(bucket);
124+
125+
while (true){
126+
if (writeLock.tryLock()){
127+
try {
128+
return maps[bucket].computeIfPresent(key, mappingFunction);
129+
} finally {
130+
writeLock.unlock();
131+
}
132+
}
133+
Thread.onSpinWait();
134+
}
135+
}
136+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package com.trivago.fastutilconcurrentwrapper.intkey;
2+
3+
import com.trivago.fastutilconcurrentwrapper.PrimitiveConcurrentMap;
4+
import com.trivago.fastutilconcurrentwrapper.PrimitiveMapBuilder;
5+
import it.unimi.dsi.fastutil.ints.Int2LongFunction;
6+
import it.unimi.dsi.fastutil.ints.Int2LongOpenHashMap;
7+
8+
import java.util.function.BiFunction;
9+
10+
public class ConcurrentIntLongMap extends PrimitiveConcurrentMap<Integer,Long> {
11+
protected final Int2LongOpenHashMap[] maps;
12+
protected final long defaultValue;
13+
14+
public ConcurrentIntLongMap (
15+
int numBuckets,
16+
int initialCapacity,
17+
float loadFactor,
18+
long defaultValue
19+
){
20+
super(numBuckets);
21+
22+
this.maps = new Int2LongOpenHashMap[numBuckets];
23+
this.defaultValue = defaultValue;
24+
for (int i = 0; i < numBuckets; i++)
25+
maps[i] = new Int2LongOpenHashMap(initialCapacity, loadFactor);
26+
}
27+
28+
@Override protected Int2LongOpenHashMap mapAt (int index){ return maps[index]; }
29+
30+
public boolean containsKey (int key) {
31+
int bucket = getBucket(key);
32+
try (var __ = readAt(bucket)){
33+
return maps[bucket].containsKey(key);
34+
}
35+
}
36+
37+
public long get (int intKey) {
38+
int bucket = getBucket(intKey);
39+
try (var __ = readAt(bucket)){
40+
return maps[bucket].getOrDefault(intKey, defaultValue);
41+
}
42+
}
43+
44+
public long put (int intKey, long value) {
45+
int bucket = getBucket(intKey);
46+
try (var __ = writeAt(bucket)){
47+
return maps[bucket].put(intKey, value);
48+
}
49+
}
50+
51+
public long getDefaultValue (){ return defaultValue; }
52+
53+
public long remove (int intKey) {
54+
int bucket = getBucket(intKey);
55+
try (var __ = writeAt(bucket)){
56+
return maps[bucket].remove(intKey);
57+
}
58+
}
59+
60+
public boolean remove (int key, long value) {
61+
int bucket = getBucket(key);
62+
try (var __ = writeAt(bucket)){
63+
return maps[bucket].remove(key, value);
64+
}
65+
}
66+
67+
public long computeIfAbsent (int key, Int2LongFunction mappingFunction) {
68+
int bucket = getBucket(key);
69+
try (var __ = writeAt(bucket)){
70+
return maps[bucket].computeIfAbsent(key, mappingFunction);
71+
}
72+
}
73+
74+
public long computeIfPresent(int key, BiFunction<Integer, Long, Long> mappingFunction) {
75+
int bucket = getBucket(key);
76+
try (var __ = writeAt(bucket)){
77+
return maps[bucket].computeIfPresent(key, mappingFunction);
78+
}
79+
}
80+
81+
public static PrimitiveMapBuilder<ConcurrentIntLongMap,Long> newBuilder () {
82+
return new PrimitiveMapBuilder<>(){
83+
@Override
84+
public ConcurrentIntLongMap build () {
85+
long def = super.defaultValue != null ? super.defaultValue : 0;
86+
return switch (mapMode){
87+
case BUSY_WAITING -> new ConcurrentBusyWaitingIntLongMap(buckets, initialCapacity, loadFactor, def);
88+
case BLOCKING -> new ConcurrentIntLongMap(buckets, initialCapacity, loadFactor, def);
89+
};
90+
}
91+
};
92+
}
93+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package com.trivago.fastutilconcurrentwrapper;
2+
3+
import com.trivago.fastutilconcurrentwrapper.intkey.ConcurrentBusyWaitingIntLongMap;
4+
import com.trivago.fastutilconcurrentwrapper.intkey.ConcurrentIntLongMap;
5+
import lombok.val;
6+
import org.junit.jupiter.api.Test;
7+
8+
import static org.junit.jupiter.api.Assertions.*;
9+
10+
public class ConcurrentIntLongMapBuilderTest {
11+
private static final long DEFAULT_VALUE = -1L;
12+
13+
@Test
14+
public void simpleBuilderTest() {
15+
val b = ConcurrentIntLongMap.newBuilder()
16+
.withBuckets(2)
17+
.withDefaultValue(DEFAULT_VALUE)
18+
.withInitialCapacity(100)
19+
.withMode(PrimitiveMapBuilder.MapMode.BUSY_WAITING)
20+
.withLoadFactor(0.9f);
21+
22+
val map = (ConcurrentBusyWaitingIntLongMap) b.build();
23+
24+
map.put(1, 10L);
25+
long v = map.get(1);
26+
27+
assertInstanceOf(ConcurrentBusyWaitingIntLongMap.class, map);
28+
assertEquals(10L, v);
29+
assertEquals(map.get(2), map.getDefaultValue());
30+
}
31+
32+
@Test
33+
public void buildsBlockingMap() {
34+
val b = ConcurrentIntLongMap.newBuilder()
35+
.withBuckets(2)
36+
.withDefaultValue(DEFAULT_VALUE)
37+
.withInitialCapacity(100)
38+
.withMode(PrimitiveMapBuilder.MapMode.BLOCKING)
39+
.withLoadFactor(0.9f);
40+
41+
ConcurrentIntLongMap map = b.build();
42+
43+
map.put(1, 10L);
44+
long v = map.get(1);
45+
46+
assertInstanceOf(ConcurrentIntLongMap.class, map);
47+
assertEquals(10L, v);
48+
assertEquals(-1, map.getDefaultValue());
49+
assertEquals(-1, map.get(2));
50+
assertEquals(map.get(2), map.getDefaultValue());
51+
}
52+
}

0 commit comments

Comments
 (0)