Use weak caches for custom textures
This commit is contained in:
5
src/main/kotlin/util/Optionalutil.kt
Normal file
5
src/main/kotlin/util/Optionalutil.kt
Normal file
@@ -0,0 +1,5 @@
|
||||
package moe.nea.firmament.util
|
||||
|
||||
import java.util.Optional
|
||||
|
||||
fun <T : Any> T?.intoOptional(): Optional<T> = Optional.ofNullable(this)
|
||||
57
src/main/kotlin/util/collections/InstanceList.kt
Normal file
57
src/main/kotlin/util/collections/InstanceList.kt
Normal file
@@ -0,0 +1,57 @@
|
||||
package moe.nea.firmament.util.collections
|
||||
|
||||
import java.lang.ref.ReferenceQueue
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
class InstanceList<T : Any>(val name: String) {
|
||||
val queue = object : ReferenceQueue<T>() {}
|
||||
val set = mutableSetOf<Ref>()
|
||||
|
||||
val size: Int
|
||||
get() {
|
||||
clearOldReferences()
|
||||
return set.size
|
||||
}
|
||||
|
||||
fun clearOldReferences() {
|
||||
while (true) {
|
||||
val reference = queue.poll() ?: break
|
||||
set.remove(reference)
|
||||
}
|
||||
}
|
||||
|
||||
fun getAll(): List<T> {
|
||||
clearOldReferences()
|
||||
return set.mapNotNull { it.get() }
|
||||
}
|
||||
|
||||
fun add(t: T) {
|
||||
set.add(Ref(t))
|
||||
}
|
||||
|
||||
init {
|
||||
if (init)
|
||||
allInstances.add(this)
|
||||
}
|
||||
|
||||
inner class Ref(referent: T) : WeakReference<T>(referent) {
|
||||
val hashCode = System.identityHashCode(referent)
|
||||
override fun equals(other: Any?): Boolean {
|
||||
return other is InstanceList<*>.Ref && hashCode == other.hashCode && get() === other.get()
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return hashCode
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private var init = false
|
||||
val allInstances = InstanceList<InstanceList<*>>("InstanceLists")
|
||||
|
||||
init {
|
||||
init = true
|
||||
allInstances.add(allInstances)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
|
||||
package moe.nea.firmament.util
|
||||
package moe.nea.firmament.util.collections
|
||||
|
||||
import moe.nea.firmament.util.IdentityCharacteristics
|
||||
|
||||
fun <K, V> mutableMapWithMaxSize(maxSize: Int): MutableMap<K, V> = object : LinkedHashMap<K, V>() {
|
||||
override fun removeEldestEntry(eldest: MutableMap.MutableEntry<K, V>): Boolean {
|
||||
110
src/main/kotlin/util/collections/WeakCache.kt
Normal file
110
src/main/kotlin/util/collections/WeakCache.kt
Normal file
@@ -0,0 +1,110 @@
|
||||
package moe.nea.firmament.util.collections
|
||||
|
||||
import java.lang.ref.ReferenceQueue
|
||||
import java.lang.ref.WeakReference
|
||||
import moe.nea.firmament.features.debug.DebugLogger
|
||||
|
||||
/**
|
||||
* Cache class that uses [WeakReferences][WeakReference] to only cache values while there is still a life reference to
|
||||
* the key. Each key can have additional extra data that is used to look up values. That extra data is not required to
|
||||
* be a life reference. The main Key is compared using strict reference equality. This map is not synchronized.
|
||||
*/
|
||||
class WeakCache<Key : Any, ExtraKey : Any, Value : Any>(val name: String) {
|
||||
private val queue = object : ReferenceQueue<Key>() {}
|
||||
private val map = mutableMapOf<Ref, Value>()
|
||||
|
||||
val size: Int
|
||||
get() {
|
||||
clearOldReferences()
|
||||
return map.size
|
||||
}
|
||||
|
||||
fun clearOldReferences() {
|
||||
var successCount = 0
|
||||
var totalCount = 0
|
||||
while (true) {
|
||||
val reference = queue.poll() ?: break
|
||||
totalCount++
|
||||
if (map.remove(reference) != null)
|
||||
successCount++
|
||||
}
|
||||
if (totalCount > 0)
|
||||
logger.log { "Cleared $successCount/$totalCount references from queue" }
|
||||
}
|
||||
|
||||
fun get(key: Key, extraData: ExtraKey): Value? {
|
||||
clearOldReferences()
|
||||
return map[Ref(key, extraData)]
|
||||
}
|
||||
|
||||
fun put(key: Key, extraData: ExtraKey, value: Value) {
|
||||
clearOldReferences()
|
||||
map[Ref(key, extraData)] = value
|
||||
}
|
||||
|
||||
fun getOrPut(key: Key, extraData: ExtraKey, value: (Key, ExtraKey) -> Value): Value {
|
||||
clearOldReferences()
|
||||
return map.getOrPut(Ref(key, extraData)) { value(key, extraData) }
|
||||
}
|
||||
|
||||
fun clear() {
|
||||
map.clear()
|
||||
}
|
||||
|
||||
init {
|
||||
allInstances.add(this)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val allInstances = InstanceList<WeakCache<*, *, *>>("WeakCaches")
|
||||
private val logger = DebugLogger("WeakCache")
|
||||
fun <Key : Any, Value : Any> memoize(name: String, function: (Key) -> Value):
|
||||
CacheFunction.NoExtraData<Key, Value> {
|
||||
return CacheFunction.NoExtraData(WeakCache(name), function)
|
||||
}
|
||||
|
||||
fun <Key : Any, ExtraKey : Any, Value : Any> memoize(name: String, function: (Key, ExtraKey) -> Value):
|
||||
CacheFunction.WithExtraData<Key, ExtraKey, Value> {
|
||||
return CacheFunction.WithExtraData(WeakCache(name), function)
|
||||
}
|
||||
}
|
||||
|
||||
inner class Ref(
|
||||
weakInstance: Key,
|
||||
val extraData: ExtraKey,
|
||||
) : WeakReference<Key>(weakInstance, queue) {
|
||||
val hashCode = System.identityHashCode(weakInstance) * 31 + extraData.hashCode()
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (other !is WeakCache<*, *, *>.Ref) return false
|
||||
return other.hashCode == this.hashCode
|
||||
&& other.get() === this.get()
|
||||
&& other.extraData == this.extraData
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return hashCode
|
||||
}
|
||||
}
|
||||
|
||||
interface CacheFunction {
|
||||
val cache: WeakCache<*, *, *>
|
||||
|
||||
data class NoExtraData<Key : Any, Value : Any>(
|
||||
override val cache: WeakCache<Key, Unit, Value>,
|
||||
val wrapped: (Key) -> Value,
|
||||
) : CacheFunction, (Key) -> Value {
|
||||
override fun invoke(p1: Key): Value {
|
||||
return cache.getOrPut(p1, Unit, { a, _ -> wrapped(a) })
|
||||
}
|
||||
}
|
||||
|
||||
data class WithExtraData<Key : Any, ExtraKey : Any, Value : Any>(
|
||||
override val cache: WeakCache<Key, ExtraKey, Value>,
|
||||
val wrapped: (Key, ExtraKey) -> Value,
|
||||
) : CacheFunction, (Key, ExtraKey) -> Value {
|
||||
override fun invoke(p1: Key, p2: ExtraKey): Value {
|
||||
return cache.getOrPut(p1, p2, wrapped)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
package moe.nea.firmament.util
|
||||
package moe.nea.firmament.util.collections
|
||||
|
||||
fun <T, R> List<T>.lastNotNullOfOrNull(func: (T) -> R?): R? {
|
||||
for (i in indices.reversed()) {
|
||||
Reference in New Issue
Block a user