@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 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 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 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 "" else return "" } }