io.github.graphglue.util.CacheMap.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of graphglue-core Show documentation
Show all versions of graphglue-core Show documentation
A library to develop annotation-based code-first GraphQL servers using GraphQL Kotlin, Spring Boot and Neo4j - excluding Spring GraphQL server dependencies
The newest version!
package io.github.graphglue.util
import java.util.function.Consumer
import java.util.function.Function
/**
* Cache which can be used to cache and compute entities
* @param K the type of the keys under which cached entities are saved
* @param V the type of the cached entities
* @param backingMap the map which is used to cache the entities, defaults to a Hashmap
*/
class CacheMap(private val backingMap: MutableMap = HashMap()) : Map by backingMap {
/**
* set of entities which are currently computed using a callback
*/
private val currentlyComputing = mutableSetOf()
/**
* Gets the entity in cache under the specified `key`
* If no cache entry is found, the `mappingFunction` is used to create a new entity, which
* is saved to the cache and returned.
* Throws an exception if the entity under the provided key is currently computed
*
* @param key the key for the cache entity
* @param mappingFunction used to create the entity if not found in cache
* @return the cache entity associated with the provided key
* @throws IllegalArgumentException if the entity under the provided key is currently computed
*/
fun computeIfAbsent(key: K, mappingFunction: Function): V {
if (key in currentlyComputing) {
throw IllegalArgumentException("Already computing value for key $key")
}
return if (key in this) {
this.getValue(key)
} else {
currentlyComputing.add(key)
val result = mappingFunction.apply(key)
backingMap[key] = result
currentlyComputing.remove(key)
result
}
}
/**
* Gets the entity in cache under the specified `key`
* If no cache entry is found, the `mappingFunction` is used to create a new entity, which
* is saved to the cache and returned.
* If the value is currently computed, returns `alternativeIfComputing`
*
* @param key the key for the cache entity
* @param alternativeIfComputing alternative return value if value is currently in computation
* @param mappingFunction used to create the entity if not found in cache
* @return the cache entity associated with the provided key
* @throws IllegalArgumentException if the entity under the provided key is currently computed
*/
fun computeIfAbsent(key: K, alternativeIfComputing: V, mappingFunction: Function): V {
return if (key in currentlyComputing) {
alternativeIfComputing
} else {
computeIfAbsent(key, mappingFunction)
}
}
fun putAndInitIfAbsent(key: K, value: V, initFunction: Consumer): V {
if (key in currentlyComputing) {
throw IllegalArgumentException("Already computing value for key $key")
}
return if (key in this) {
this.getValue(key)
} else {
backingMap[key] = value
initFunction.accept(value)
value
}
}
}