All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.earth.worldwind.util.LruMemoryCache.kt Maven / Gradle / Ivy

Go to download

The WorldWind Kotlin SDK (WWK) includes the library, examples and tutorials for building multiplatform 3D virtual globe applications for Android, Web and Java.

There is a newer version: 1.6.2
Show newest version
package earth.worldwind.util

import earth.worldwind.util.Logger.ERROR
import earth.worldwind.util.Logger.logMessage
import kotlin.jvm.JvmOverloads

open class LruMemoryCache @JvmOverloads constructor(
    val capacity: Long, protected val lowWater: Long = (capacity * 0.75).toLong()
) {
    var usedCapacity = 0L
        protected set
    val entryCount get() = entries.size
    // sorts entries from least recently used to most recently used
    protected open val lruComparator = Comparator> { lhs, rhs -> lhs.lastUsed.compareTo(rhs.lastUsed) }
    protected val entries = mutableMapOf>()
    protected open var age = 0L
        get() = ++field // Auto increment cache age on each access to its entries

    protected open class Entry(val key: K, val value: V, val size: Int) { var lastUsed = 0L }

    init {
        require(capacity >= 1) {
            logMessage(ERROR, "LruMemoryCache", "constructor", "invalidCapacity")
        }
        require(lowWater in 0 until capacity) {
            logMessage(
                ERROR, "LruMemoryCache", "constructor",
                "The specified low-water value is greater than or equal to the capacity, or less than 1"
            )
        }
    }

    open operator fun get(key: K) = entries[key]?.run {
        lastUsed = age
        value
    }

    open fun put(key: K, value: V, size: Int): V? {
        if (usedCapacity + size > capacity) makeSpace(size)
        val newEntry = Entry(key, value, size)
        newEntry.lastUsed = age
        usedCapacity += newEntry.size
        val oldEntry = entries.put(key, newEntry)
        if (oldEntry != null) {
            usedCapacity -= oldEntry.size
            if (newEntry.value !== oldEntry.value) {
                entryRemoved(oldEntry.key, oldEntry.value, newEntry.value, false)
                return oldEntry.value
            }
        }
        return null
    }

    open fun remove(key: K) = entries.remove(key)?.run {
        usedCapacity -= size
        entryRemoved(key, value, null, false)
        value
    }

    open fun trimToAge(maxAge: Long): Int {
        var trimmedCapacity = 0

        // Sort the entries from least recently used to most recently used.
        val sortedEntries = assembleSortedEntries()

        // Remove the least recently used entries until the entry's age is within the specified maximum age.
        for (i in sortedEntries.indices) {
            val entry = sortedEntries[i]
            if (entry.lastUsed < maxAge) {
                entries.remove(entry.key)
                usedCapacity -= entry.size
                trimmedCapacity += entry.size
                entryRemoved(entry.key, entry.value, null, false)
            } else break
        }
        return trimmedCapacity
    }

    open fun containsKey(key: K) = entries.containsKey(key)

    open fun clear() {
        // NOTE Entities cleared without entryRemoved call
        // for (entry in entries.values) entryRemoved(entry.key, entry.value, null, false)
        entries.clear()
        usedCapacity = 0
    }

    protected open fun makeSpace(spaceRequired: Int) {
        // Sort the entries from least recently used to most recently used.
        val sortedEntries = assembleSortedEntries()

        // Remove the least recently used entries until the cache capacity reaches the low water and the cache has
        // enough free capacity for the required space.
        for (i in sortedEntries.indices) {
            val entry = sortedEntries[i]
            if (usedCapacity > lowWater || capacity - usedCapacity < spaceRequired) {
                entries.remove(entry.key)
                usedCapacity -= entry.size
                entryRemoved(entry.key, entry.value, null, true)
            } else break
        }
    }

    /*
     * Sort the entries from least recently used to most recently used.
     */
    protected open fun assembleSortedEntries() = entries.values.sortedWith(lruComparator)

    protected open fun entryRemoved(key: K, oldValue: V, newValue: V?, evicted: Boolean) {}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy