-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
1 parent
a665d67
commit fee9de5
Showing
5 changed files
with
491 additions
and
0 deletions.
There are no files selected for viewing
76 changes: 76 additions & 0 deletions
76
src/main/java/com/trivago/fastutilconcurrentwrapper/ConcurrentLongIntMapBuilder.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
package com.trivago.fastutilconcurrentwrapper; | ||
|
||
import com.trivago.fastutilconcurrentwrapper.map.ConcurrentBusyWaitingLongIntMap; | ||
import com.trivago.fastutilconcurrentwrapper.map.ConcurrentBusyWaitingLongLongMap; | ||
import com.trivago.fastutilconcurrentwrapper.map.ConcurrentLongIntMap; | ||
import com.trivago.fastutilconcurrentwrapper.map.ConcurrentLongLongMap; | ||
|
||
public final class ConcurrentLongIntMapBuilder { | ||
private MapMode mapMode = MapMode.BLOCKING; | ||
private int buckets = 8; | ||
private int initialCapacity = 100_000; | ||
private float loadFactor = 0.8f; | ||
private int defaultValue = LongIntMap.DEFAULT_VALUE; | ||
|
||
private ConcurrentLongIntMapBuilder() { | ||
|
||
} | ||
|
||
public static ConcurrentLongIntMapBuilder newBuilder() { | ||
return new ConcurrentLongIntMapBuilder(); | ||
} | ||
|
||
public ConcurrentLongIntMapBuilder withBuckets(int buckets) { | ||
this.buckets = buckets; | ||
return this; | ||
} | ||
|
||
public ConcurrentLongIntMapBuilder withInitialCapacity(int initialCapacity) { | ||
this.initialCapacity = initialCapacity; | ||
return this; | ||
} | ||
|
||
public ConcurrentLongIntMapBuilder withLoadFactor(float loadFactor) { | ||
this.loadFactor = loadFactor; | ||
return this; | ||
} | ||
|
||
public ConcurrentLongIntMapBuilder withMode(MapMode mapMode) { | ||
this.mapMode = mapMode; | ||
return this; | ||
} | ||
|
||
public ConcurrentLongIntMapBuilder withDefaultValue(int defaultValue) { | ||
this.defaultValue = defaultValue; | ||
return this; | ||
} | ||
|
||
public LongIntMap build() { | ||
return mapMode.createMap(this); | ||
} | ||
|
||
public enum MapMode { | ||
BUSY_WAITING { | ||
@Override | ||
LongIntMap createMap(ConcurrentLongIntMapBuilder builder) { | ||
return new ConcurrentBusyWaitingLongIntMap( | ||
builder.buckets, | ||
builder.initialCapacity, | ||
builder.loadFactor, | ||
builder.defaultValue); | ||
} | ||
}, | ||
BLOCKING { | ||
@Override | ||
LongIntMap createMap(ConcurrentLongIntMapBuilder builder) { | ||
return new ConcurrentLongIntMap( | ||
builder.buckets, | ||
builder.initialCapacity, | ||
builder.loadFactor, | ||
builder.defaultValue); | ||
} | ||
}; | ||
|
||
abstract LongIntMap createMap(ConcurrentLongIntMapBuilder builder); | ||
} | ||
} |
29 changes: 29 additions & 0 deletions
29
src/main/java/com/trivago/fastutilconcurrentwrapper/LongIntMap.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package com.trivago.fastutilconcurrentwrapper; | ||
|
||
import it.unimi.dsi.fastutil.ints.Int2LongFunction; | ||
import it.unimi.dsi.fastutil.longs.Long2IntFunction; | ||
|
||
import java.util.function.BiFunction; | ||
|
||
public interface LongIntMap extends PrimitiveLongKeyMap { | ||
|
||
int DEFAULT_VALUE = 0; | ||
|
||
/** | ||
* @param key key to get | ||
* @return 0 if the key is not present | ||
*/ | ||
int get(long key); | ||
|
||
int put(long key, int value); | ||
|
||
int getDefaultValue(); | ||
|
||
int remove(long key); | ||
|
||
boolean remove(long key, int value); | ||
|
||
int computeIfAbsent(long key, Long2IntFunction mappingFunction); | ||
|
||
int computeIfPresent(long key, BiFunction<Long, Integer, Integer> mappingFunction); | ||
} |
165 changes: 165 additions & 0 deletions
165
src/main/java/com/trivago/fastutilconcurrentwrapper/map/ConcurrentBusyWaitingLongIntMap.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
package com.trivago.fastutilconcurrentwrapper.map; | ||
|
||
import com.trivago.fastutilconcurrentwrapper.LongIntMap; | ||
import com.trivago.fastutilconcurrentwrapper.LongLongMap; | ||
import com.trivago.fastutilconcurrentwrapper.wrapper.PrimitiveFastutilLongIntWrapper; | ||
import com.trivago.fastutilconcurrentwrapper.wrapper.PrimitiveFastutilLongLongWrapper; | ||
import it.unimi.dsi.fastutil.longs.Long2IntFunction; | ||
import it.unimi.dsi.fastutil.longs.Long2LongFunction; | ||
|
||
import java.util.concurrent.locks.Lock; | ||
import java.util.function.BiFunction; | ||
|
||
public class ConcurrentBusyWaitingLongIntMap extends PrimitiveConcurrentMap implements LongIntMap { | ||
|
||
private final LongIntMap[] maps; | ||
private final int defaultValue; | ||
|
||
public ConcurrentBusyWaitingLongIntMap(int numBuckets, | ||
int initialCapacity, | ||
float loadFactor, | ||
int defaultValue) { | ||
super(numBuckets); | ||
|
||
this.maps = new LongIntMap[numBuckets]; | ||
this.defaultValue = defaultValue; | ||
|
||
for (int i = 0; i < numBuckets; i++) { | ||
maps[i] = new PrimitiveFastutilLongIntWrapper(initialCapacity, loadFactor, defaultValue); | ||
} | ||
} | ||
|
||
@Override | ||
public int size() { | ||
return super.size(maps); | ||
} | ||
|
||
@Override | ||
public boolean isEmpty() { | ||
return super.isEmpty(maps); | ||
} | ||
|
||
@Override | ||
public boolean containsKey(long key) { | ||
int bucket = getBucket(key); | ||
|
||
Lock readLock = locks[bucket].readLock(); | ||
|
||
while (true) { | ||
if (readLock.tryLock()) { | ||
try { | ||
return maps[bucket].containsKey(key); | ||
} finally { | ||
readLock.unlock(); | ||
} | ||
} | ||
} | ||
} | ||
|
||
@Override | ||
public int get(long key) { | ||
int bucket = getBucket(key); | ||
|
||
Lock readLock = locks[bucket].readLock(); | ||
|
||
while (true) { | ||
if (readLock.tryLock()) { | ||
try { | ||
return maps[bucket].get(key); | ||
} finally { | ||
readLock.unlock(); | ||
} | ||
} | ||
} | ||
} | ||
|
||
@Override | ||
public int put(long key, int value) { | ||
int bucket = getBucket(key); | ||
|
||
Lock writeLock = locks[bucket].writeLock(); | ||
|
||
while (true) { | ||
if (writeLock.tryLock()) { | ||
try { | ||
return maps[bucket].put(key, value); | ||
} finally { | ||
writeLock.unlock(); | ||
} | ||
} | ||
} | ||
} | ||
|
||
@Override | ||
public int getDefaultValue() { | ||
return defaultValue; | ||
} | ||
|
||
@Override | ||
public int remove(long key) { | ||
int bucket = getBucket(key); | ||
|
||
Lock writeLock = locks[bucket].writeLock(); | ||
|
||
while (true) { | ||
if (writeLock.tryLock()) { | ||
try { | ||
return maps[bucket].remove(key); | ||
} finally { | ||
writeLock.unlock(); | ||
} | ||
} | ||
} | ||
} | ||
|
||
@Override | ||
public boolean remove(long key, int value) { | ||
int bucket = getBucket(key); | ||
|
||
Lock writeLock = locks[bucket].writeLock(); | ||
|
||
while (true) { | ||
if (writeLock.tryLock()) { | ||
try { | ||
return maps[bucket].remove(key, value); | ||
} finally { | ||
writeLock.unlock(); | ||
} | ||
} | ||
} | ||
} | ||
|
||
@Override | ||
public int computeIfAbsent(long key, Long2IntFunction mappingFunction) { | ||
int bucket = getBucket(key); | ||
|
||
Lock writeLock = locks[bucket].writeLock(); | ||
|
||
while (true) { | ||
if (writeLock.tryLock()) { | ||
try { | ||
return maps[bucket].computeIfAbsent(key, mappingFunction); | ||
} finally { | ||
writeLock.unlock(); | ||
} | ||
} | ||
} | ||
} | ||
|
||
@Override | ||
public int computeIfPresent(long key, BiFunction<Long, Integer, Integer> mappingFunction) { | ||
int bucket = getBucket(key); | ||
|
||
Lock writeLock = locks[bucket].writeLock(); | ||
|
||
while (true) { | ||
if (writeLock.tryLock()) { | ||
try { | ||
return maps[bucket].computeIfPresent(key, mappingFunction); | ||
} finally { | ||
writeLock.unlock(); | ||
} | ||
} | ||
} | ||
} | ||
} |
147 changes: 147 additions & 0 deletions
147
src/main/java/com/trivago/fastutilconcurrentwrapper/map/ConcurrentLongIntMap.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
package com.trivago.fastutilconcurrentwrapper.map; | ||
|
||
import com.trivago.fastutilconcurrentwrapper.IntIntMap; | ||
import com.trivago.fastutilconcurrentwrapper.LongIntMap; | ||
import com.trivago.fastutilconcurrentwrapper.wrapper.PrimitiveFastutilIntIntWrapper; | ||
import com.trivago.fastutilconcurrentwrapper.wrapper.PrimitiveFastutilLongIntWrapper; | ||
import it.unimi.dsi.fastutil.ints.Int2IntFunction; | ||
import it.unimi.dsi.fastutil.longs.Long2IntFunction; | ||
|
||
import java.util.concurrent.locks.Lock; | ||
import java.util.function.BiFunction; | ||
|
||
public class ConcurrentLongIntMap extends PrimitiveConcurrentMap implements LongIntMap { | ||
|
||
private final LongIntMap[] maps; | ||
private final int defaultValue; | ||
|
||
public ConcurrentLongIntMap( | ||
int numBuckets, | ||
int initialCapacity, | ||
float loadFactor, | ||
int defaultValue) { | ||
|
||
super(numBuckets); | ||
|
||
this.maps = new LongIntMap[numBuckets]; | ||
this.defaultValue = defaultValue; | ||
|
||
for (int i = 0; i < numBuckets; i++) { | ||
maps[i] = new PrimitiveFastutilLongIntWrapper(initialCapacity, loadFactor, defaultValue); | ||
} | ||
} | ||
|
||
@Override | ||
public int size() { | ||
return super.size(maps); | ||
} | ||
|
||
@Override | ||
public boolean isEmpty() { | ||
return super.isEmpty(maps); | ||
} | ||
|
||
@Override | ||
public boolean containsKey(long key) { | ||
int bucket = getBucket(key); | ||
|
||
Lock readLock = locks[bucket].readLock(); | ||
readLock.lock(); | ||
try { | ||
return maps[bucket].containsKey(key); | ||
} finally { | ||
readLock.unlock(); | ||
} | ||
} | ||
|
||
@Override | ||
public int get(long l) { | ||
int bucket = getBucket(l); | ||
|
||
int result; | ||
|
||
Lock readLock = locks[bucket].readLock(); | ||
readLock.lock(); | ||
try { | ||
result = maps[bucket].get(l); | ||
} finally { | ||
readLock.unlock(); | ||
} | ||
|
||
return result; | ||
} | ||
|
||
@Override | ||
public int put(long key, int value) { | ||
int bucket = getBucket(key); | ||
|
||
int result; | ||
|
||
Lock writeLock = locks[bucket].writeLock(); | ||
writeLock.lock(); | ||
try { | ||
result = maps[bucket].put(key, value); | ||
} finally { | ||
writeLock.unlock(); | ||
} | ||
|
||
return result; | ||
} | ||
|
||
@Override | ||
public int getDefaultValue() { | ||
return defaultValue; | ||
} | ||
|
||
@Override | ||
public int remove(long key) { | ||
int bucket = getBucket(key); | ||
|
||
Lock writeLock = locks[bucket].writeLock(); | ||
writeLock.lock(); | ||
try { | ||
return maps[bucket].remove(key); | ||
} finally { | ||
writeLock.unlock(); | ||
} | ||
} | ||
|
||
@Override | ||
public boolean remove(long key, int value) { | ||
int bucket = getBucket(key); | ||
|
||
Lock writeLock = locks[bucket].writeLock(); | ||
writeLock.lock(); | ||
try { | ||
return maps[bucket].remove(key, value); | ||
} finally { | ||
writeLock.unlock(); | ||
} | ||
} | ||
|
||
@Override | ||
public int computeIfAbsent(long key, Long2IntFunction mappingFunction) { | ||
int bucket = getBucket(key); | ||
|
||
Lock writeLock = locks[bucket].writeLock(); | ||
writeLock.lock(); | ||
try { | ||
return maps[bucket].computeIfAbsent(key, mappingFunction); | ||
} finally { | ||
writeLock.unlock(); | ||
} | ||
} | ||
|
||
@Override | ||
public int computeIfPresent(long key, BiFunction<Long, Integer, Integer> mappingFunction) { | ||
int bucket = getBucket(key); | ||
|
||
Lock writeLock = locks[bucket].writeLock(); | ||
writeLock.lock(); | ||
try { | ||
return maps[bucket].computeIfPresent(key, mappingFunction); | ||
} finally { | ||
writeLock.unlock(); | ||
} | ||
} | ||
} |
74 changes: 74 additions & 0 deletions
74
...n/java/com/trivago/fastutilconcurrentwrapper/wrapper/PrimitiveFastutilLongIntWrapper.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
package com.trivago.fastutilconcurrentwrapper.wrapper; | ||
|
||
import com.trivago.fastutilconcurrentwrapper.LongIntMap; | ||
import com.trivago.fastutilconcurrentwrapper.LongLongMap; | ||
import it.unimi.dsi.fastutil.longs.Long2IntFunction; | ||
import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap; | ||
import it.unimi.dsi.fastutil.longs.Long2LongFunction; | ||
import it.unimi.dsi.fastutil.longs.Long2LongOpenHashMap; | ||
|
||
import java.util.function.BiFunction; | ||
|
||
public class PrimitiveFastutilLongIntWrapper implements LongIntMap { | ||
private final Long2IntOpenHashMap map; | ||
private final int defaultValue; | ||
|
||
public PrimitiveFastutilLongIntWrapper(int initialCapacity, float loadFactor) { | ||
this(initialCapacity, loadFactor, LongIntMap.DEFAULT_VALUE); | ||
} | ||
|
||
public PrimitiveFastutilLongIntWrapper(int initialCapacity, float loadFactor, int defaultValue) { | ||
this.defaultValue = defaultValue; | ||
this.map = new Long2IntOpenHashMap(initialCapacity, loadFactor); | ||
} | ||
|
||
@Override | ||
public int get(long key) { | ||
return map.getOrDefault(key, defaultValue); | ||
} | ||
|
||
@Override | ||
public int put(long key, int value) { | ||
return map.put(key, value); | ||
} | ||
|
||
@Override | ||
public int getDefaultValue() { | ||
return defaultValue; | ||
} | ||
|
||
@Override | ||
public int remove(long key) { | ||
return map.remove(key); | ||
} | ||
|
||
@Override | ||
public boolean remove(long key, int value) { | ||
return map.remove(key, value); | ||
} | ||
|
||
@Override | ||
public int size() { | ||
return map.size(); | ||
} | ||
|
||
@Override | ||
public boolean containsKey(long key) { | ||
return map.containsKey(key); | ||
} | ||
|
||
@Override | ||
public boolean isEmpty() { | ||
return map.isEmpty(); | ||
} | ||
|
||
@Override | ||
public int computeIfAbsent(long key, Long2IntFunction mappingFunction) { | ||
return map.computeIfAbsent(key, mappingFunction); | ||
} | ||
|
||
@Override | ||
public int computeIfPresent(long key, BiFunction<Long, Integer, Integer> mappingFunction) { | ||
return map.computeIfPresent(key, mappingFunction); | ||
} | ||
} |