commonMain.io.nacular.doodle.utils.LeastRecentlyUsedCache.kt Maven / Gradle / Ivy
package io.nacular.doodle.utils
/**
* Created by Nicholas Eddy on 3/22/20.
*/
public class LeastRecentlyUsedCache(private val maxSize: Int): MutableMap {
private inner class Entry(var value: V, var key: K) {
var left : Entry? = null
var right: Entry? = null
}
private val hashMap = mutableMapOf()
private var start = null as LeastRecentlyUsedCache.Entry?
private var end = null as LeastRecentlyUsedCache.Entry?
// FIXME: File Kotlin bug for this, which fails w/ ClassCastException whenever the key isn't found
// override operator fun get(key: K): V? = hashMap[key]?.let {
// removeNode(it)
// addAtTop (it)
// return it.value
// }
override operator fun get(key: K): V? {
return hashMap[key]?.let {
removeNode(it)
addAtTop (it)
return it.value
}
}
override val entries: MutableSet>
get() = hashMap.entries.map {
object: MutableMap.MutableEntry {
override var key = it.key
override var value = it.value.value
override fun setValue(newValue: V): V {
val result = it.value.value
it.value.value = newValue
return result
}
}
}.toMutableSet()
override val keys : MutableSet get() = hashMap.keys
override val size : Int get() = hashMap.size
override val values: MutableList get() = hashMap.values.map { it.value }.toMutableList()
override fun containsKey(key: K): Boolean = hashMap.containsKey(key)
override fun containsValue(value: V): Boolean = value in values
override fun isEmpty(): Boolean = hashMap.isEmpty()
override fun clear() {
hashMap.clear()
start = null
end = null
}
override fun put(key: K, value: V): V? {
var result = value
when (val entry = hashMap[key]) {
null -> {
val newNode = Entry(key = key, value = value)
// We have reached maximum size so need to make room for new element.
if (hashMap.size >= maxSize) {
end?.let { end ->
hashMap.remove(end.key)
removeNode(end)
addAtTop(newNode)
}
} else {
addAtTop(newNode)
}
if (end != null) {
hashMap[key] = newNode
}
}
else -> {
result = entry.value
entry.value = value
removeNode(entry)
addAtTop(entry)
}
}
return result
}
override fun putAll(from: Map) {
from.forEach {
this[it.key] = it.value
}
}
override fun remove(key: K): V? = hashMap.remove(key)?.also {
removeNode(it)
}?.value
private fun addAtTop(node: Entry) {
node.left = null
node.right = start
start?.let { it.left = node }
start = node
if (end == null) end = start
}
private fun removeNode(node: Entry) {
when (val l = node.left) {
null -> start = node.right
else -> l.right = node.right
}
when (val r = node.right) {
null -> end = node.left
else -> r.left = node.left
}
}
}