'close' method moved to separate class; autoClosed scope

This commit is contained in:
Andrew Golovashevich 2025-08-13 14:23:56 +03:00
parent d5ed25cb54
commit 140b463ce8
3 changed files with 113 additions and 82 deletions

1
.gitignore vendored
View File

@ -7,3 +7,4 @@ build/
/out/ /out/
/gradlew* /gradlew*
.kotlin/ .kotlin/
/kotlin-js-store

View File

@ -1,90 +1,29 @@
@file:OptIn(ExperimentalContracts::class)
package ru.landrafhomyak.utility.reference_counter package ru.landrafhomyak.utility.reference_counter
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
import kotlin.jvm.JvmName import kotlin.jvm.JvmName
import ru.landgrafhomyak.utility.highlevel_try_finally.safeAutoClose1 import kotlin.jvm.JvmStatic
import ru.landgrafhomyak.utility.highlevel_try_finally.safeAutoClose2
public class CloseableReferenceCounter { public class CloseableReferenceCounter : MayBeClosedReferenceCounter {
private val _value: _AtomicLong public constructor(errMessageClosed: String) : super(errMessageClosed)
private val _errMessageClosed: String
public 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") @JvmName("close")
public fun close(errExistRefs: String) { public override fun close(errExistRefs: String) {
super.close(errExistRefs)
}
public companion object {
@JvmStatic
@JvmName("autoClosed")
public fun <R> autoClosed(errMessageClosed: String, errExistRefs: String, scope: (MayBeClosedReferenceCounter) -> R): R {
_Platform.jvm_assertNotNull(errMessageClosed, "param: errMessageClosed")
_Platform.jvm_assertNotNull(errExistRefs, "param: errExistRefs") _Platform.jvm_assertNotNull(errExistRefs, "param: errExistRefs")
val state = this._value.compareAndExchange(0, _Misc.CLOSED_STATE_VALUE) _Platform.jvm_assertNotNull(scope, "param: scope")
when {
state > 0 -> throw IllegalStateException(errExistRefs)
state < 0 -> this.throwClosed()
}
}
@JvmName("withRef\$kt") val refcnt = CloseableReferenceCounter(errMessageClosed)
public inline fun <R> withRef(protected: () -> R): R { val ret = scope(refcnt)
this.incref() refcnt.close(errExistRefs)
return safeAutoClose1(finally = this::decref, action = protected) return ret
} }
override fun toString(): String {
val refcntCached = this._value.get()
@Suppress("LiftReturnOrAssignment")
if (refcntCached < 0)
return "<ref counter [closed]>"
else
return "<ref counter [${refcntCached}]>"
} }
} }

View File

@ -0,0 +1,91 @@
@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}]>"
}
}