reference-counter.kt/src/commonMain/kotlin/ru/landrafhomyak/utility/reference_counter/MayBeClosedReferenceCounter.kt

91 lines
2.4 KiB
Kotlin

@file:OptIn(ExperimentalContracts::class)
package ru.landrafhomyak.utility.reference_counter
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
import kotlin.jvm.JvmName
import ru.landgrafhomyak.utility.highlevel_try_finally.safeAutoClose1
import ru.landgrafhomyak.utility.highlevel_try_finally.safeAutoClose2
public sealed class MayBeClosedReferenceCounter {
private val _value: _AtomicLong
private val _errMessageClosed: String
protected constructor(errMessageClosed: String) {
_Platform.jvm_assertNotNull(errMessageClosed, "param: errMessageClosed")
this._errMessageClosed = errMessageClosed
this._value = _AtomicLong(0L)
}
@JvmName("throwClosed")
public fun throwClosed() {
throw IllegalStateException(this._errMessageClosed)
}
@JvmName("incref")
public fun incref() {
this._value.update { o ->
if (o < 0) this.throwClosed()
return@update o + 1
}
}
@JvmName("tryIncref\$kt")
public inline fun <R> tryIncref(block: () -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
this.incref()
return safeAutoClose2(onError = this::decref, action = block)
}
@JvmName("assertNotClosed")
public fun assertNotClosed() {
if (this._value.get() < 0) this.throwClosed()
}
@JvmName("decref")
public fun decref() {
this._value.update(Long::dec)
}
@JvmName("tryDecref\$kt")
public inline fun <R> tryDecref(block: () -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
this.assertNotClosed()
return safeAutoClose2(onSuccess = this::decref, action = block)
}
@get:JvmName("isClosed")
public val isClosed: Boolean get() = this._value.get() < 0
@Suppress("INAPPLICABLE_JVM_NAME")
@JvmName("close")
protected open fun close(errExistRefs: String) {
_Platform.jvm_assertNotNull(errExistRefs, "param: errExistRefs")
val state = this._value.compareAndExchange(0, _Misc.CLOSED_STATE_VALUE)
when {
state > 0 -> throw IllegalStateException(errExistRefs)
state < 0 -> this.throwClosed()
}
}
@JvmName("withRef\$kt")
public inline fun <R> withRef(protected: () -> R): R {
this.incref()
return safeAutoClose1(finally = this::decref, action = protected)
}
override fun toString(): String {
val refcntCached = this._value.get()
@Suppress("LiftReturnOrAssignment")
if (refcntCached < 0)
return "<ref counter [closed]>"
else
return "<ref counter [${refcntCached}]>"
}
}