@@ -11,9 +11,7 @@ import java.util.concurrent.CompletableFuture
1111import java.util.concurrent.Executor
1212import kotlin.coroutines.coroutineContext
1313
14- class Cache <K , V >(
15- @Deprecated(" This should be ignored - use overloaded methods" ) private val defaultScope : CoroutineScope ,
16- @Deprecated(" This should be ignored - use overloaded methods" ) private val useCallingContext : Boolean ,
14+ class Cache <K : Any , V : Any >(
1715 private val cache : AsyncCache <K , V >
1816) {
1917
@@ -24,7 +22,7 @@ class Cache<K, V>(
2422 }
2523
2624 /* *
27- * Returns the value associated with key in this cache, or null if there is no cached future for key.
25+ * Returns the value associated with a key in this cache, or null if there is no cached future for the key.
2826 * This method will suspend while the value is fetched.
2927 * For a non-suspending alternative, see [getOrNull].
3028 */
@@ -33,15 +31,15 @@ class Cache<K, V>(
3331 }
3432
3533 /* *
36- * Returns the value associated with key in this cache or null if this cache does not
34+ * Returns the value associated with a key in this cache or null if this cache does not
3735 * contain an entry for the key. This is a non-suspendable alternative to getIfPresent(key).
3836 */
3937 fun getOrNull (key : K ): V ? {
4038 return cache.synchronous().getIfPresent(key)
4139 }
4240
4341 /* *
44- * Returns the value associated with key in this cache, obtaining that value from the
42+ * Returns the value associated with a key in this cache, getting that value from the
4543 * [compute] function if necessary. This function will suspend while the compute method
4644 * is executed.
4745 *
@@ -55,10 +53,10 @@ class Cache<K, V>(
5553 *
5654 */
5755 suspend fun get (key : K , compute : suspend (K ) -> V ): V {
58- val scope = scope( )
56+ val scope = CoroutineScope (coroutineContext )
5957 var error: Throwable ? = null
6058 val value = cache.get(key) { k, _ ->
61- scope.async {
59+ val asCompletableFuture = scope.async {
6260 // if compute throws, then it will cause the parent coroutine to be cancelled as well
6361 // we don't want that, as want to throw the exception back to the caller.
6462 // so we must capture it and throw it manually
@@ -69,25 +67,28 @@ class Cache<K, V>(
6967 null
7068 }
7169 }.asCompletableFuture()
70+ asCompletableFuture.thenApply { it ? : throw error ? : NullPointerException () }
7271 }.await()
7372 error?.let { throw it }
7473 return value
7574 }
7675
7776 /* *
78- * Returns the value associated with key in this cache, obtaining that value from the
77+ * Returns the value associated with a key in this cache, getting that value from the
7978 * [compute] function if necessary. This function will suspend while the compute method
8079 * is executed. If the suspendable computation throws, the exception will be propagated to the caller.
8180 *
8281 * If the specified key is not already associated with a value, attempts to compute its value asynchronously
83- * and enters it into this cache unless null.
82+ * and enters it into this cache unless null. The entire method invocation is performed atomically, so the
83+ * function is applied at most once per key. If the asynchronous computation fails, the entry will be
84+ * automatically removed from this cache.
8485 *
8586 * @param key the key to lookup in the cache
8687 * @param compute the suspendable function to generate a value for the given key.
8788 * @return the present value, the computed value, or throws.
8889 */
8990 suspend fun getOrNull (key : K , compute : suspend (K ) -> V ? ): V ? {
90- val scope = scope( )
91+ val scope = CoroutineScope (coroutineContext )
9192 return cache.get(key) { k, _ -> scope.async { compute(k) }.asCompletableFuture() }.await()
9293 }
9394
@@ -115,10 +116,10 @@ class Cache<K, V>(
115116 * If the suspendable computation throws, the entry will be automatically removed.
116117 *
117118 * @param key the key to associate the computed value with
118- * @param compute the suspendable function that generate the value.
119+ * @param compute the suspendable function that generates the value.
119120 */
120121 suspend fun put (key : K , compute : suspend () -> V ) {
121- val scope = scope( )
122+ val scope = CoroutineScope (coroutineContext )
122123 cache.put(key, scope.async { compute() }.asCompletableFuture())
123124 }
124125
@@ -140,7 +141,7 @@ class Cache<K, V>(
140141 }
141142
142143 suspend fun getAll (keys : Collection <K >, compute : suspend (Collection <K >) -> Map <K , V >): Map <K , V > {
143- val scope = scope( )
144+ val scope = CoroutineScope (coroutineContext )
144145 var error: Throwable ? = null
145146 val value = cache.getAll(keys) { ks: Set <K >, _: Executor ->
146147 scope.async {
@@ -176,8 +177,4 @@ class Cache<K, V>(
176177 fun invalidateAll () {
177178 cache.synchronous().invalidateAll()
178179 }
179-
180- private suspend fun scope (): CoroutineScope {
181- return if (useCallingContext) CoroutineScope (coroutineContext) else defaultScope
182- }
183180}
0 commit comments