-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
193 additions
and
0 deletions.
There are no files selected for viewing
19 changes: 19 additions & 0 deletions
19
core/src/commonMain/kotlin/it/unibo/tuprolog/utils/Cache.kt
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,19 @@ | ||
package it.unibo.tuprolog.utils | ||
|
||
import it.unibo.tuprolog.utils.impl.LRUCache | ||
|
||
interface Cache<K, V> { | ||
val capacity: Int | ||
|
||
operator fun set(key: K, value: V): K? | ||
|
||
operator fun get(key: K): V? | ||
|
||
fun toMap(): Map<K, V> | ||
|
||
fun toSequence(): Sequence<Pair<K, V>> | ||
|
||
companion object { | ||
fun <K, V> lru(capacity: Int = 5): Cache<K, V> = LRUCache(capacity) | ||
} | ||
} |
65 changes: 65 additions & 0 deletions
65
core/src/commonMain/kotlin/it/unibo/tuprolog/utils/Optional.kt
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,65 @@ | ||
package it.unibo.tuprolog.utils | ||
|
||
sealed class Optional<T> { | ||
|
||
companion object { | ||
fun <T> of(value: T): Optional<out T> = Some(value) | ||
|
||
fun <T> empty(): Optional<out T> = None | ||
} | ||
|
||
data class Some<T>(override val value: T) : Optional<T>() { | ||
override val isPresent: Boolean | ||
get() = true | ||
|
||
override fun <R> map(function: (T) -> R): Some<R> = | ||
Some(function(value)) | ||
|
||
override fun filter(predicate: (T) -> Boolean): Optional<out T> = | ||
when { | ||
predicate(value) -> this | ||
else -> None | ||
} | ||
|
||
override fun toSequence(): Sequence<T> = | ||
sequenceOf(value) | ||
|
||
override fun toString(): String = | ||
"Some($value)" | ||
} | ||
|
||
object None : Optional<Nothing>() { | ||
override val value: Nothing? | ||
get() = null | ||
|
||
override val isPresent: Boolean | ||
get() = false | ||
|
||
override fun <R> map(function: (Nothing) -> R): None = | ||
None | ||
|
||
override fun filter(predicate: (Nothing) -> Boolean): None = | ||
None | ||
|
||
override fun toSequence(): Sequence<Nothing> = | ||
emptySequence() | ||
|
||
override fun toString(): String = | ||
"None" | ||
} | ||
|
||
abstract val value: T? | ||
|
||
abstract val isPresent: Boolean | ||
|
||
val isAbsent: Boolean | ||
get() = !isPresent | ||
|
||
abstract fun <R> map(function: (T) -> R): Optional<out R> | ||
|
||
abstract fun filter(predicate: (T) -> Boolean): Optional<out T> | ||
|
||
abstract fun toSequence(): Sequence<T> | ||
|
||
abstract override fun toString(): String | ||
} |
83 changes: 83 additions & 0 deletions
83
core/src/commonMain/kotlin/it/unibo/tuprolog/utils/impl/LRUCache.kt
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,83 @@ | ||
package it.unibo.tuprolog.utils.impl | ||
|
||
import it.unibo.tuprolog.utils.Cache | ||
import it.unibo.tuprolog.utils.Optional | ||
|
||
internal class LRUCache<K, V>(override val capacity: Int) : Cache<K, V> { | ||
|
||
init { | ||
require(capacity > 0) | ||
} | ||
|
||
private val cache = HashMap<K, V>() | ||
private val insertionOrder = (0 until capacity).map { Optional.empty<K>() }.toTypedArray() | ||
private val size get() = cache.size | ||
private var nextFreeIndex = 0 | ||
|
||
override fun set(key: K, value: V): K? { | ||
val evicted = insertionOrder[nextFreeIndex].value?.also { | ||
cache.remove(it) | ||
} | ||
insertionOrder[nextFreeIndex] = Optional.of(key) | ||
cache[key] = value | ||
nextFreeIndex = (nextFreeIndex + 1) % capacity | ||
return evicted | ||
} | ||
|
||
override fun get(key: K): V? = | ||
cache[key] | ||
|
||
override fun toMap(): Map<K, V> = | ||
cache.toMap() | ||
|
||
override fun equals(other: Any?): Boolean { | ||
if (this === other) return true | ||
if (other == null || this::class != other::class) return false | ||
|
||
other as LRUCache<*, *> | ||
|
||
if (capacity != other.capacity) return false | ||
if (cache != other.cache) return false | ||
if (!insertionOrder.contentEquals(other.insertionOrder)) return false | ||
if (nextFreeIndex != other.nextFreeIndex) return false | ||
|
||
return true | ||
} | ||
|
||
override fun hashCode(): Int { | ||
var result = capacity | ||
result = 31 * result + cache.hashCode() | ||
result = 31 * result + insertionOrder.contentHashCode() | ||
result = 31 * result + nextFreeIndex | ||
return result | ||
} | ||
|
||
override fun toSequence(): Sequence<Pair<K, V>> { | ||
val lri = leastRecentIndex | ||
return (0 until size).asSequence() | ||
.map { (it + lri) % capacity } | ||
.map { insertionOrder[it] } | ||
.take(cache.size) | ||
.filterIsInstance<Optional.Some<K>>() | ||
.map { it.value } | ||
.map { it to cache[it]!! } | ||
} | ||
|
||
override fun toString(): String { | ||
return "LRUCache(${toSequence().map { "${it.first} = ${it.second}" }.joinToString(",")})" | ||
} | ||
|
||
|
||
private val leastRecentIndex: Int | ||
get() = (nextFreeIndex + capacity + 1) % capacity | ||
|
||
// private fun getKeyToEvict(): K? = | ||
// insertionOrder[(nextFreeIndex + size) % capacity].value | ||
// | ||
// private fun pop(): K { | ||
// val leastRecentIndex = (nextFreeIndex + capacity + 1) % capacity | ||
// val result = insertionOrder[leastRecentIndex] | ||
// insertionOrder[leastRecentIndex] = Optional.empty() | ||
// cache.remove(result) | ||
// } | ||
} |
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,26 @@ | ||
import it.unibo.tuprolog.utils.Cache | ||
import org.junit.Test | ||
|
||
class LRUCacheTest { | ||
@Test | ||
fun test() { | ||
val cache = Cache.lru<String, Int>(4) | ||
println(cache) | ||
cache["A"] = 1 | ||
println(cache) | ||
cache["B"] = 2 | ||
println(cache) | ||
cache["C"] = 3 | ||
println(cache) | ||
cache["D"] = 4 | ||
println(cache) | ||
cache["E"] = 5 | ||
println(cache) | ||
cache["F"] = 5 | ||
println(cache) | ||
cache["G"] = 6 | ||
println(cache) | ||
cache["H"] = 7 | ||
println(cache) | ||
} | ||
} |