From 881f24e08df206832df9f083e2a4def2342bd194 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Mon, 6 Jul 2020 10:37:31 +0200 Subject: [PATCH] make LRUCache thread-safe --- .../it/unibo/tuprolog/utils/impl/LRUCache.kt | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/core/src/commonMain/kotlin/it/unibo/tuprolog/utils/impl/LRUCache.kt b/core/src/commonMain/kotlin/it/unibo/tuprolog/utils/impl/LRUCache.kt index 1869535f9..dac205a94 100644 --- a/core/src/commonMain/kotlin/it/unibo/tuprolog/utils/impl/LRUCache.kt +++ b/core/src/commonMain/kotlin/it/unibo/tuprolog/utils/impl/LRUCache.kt @@ -2,6 +2,9 @@ package it.unibo.tuprolog.utils.impl import it.unibo.tuprolog.utils.Cache import it.unibo.tuprolog.utils.Optional +import it.unibo.tuprolog.utils.buffered +import kotlin.jvm.Synchronized +import kotlin.jvm.Volatile internal class LRUCache(override val capacity: Int) : Cache { @@ -11,10 +14,14 @@ internal class LRUCache(override val capacity: Int) : Cache { private val cache = mutableMapOf() private val insertionOrder = (0 until capacity).map { Optional.none() }.toTypedArray() + @Volatile private var nextFreeIndex = 0 - override val size get() = cache.size + override val size + @Synchronized + get() = cache.size + @Synchronized override fun set(key: K, value: V): Optional> { val evicted: Optional> = insertionOrder[nextFreeIndex].let { evictedKey -> if (evictedKey is Optional.Some) { @@ -31,6 +38,7 @@ internal class LRUCache(override val capacity: Int) : Cache { return evicted } + @Synchronized override fun get(key: K): Optional = if (cache.containsKey(key)) { Optional.of(cache[key]) @@ -38,9 +46,11 @@ internal class LRUCache(override val capacity: Int) : Cache { Optional.none() } + @Synchronized override fun toMap(): Map = cache.toMap() + @Synchronized override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this::class != other::class) return false @@ -55,6 +65,7 @@ internal class LRUCache(override val capacity: Int) : Cache { return true } + @Synchronized override fun hashCode(): Int { var result = capacity result = 31 * result + cache.hashCode() @@ -63,6 +74,7 @@ internal class LRUCache(override val capacity: Int) : Cache { return result } + @Synchronized override fun toSequence(): Sequence> { val indexes = if (size < capacity) { (0 until size).asSequence() @@ -74,8 +86,10 @@ internal class LRUCache(override val capacity: Int) : Cache { .filterIsInstance>() .map { it.value } .map { it to cache[it]!! } + .buffered() } + @Synchronized override fun toString(): String { return "LRUCache(${toSequence().map { "${it.first} = ${it.second}" }.joinToString(", ")})" }