56 lines
1.4 KiB
Kotlin
56 lines
1.4 KiB
Kotlin
package ru.landrafhomyak.utility.reference_counter
|
|
|
|
import kotlinx.atomicfu.AtomicLong
|
|
import kotlinx.atomicfu.atomic
|
|
import kotlinx.atomicfu.update
|
|
import ru.landgrafhomyak.utility.highlevel_try_finally.safeAutoClose1
|
|
import ru.landgrafhomyak.utility.highlevel_try_finally.safeAutoClose2
|
|
|
|
internal class CloseableReferenceCounter(private val _errMessage: String) {
|
|
private val _value: AtomicLong = atomic(0L)
|
|
|
|
fun throwClosed() {
|
|
throw IllegalStateException(this._errMessage)
|
|
}
|
|
|
|
fun incref() {
|
|
this._value.update { o ->
|
|
if (o < 0) this.throwClosed()
|
|
return@update o + 1
|
|
}
|
|
}
|
|
|
|
inline fun <R> tryIncref(block: () -> R): R {
|
|
this.incref()
|
|
return safeAutoClose2(onError = this::decref, action = block)
|
|
}
|
|
|
|
fun checkNotClosed() {
|
|
if (this._value.value < 0) this.throwClosed()
|
|
}
|
|
|
|
fun decref() {
|
|
this._value.update(Long::dec)
|
|
}
|
|
|
|
fun close(errExistRefs: String) {
|
|
val state = this._value.compareAndExchange(0, -1)
|
|
when {
|
|
state > 0 -> throw IllegalStateException(errExistRefs)
|
|
state < 0 -> this.throwClosed()
|
|
}
|
|
}
|
|
|
|
inline fun <R> withRef(protected: () -> R): R {
|
|
this.incref()
|
|
return safeAutoClose1(finally = this::decref, action = protected)
|
|
}
|
|
|
|
private fun AtomicLong.compareAndExchange(expected: Long, newValue: Long): Long {
|
|
while (true) {
|
|
val old = this@compareAndExchange.value
|
|
if (old != expected) return old
|
|
if (this@compareAndExchange.compareAndSet(old, newValue)) return old
|
|
}
|
|
}
|
|
} |