Skip to content

Commit

Permalink
+ wrong lru cache
Browse files Browse the repository at this point in the history
  • Loading branch information
gciatto committed May 5, 2020
1 parent 7a4ddbc commit 4cae84f
Show file tree
Hide file tree
Showing 4 changed files with 193 additions and 0 deletions.
19 changes: 19 additions & 0 deletions core/src/commonMain/kotlin/it/unibo/tuprolog/utils/Cache.kt
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 core/src/commonMain/kotlin/it/unibo/tuprolog/utils/Optional.kt
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
}
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)
// }
}
26 changes: 26 additions & 0 deletions core/src/jvmTest/kotlin/LRUCacheTest.kt
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)
}
}

0 comments on commit 4cae84f

Please sign in to comment.