@file:OptIn(ExperimentalContracts::class) package ru.landgrafhomyak.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 { contract { callsInPlace(protected, InvocationKind.EXACTLY_ONCE) } 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 "" } @Suppress("LEAKED_IN_PLACE_LAMBDA", "WRONG_INVOCATION_KIND") @JvmName("child") public fun child(errMessageClosed: String, errExistRefs: String, scope: (MayBeClosedReferenceCounter) -> R): R { contract { callsInPlace(scope, InvocationKind.EXACTLY_ONCE) } _Platform.jvm_assertNotNull(errMessageClosed, "param: errMessageClosed") _Platform.jvm_assertNotNull(errExistRefs, "param: errExistRefs") _Platform.jvm_assertNotNull(scope, "param: scope") this.withRef { return CloseableReferenceCounter.autoClosed( errMessageClosed = errMessageClosed, errExistRefs = errExistRefs, scope = scope ) } } @JvmName("newChild") public fun newChild(errMessageClosed: String): ChildReferenceCounter { _Platform.jvm_assertNotNull(errMessageClosed, "param: errMessageClosed") this.tryIncref { return ChildReferenceCounter(this, errMessageClosed) } } @Suppress("LEAKED_IN_PLACE_LAMBDA", "WRONG_INVOCATION_KIND") @JvmName("child_inheritErrMessage") public fun child_inheritErrMessage(errExistRefs: String, scope: (MayBeClosedReferenceCounter) -> R): R { contract { callsInPlace(scope, InvocationKind.EXACTLY_ONCE) } _Platform.jvm_assertNotNull(errExistRefs, "param: errExistRefs") _Platform.jvm_assertNotNull(scope, "param: scope") return this.child( errMessageClosed = this._errMessageClosed, errExistRefs = errExistRefs, scope = scope ) } @JvmName("newChild_inheritErrMessage") public fun newChild_inheritErrMessage(): ChildReferenceCounter { return this.newChild(this._errMessageClosed) } }