package moe.nea.firmament.util.collections import moe.nea.firmament.util.IdentityCharacteristics fun mutableMapWithMaxSize(maxSize: Int): MutableMap = object : LinkedHashMap() { override fun removeEldestEntry(eldest: MutableMap.MutableEntry): Boolean { return size > maxSize } } fun ((T) -> R).memoizeIdentity(maxCacheSize: Int): (T) -> R { val memoized = { it: IdentityCharacteristics -> this(it.value) }.memoize(maxCacheSize) return { memoized(IdentityCharacteristics(it)) } } @PublishedApi internal val SENTINEL_NULL = java.lang.Object() /** * Requires the map to only contain values of type [R] or [SENTINEL_NULL]. This is ensured if the map is only ever * accessed via this function. */ inline fun MutableMap.computeNullableFunction(key: T, crossinline func: () -> R): R { val value = this.getOrPut(key) { func() ?: SENTINEL_NULL } @Suppress("UNCHECKED_CAST") return if (value === SENTINEL_NULL) null as R else value as R } fun ((T) -> R).memoize(maxCacheSize: Int): (T) -> R { val map = mutableMapWithMaxSize(maxCacheSize) return { map.computeNullableFunction(it) { this@memoize(it) } } }