Last active
June 15, 2024 22:10
-
-
Save NicolaM94/d65b859355560d03823ca95dbe59df71 to your computer and use it in GitHub Desktop.
Kotlin implementation for the LFU (Least Frequently Used) cache algorithm
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
package main | |
// Object stored in the cache, could be anything | |
class Object (val key: String, val value: Int) | |
class LeastFrequentlyUsed (private val cacheLimit :Int) { | |
// Holds objects | |
private val cache = mutableListOf<Object>() | |
// Keeps track of hashes -> index, used in get(key) => hash(key) => index | |
private val indexLinks = mutableMapOf<Int,Int>() | |
// Keeps track of calls | |
private val calledObjects = mutableMapOf<Int, Int>() | |
// Keeps track of the last inserted index | |
private var lastInserted :Int = 0 | |
// Collectors and printer for the LFU cache state | |
private fun collectCache() :MutableList<Pair<String,Int>> { | |
val collector = mutableListOf<Pair<String,Int>>() | |
cache.forEach { | |
collector.add(Pair(it.key, it.value)) | |
} | |
return collector | |
} | |
private fun collectCounters () :MutableList<Pair<String,Int>> { | |
val collector = mutableListOf<Pair<String,Int>>() | |
cache.forEach { | |
collector.add(Pair( | |
it.key, | |
calledObjects[it.key.hashCode()]!! | |
)) | |
} | |
return collector | |
} | |
private fun collectIndexLinks () :MutableList<Pair<String,Int>> { | |
val collector = mutableListOf<Pair<String,Int>>() | |
cache.forEach { | |
collector.add(Pair( | |
it.key, | |
indexLinks[it.key.hashCode()]!! | |
)) | |
} | |
return collector | |
} | |
fun printLfu() { | |
println("Cache: ${collectCache()}") | |
println("Counters: ${collectCounters()}") | |
println("IndexLinks: ${collectIndexLinks()}") | |
println() | |
} | |
// LFU setter | |
fun set(key :String, value: Int) { | |
val hashKey = key.hashCode() | |
// If we reached the cache limit we need to take away the less used item in the cache | |
if (lastInserted == cacheLimit) { | |
// Lower lastInserted of 1 just to bring it back to max later | |
lastInserted-- | |
// Brings up least used item, stored in the last index of the cache | |
val lessUsedItem = cache.last() | |
// Removes the least used item from cache | |
cache.removeLast() | |
// Clears indexLinks from the element removed from cache | |
indexLinks.remove(lessUsedItem.key.hashCode()) | |
// Clears calledObjects from the element removed from cache | |
calledObjects.remove(lessUsedItem.key.hashCode()) | |
} | |
// Adds the new element to cache | |
cache.add(Object(key,value)) | |
// Adds the new element to indexLinks | |
indexLinks[hashKey] = lastInserted | |
// Adds the new element to calledObjects | |
calledObjects[hashKey] = 0 | |
// Turns back lastInserted to max = cache limit | |
lastInserted++ | |
} | |
// LFU getter | |
fun get (key :String) :Object? { | |
val hashKey = key.hashCode() | |
// Verify if the key is present in the LFU | |
indexLinks[hashKey] ?: return null | |
// Updates the calledObjects counter | |
calledObjects[hashKey] = calledObjects[hashKey]!!.plus(1) | |
// Gets the current element position in the cache | |
val currentItemIndex = indexLinks[hashKey]!! | |
if (currentItemIndex > 0 ) { | |
// Gets the previous element position in the cache, which is the current -1 | |
val previousItemIndex = currentItemIndex - 1 | |
// Gets the key of the previous item to find it in calledObjects and see its number of calls | |
val previousItemKey = cache[previousItemIndex].key.hashCode() | |
// Checks which is the most called: the current or the previous. | |
// If is the current, swap the two | |
if (calledObjects[hashKey]!! > calledObjects[previousItemKey]!!) { | |
// Adjusts the position in the cache | |
val temp = cache[previousItemIndex] | |
cache[previousItemIndex] = cache[currentItemIndex] | |
cache[currentItemIndex] = temp | |
// Adjusts their indices in the indexLists map | |
indexLinks[hashKey] = indexLinks[hashKey]!! - 1 | |
indexLinks[previousItemKey] = indexLinks[previousItemKey]!! + 1 | |
} | |
} | |
return cache[indexLinks[hashKey]!!] | |
} | |
} | |
fun main () { | |
val lfu = LeastFrequentlyUsed(3) | |
lfu.set("Alice", 10) | |
lfu.set("Bob", 20) | |
lfu.set("Charlie",30) | |
lfu.printLfu() | |
lfu.get("Charlie") | |
lfu.get("Charlie") | |
lfu.set("Dean", 50) | |
lfu.get("Dean") | |
lfu.printLfu() | |
lfu.get("gianni") | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment