Created
February 11, 2021 09:41
-
-
Save basvanmeurs/ec17c4e88cee668c59b33f9eae0ab03d to your computer and use it in GitHub Desktop.
Kotlin WeakMap that uses identity comparison rather than equality comparison
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 org.mypackage.util | |
import java.lang.ref.Reference | |
import java.lang.ref.ReferenceQueue | |
import java.lang.ref.WeakReference | |
/** | |
* WeakMap that uses identity comparison rather than equality comparison ([java.util.WeakHashMap]). | |
* Useful for instance mappings. | |
* | |
* Notice that keys and entries getters are not implemented. | |
*/ | |
class WeakIdentityMap<K, V> : MutableMap<K, V> { | |
private val map = mutableMapOf<IdentityWeakReference<K>, V>() | |
private val queue = ReferenceQueue<Any?>() | |
override fun clear() { | |
map.clear() | |
reap() | |
} | |
override fun containsKey(key: K): Boolean { | |
reap() | |
return map.containsKey(IdentityWeakReference(key, null)) | |
} | |
override fun containsValue(value: V): Boolean { | |
reap() | |
return map.containsValue(value) | |
} | |
override operator fun get(key: K): V? { | |
reap() | |
return map[IdentityWeakReference(key, null)] | |
} | |
override fun put(key: K, value: V): V? { | |
reap() | |
return map.put(IdentityWeakReference(key, queue), value) | |
} | |
override fun putAll(from: Map<out K, V>) { | |
reap() | |
from.forEach { (key, value) -> map[IdentityWeakReference(key, queue)] = value } | |
} | |
override fun isEmpty(): Boolean { | |
return size == 0 | |
} | |
override fun remove(key: K): V? { | |
reap() | |
return map.remove(IdentityWeakReference(key, null)) | |
} | |
override val size: Int | |
get() = doGetSize() | |
private fun doGetSize(): Int { | |
return if (map.isEmpty()) | |
0 | |
else { | |
reap() | |
map.size | |
} | |
} | |
override val values: MutableCollection<V> | |
get() = doGetValues() | |
private fun doGetValues(): MutableCollection<V> { | |
reap() | |
return map.values | |
} | |
// Too much work to implement. | |
override val keys: MutableSet<K> | |
get() = throw NotImplementedError() | |
// Too much work to implement. | |
override val entries: MutableSet<MutableMap.MutableEntry<K, V>> | |
get() = throw NotImplementedError() | |
private fun reap() { | |
var zombie: Reference<*>? | |
while (queue.poll().also { zombie = it } != null) { | |
map.remove(zombie) | |
} | |
} | |
private class IdentityWeakReference<K>(obj: K?, queue: ReferenceQueue<in K?>?) : WeakReference<K>(obj, queue) { | |
private val hash: Int = System.identityHashCode(obj) | |
override fun hashCode(): Int { | |
return hash | |
} | |
override fun equals(other: Any?): Boolean { | |
if (this === other) { | |
return true | |
} | |
if (other is IdentityWeakReference<*>) { | |
if (this.get() === other.get()) { | |
return true | |
} | |
} | |
return false | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment