WeakHashSet

This commit is contained in:
DBotThePony 2024-02-03 18:27:52 +07:00
parent bb7063c7f8
commit 40459a7e99
Signed by: DBot
GPG Key ID: DCC23B5715498507
3 changed files with 131 additions and 0 deletions

View File

@ -0,0 +1,25 @@
package ru.dbotthepony.kommons.collect
import it.unimi.dsi.fastutil.Hash
import java.lang.ref.Reference
object ReferenceHashStrategy : Hash.Strategy<Any?> {
override fun equals(a: Any?, b: Any?): Boolean {
if (a === b) return true
if (a == null || b == null) return false
if (a is Reference<*>) {
val ref = a.get()
if (b is Reference<*>) return ref != null && ref == b.get()
return ref == b
} else if (b is Reference<*>) {
return b.get() == a
} else {
return a == b
}
}
override fun hashCode(o: Any?): Int {
return o.hashCode()
}
}

View File

@ -0,0 +1,78 @@
package ru.dbotthepony.kommons.collect
import it.unimi.dsi.fastutil.objects.ObjectLinkedOpenCustomHashSet
import it.unimi.dsi.fastutil.objects.ObjectOpenCustomHashSet
import it.unimi.dsi.fastutil.objects.ObjectSet
import ru.dbotthepony.kommons.util.HashedWeakReference
import java.lang.ref.ReferenceQueue
class WeakHashSet<E : Any>(initialCapacity: Int = 16, loadFactor: Float = 0.75f, linked: Boolean = false) : MutableSet<E> {
private val queue = ReferenceQueue<E>()
private val backing: ObjectSet<Any> = if (linked) ObjectLinkedOpenCustomHashSet(initialCapacity, loadFactor, ReferenceHashStrategy) else ObjectOpenCustomHashSet(initialCapacity, loadFactor, ReferenceHashStrategy)
private fun purge() {
var next = queue.poll()
while (next != null) {
backing.remove(next)
next = queue.poll()
}
}
override fun add(element: E): Boolean {
purge()
if (element in backing) return false
return backing.add(HashedWeakReference(element, queue))
}
override fun addAll(elements: Collection<E>): Boolean {
var any = false
elements.forEach { any = add(it) || any }
return any
}
override fun clear() {
backing.clear()
while (queue.poll() != null) {}
}
override fun iterator(): MutableIterator<E> {
purge()
return backing.iterator().map { (it as HashedWeakReference<E>).get() }.filterNotNull()
}
override fun remove(element: E): Boolean {
purge()
return backing.remove(element)
}
override fun removeAll(elements: Collection<E>): Boolean {
purge()
return backing.removeAll(elements)
}
override fun retainAll(elements: Collection<E>): Boolean {
purge()
return backing.retainAll(elements)
}
override val size: Int get() {
purge()
return backing.size
}
override fun contains(element: E): Boolean {
purge()
return backing.contains(element)
}
override fun containsAll(elements: Collection<E>): Boolean {
purge()
return backing.containsAll(elements)
}
override fun isEmpty(): Boolean {
purge()
return backing.isEmpty()
}
}

View File

@ -0,0 +1,28 @@
package ru.dbotthepony.kommons.util
import java.lang.ref.ReferenceQueue
import java.lang.ref.WeakReference
/**
* [WeakReference], but with [hashCode] overridden with hash of referent object
*/
@Suppress("EqualsOrHashCode")
class HashedWeakReference<T : Any> : WeakReference<T> {
constructor(value: T) : super(value) {
hash = value.hashCode()
}
constructor(value: T, queue: ReferenceQueue<T>) : super(value, queue) {
hash = value.hashCode()
}
private val hash: Int
override fun hashCode(): Int {
return hash
}
override fun toString(): String {
return "HashedWeakReference[hash=$hash]"
}
}