aboutsummaryrefslogtreecommitdiff
path: root/src/main/kotlin/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/kotlin/util')
-rw-r--r--src/main/kotlin/util/Optionalutil.kt5
-rw-r--r--src/main/kotlin/util/collections/InstanceList.kt57
-rw-r--r--src/main/kotlin/util/collections/MutableMapWithMaxSize.kt (renamed from src/main/kotlin/util/MutableMapWithMaxSize.kt)4
-rw-r--r--src/main/kotlin/util/collections/WeakCache.kt110
-rw-r--r--src/main/kotlin/util/collections/listutil.kt (renamed from src/main/kotlin/util/listutil.kt)2
5 files changed, 176 insertions, 2 deletions
diff --git a/src/main/kotlin/util/Optionalutil.kt b/src/main/kotlin/util/Optionalutil.kt
new file mode 100644
index 0000000..1cef2fe
--- /dev/null
+++ b/src/main/kotlin/util/Optionalutil.kt
@@ -0,0 +1,5 @@
+package moe.nea.firmament.util
+
+import java.util.Optional
+
+fun <T : Any> T?.intoOptional(): Optional<T> = Optional.ofNullable(this)
diff --git a/src/main/kotlin/util/collections/InstanceList.kt b/src/main/kotlin/util/collections/InstanceList.kt
new file mode 100644
index 0000000..fd8c786
--- /dev/null
+++ b/src/main/kotlin/util/collections/InstanceList.kt
@@ -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)
+ }
+ }
+}
diff --git a/src/main/kotlin/util/MutableMapWithMaxSize.kt b/src/main/kotlin/util/collections/MutableMapWithMaxSize.kt
index 067e652..218bc55 100644
--- a/src/main/kotlin/util/MutableMapWithMaxSize.kt
+++ b/src/main/kotlin/util/collections/MutableMapWithMaxSize.kt
@@ -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 {
diff --git a/src/main/kotlin/util/collections/WeakCache.kt b/src/main/kotlin/util/collections/WeakCache.kt
new file mode 100644
index 0000000..38f9886
--- /dev/null
+++ b/src/main/kotlin/util/collections/WeakCache.kt
@@ -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)
+ }
+ }
+ }
+}
diff --git a/src/main/kotlin/util/listutil.kt b/src/main/kotlin/util/collections/listutil.kt
index 73cb23e..7f85a30 100644
--- a/src/main/kotlin/util/listutil.kt
+++ b/src/main/kotlin/util/collections/listutil.kt
@@ -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()) {