Skip to content

Commit 5539b42

Browse files
authored
feat: add Cache#compute and Cache#computeIfPresent (#31)
1 parent 53557cc commit 5539b42

File tree

5 files changed

+106
-2
lines changed

5 files changed

+106
-2
lines changed

api/src/main/java/io/github/xanthic/cache/api/Cache.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,18 @@ public interface Cache<K, V> {
6767
*/
6868
long size();
6969

70+
/**
71+
* Computes what value should be associated with the specified key, or null if the mapping should be removed.
72+
*
73+
* @param key the key with which the specified value is to be associated
74+
* @param computeFunc the function to compute a value
75+
* @return the new value associated with the specified key, or null if none
76+
* @throws NullPointerException if the specified key is null and this cache does not support null keys, or the compute function is null
77+
* @implNote atomicity is dependent on provider characteristics
78+
*/
79+
@Nullable
80+
V compute(K key, @NotNull BiFunction<? super K, ? super V, ? extends V> computeFunc);
81+
7082
/**
7183
* Obtains the value currently associated with the specified key,
7284
* or atomically stores the computed value if no prior mapping existed.
@@ -78,6 +90,19 @@ public interface Cache<K, V> {
7890
*/
7991
V computeIfAbsent(K key, @NotNull Function<K, V> computeFunc);
8092

93+
/**
94+
* Computes a new value for a specific key, if a mapping already existed.
95+
* <p>
96+
* If the compute function yields null, the mapping should be removed.
97+
*
98+
* @param key the key whose mapping should be updated
99+
* @param computeFunc the function to compute the new value for an already existing mapping
100+
* @return the new value associated with the key, or null if none
101+
* @throws NullPointerException if the specified key is null and this cache does not support null keys, or the compute function is null
102+
*/
103+
@Nullable
104+
V computeIfPresent(K key, @NotNull BiFunction<? super K, ? super V, ? extends V> computeFunc);
105+
81106
/**
82107
* Creates a mapping from the specified key to the specified value,
83108
* if no mapping for the key already existed.

core/src/main/java/io/github/xanthic/cache/core/AbstractCache.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import io.github.xanthic.cache.api.Cache;
44
import org.jetbrains.annotations.NotNull;
5+
import org.jetbrains.annotations.Nullable;
56

67
import java.util.Objects;
78
import java.util.function.BiFunction;
@@ -37,6 +38,39 @@ public V computeIfAbsent(K key, @NotNull Function<K, V> computeFunc) {
3738
}
3839
}
3940

41+
@Nullable
42+
@Override
43+
public V compute(K key, @NotNull BiFunction<? super K, ? super V, ? extends V> computeFunc) {
44+
synchronized (getLock()) {
45+
V oldValue = this.get(key);
46+
V newValue = computeFunc.apply(key, oldValue);
47+
if (newValue != null) {
48+
this.put(key, newValue);
49+
return newValue;
50+
} else if (oldValue != null) {
51+
this.remove(key);
52+
}
53+
}
54+
return null;
55+
}
56+
57+
@Override
58+
public V computeIfPresent(K key, @NotNull BiFunction<? super K, ? super V, ? extends V> computeFunc) {
59+
synchronized (getLock()) {
60+
V oldValue = this.get(key);
61+
if (oldValue != null) {
62+
V newValue = computeFunc.apply(key, oldValue);
63+
if (newValue != null) {
64+
this.put(key, newValue);
65+
return newValue;
66+
} else {
67+
this.remove(key);
68+
}
69+
}
70+
}
71+
return null;
72+
}
73+
4074
@Override
4175
public V putIfAbsent(K key, V value) {
4276
synchronized (getLock()) {

core/src/main/java/io/github/xanthic/cache/core/delegate/GenericMapCacheDelegate.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import io.github.xanthic.cache.api.ICacheSpec;
66
import lombok.Data;
77
import org.jetbrains.annotations.NotNull;
8+
import org.jetbrains.annotations.Nullable;
89

910
import java.util.Map;
1011
import java.util.function.BiFunction;
@@ -32,11 +33,22 @@ public V put(K key, V value) {
3233
return map.put(key, value);
3334
}
3435

36+
@Nullable
37+
@Override
38+
public V compute(K key, @NotNull BiFunction<? super K, ? super V, ? extends V> computeFunc) {
39+
return map.compute(key, computeFunc);
40+
}
41+
3542
@Override
3643
public V computeIfAbsent(K key, @NotNull Function<K, V> computeFunc) {
3744
return map.computeIfAbsent(key, computeFunc);
3845
}
3946

47+
@Override
48+
public V computeIfPresent(K key, @NotNull BiFunction<? super K, ? super V, ? extends V> computeFunc) {
49+
return map.computeIfPresent(key, computeFunc);
50+
}
51+
4052
@Override
4153
public V remove(K key) {
4254
return map.remove(key);

core/src/testFixtures/java/io/github/xanthic/cache/core/provider/ProviderTestBase.java

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public void putGetClearTest() {
5959
}
6060

6161
@Test
62-
@DisplayName("Tests cache computeIfAbsent, merge, and remove")
62+
@DisplayName("Tests cache compute, computeIfAbsent, computeIfPresent, merge, and remove")
6363
public void computeMergeRemoveTest() {
6464
// Build cache
6565
Cache<String, Integer> cache = build(null);
@@ -71,9 +71,30 @@ public void computeMergeRemoveTest() {
7171
// Test merge
7272
Assertions.assertEquals(420 + 69, cache.merge("4/20", 69, Integer::sum));
7373

74+
// Test computeIfPresent
75+
Assertions.assertNull(cache.computeIfPresent("", (k, v) -> 0));
76+
Assertions.assertNull(cache.put("", 0));
77+
Assertions.assertNull(cache.computeIfPresent("", (k, v) -> null));
78+
Assertions.assertNull(cache.get(""));
79+
80+
Assertions.assertEquals(420 + 69 + 1, cache.computeIfPresent("4/20", (k, v) -> v + 1));
81+
7482
// Test remove
75-
Assertions.assertEquals(420 + 69, cache.remove("4/20"));
83+
Assertions.assertEquals(420 + 70, cache.remove("4/20"));
7684
Assertions.assertNull(cache.get("4/20"));
85+
86+
// Test compute
87+
Assertions.assertNull(cache.compute("a", (k, v) -> null));
88+
Assertions.assertNull(cache.get("a"));
89+
90+
Assertions.assertEquals(9, cache.compute("a", (k, v) -> 9));
91+
Assertions.assertEquals(9, cache.get("a"));
92+
93+
Assertions.assertEquals(10, cache.compute("a", (k, v) -> v + 1));
94+
Assertions.assertEquals(10, cache.get("a"));
95+
96+
Assertions.assertNull(cache.compute("a", (k, v) -> null));
97+
Assertions.assertNull(cache.get("a"));
7798
}
7899

79100
@Test

provider-infinispan/src/main/java/io/github/xanthic/cache/provider/infinispan/InfinispanDelegate.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import io.github.xanthic.cache.api.Cache;
44
import lombok.Value;
55
import org.jetbrains.annotations.NotNull;
6+
import org.jetbrains.annotations.Nullable;
67

78
import java.util.Map;
89
import java.util.function.BiFunction;
@@ -37,11 +38,22 @@ public long size() {
3738
return cache.size();
3839
}
3940

41+
@Nullable
42+
@Override
43+
public V compute(K key, @NotNull BiFunction<? super K, ? super V, ? extends V> computeFunc) {
44+
return cache.compute(key, computeFunc);
45+
}
46+
4047
@Override
4148
public V computeIfAbsent(K key, @NotNull Function<K, V> computeFunc) {
4249
return cache.computeIfAbsent(key, computeFunc);
4350
}
4451

52+
@Override
53+
public V computeIfPresent(K key, @NotNull BiFunction<? super K, ? super V, ? extends V> computeFunc) {
54+
return cache.computeIfPresent(key, computeFunc);
55+
}
56+
4557
@Override
4658
public V putIfAbsent(K key, V value) {
4759
return cache.putIfAbsent(key, value);

0 commit comments

Comments
 (0)