Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0332e3eef7 | |||
| 4b63563cbd | |||
| 3302c67fa6 | |||
| 5ac9133813 | |||
| 8bf13d0f69 | |||
| 1a26d61cd2 |
@ -15,7 +15,7 @@ buildscript {
|
|||||||
}
|
}
|
||||||
|
|
||||||
group = "ru.landgrafhomyak.utility"
|
group = "ru.landgrafhomyak.utility"
|
||||||
version = "0.3"
|
version = "0.5"
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
|||||||
@ -0,0 +1,19 @@
|
|||||||
|
package ru.landgrafhomyak.utility.reference_counter
|
||||||
|
|
||||||
|
import kotlin.jvm.JvmName
|
||||||
|
|
||||||
|
public class ChildReferenceCounter : MayBeClosedReferenceCounter {
|
||||||
|
private val _parent: MayBeClosedReferenceCounter
|
||||||
|
|
||||||
|
internal constructor(parent: MayBeClosedReferenceCounter, errMessageClosed: String) : super(errMessageClosed) {
|
||||||
|
this._parent = parent
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("INAPPLICABLE_JVM_NAME")
|
||||||
|
@JvmName("close")
|
||||||
|
public override fun close(errExistRefs: String) {
|
||||||
|
this._parent.tryDecref {
|
||||||
|
super.close(errExistRefs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
package ru.landgrafhomyak.utility.reference_counter
|
||||||
|
|
||||||
|
import kotlin.contracts.InvocationKind
|
||||||
|
import kotlin.contracts.contract
|
||||||
|
import kotlin.jvm.JvmName
|
||||||
|
import kotlin.jvm.JvmStatic
|
||||||
|
|
||||||
|
public class CloseableReferenceCounter : MayBeClosedReferenceCounter {
|
||||||
|
public constructor(errMessageClosed: String) : super(errMessageClosed)
|
||||||
|
|
||||||
|
@Suppress("INAPPLICABLE_JVM_NAME")
|
||||||
|
@JvmName("close")
|
||||||
|
public override fun close(errExistRefs: String) {
|
||||||
|
super.close(errExistRefs)
|
||||||
|
}
|
||||||
|
|
||||||
|
public companion object {
|
||||||
|
@Suppress("LEAKED_IN_PLACE_LAMBDA", "WRONG_INVOCATION_KIND")
|
||||||
|
@JvmStatic
|
||||||
|
@JvmName("autoClosed")
|
||||||
|
public fun <R> autoClosed(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")
|
||||||
|
|
||||||
|
val refcnt = CloseableReferenceCounter(errMessageClosed)
|
||||||
|
val ret = scope(refcnt)
|
||||||
|
refcnt.close(errExistRefs)
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,164 @@
|
|||||||
|
@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
|
||||||
|
|
||||||
|
@CloseableReferenceCounter_Debug.RequiresExplicitDebug
|
||||||
|
public class CloseableReferenceCounter_Debug {
|
||||||
|
public fun interface Observer {
|
||||||
|
public fun observeState(instance: CloseableReferenceCounter_Debug, actions: String)
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresOptIn(level = RequiresOptIn.Level.WARNING)
|
||||||
|
@Retention(AnnotationRetention.BINARY)
|
||||||
|
public annotation class RequiresExplicitDebug
|
||||||
|
|
||||||
|
private val _dbgName: String
|
||||||
|
private val _errMessage: String
|
||||||
|
private val _logger: Observer?
|
||||||
|
private val _value: _AtomicLong
|
||||||
|
private val _id: Long
|
||||||
|
|
||||||
|
public constructor(dbgName: String, errMessage: String, logger: Observer? = null) {
|
||||||
|
_Platform.jvm_assertNotNull(dbgName, "param: dbgName")
|
||||||
|
_Platform.jvm_assertNotNull(errMessage, "param: errMessage")
|
||||||
|
|
||||||
|
this._dbgName = dbgName
|
||||||
|
this._errMessage = dbgName
|
||||||
|
this._logger = logger
|
||||||
|
this._value = _AtomicLong(0L)
|
||||||
|
@Suppress("RemoveRedundantQualifierName")
|
||||||
|
this._id = CloseableReferenceCounter_Debug._nextId.getAndUpdate(Long::inc)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
private inline fun _throwErrors(valueToCheck: Long) {
|
||||||
|
when {
|
||||||
|
valueToCheck >= 0 || valueToCheck == _Misc.CLOSED_STATE_VALUE -> {}
|
||||||
|
valueToCheck < _Misc.CLOSED_STATE_VALUE -> throw RuntimeException("Too many references")
|
||||||
|
valueToCheck > _Misc.CLOSED_STATE_VALUE -> throw RuntimeException(".decref called more times than .incref")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresExplicitDebug
|
||||||
|
@JvmName("throwErrors")
|
||||||
|
public fun throwErrors() {
|
||||||
|
this._throwErrors(this._value.get())
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmName("throwClosed")
|
||||||
|
public fun throwClosed() {
|
||||||
|
throw IllegalStateException(this._errMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmName("incref")
|
||||||
|
public fun incref() {
|
||||||
|
this._value.update { o ->
|
||||||
|
if (o < 0) {
|
||||||
|
this._throwErrors(o)
|
||||||
|
this.throwClosed()
|
||||||
|
this._throwErrors(o + 1)
|
||||||
|
}
|
||||||
|
return@update o + 1
|
||||||
|
}
|
||||||
|
this._logger?.observeState(this, "incref")
|
||||||
|
}
|
||||||
|
|
||||||
|
@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 { o ->
|
||||||
|
if (o < 0) {
|
||||||
|
this._throwErrors(o)
|
||||||
|
this.throwClosed()
|
||||||
|
this._throwErrors(o - 1)
|
||||||
|
}
|
||||||
|
return@update o - 1
|
||||||
|
}
|
||||||
|
this._logger?.observeState(this, "decref")
|
||||||
|
}
|
||||||
|
|
||||||
|
@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() {
|
||||||
|
val state = this._value.get()
|
||||||
|
this._throwErrors(state)
|
||||||
|
return state < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmName("close")
|
||||||
|
public fun close(errExistRefs: String) {
|
||||||
|
_Platform.jvm_assertNotNull(errExistRefs, "param: errExistRefs")
|
||||||
|
val state = this._value.compareAndExchange(0, _Misc.CLOSED_STATE_VALUE)
|
||||||
|
this._throwErrors(state)
|
||||||
|
when {
|
||||||
|
state > 0 -> throw IllegalStateException(errExistRefs)
|
||||||
|
state < 0 -> this.throwClosed()
|
||||||
|
}
|
||||||
|
this._logger?.observeState(this, "closed")
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmName("withRef\$kt")
|
||||||
|
public inline fun <R> 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()
|
||||||
|
val stateRepr: String
|
||||||
|
@Suppress("LiftReturnOrAssignment")
|
||||||
|
when {
|
||||||
|
refcntCached >= 0 -> stateRepr = refcntCached.toString()
|
||||||
|
refcntCached == _Misc.CLOSED_STATE_VALUE -> stateRepr = "closed"
|
||||||
|
refcntCached < _Misc.CLOSED_STATE_VALUE -> stateRepr = "overflow"
|
||||||
|
refcntCached > _Misc.CLOSED_STATE_VALUE -> stateRepr = "underflow"
|
||||||
|
else -> throw Error("Unreachable")
|
||||||
|
}
|
||||||
|
return "<ref counter \"${this._dbgName}@${this._id}\" [${stateRepr}]>"
|
||||||
|
}
|
||||||
|
|
||||||
|
public companion object {
|
||||||
|
private val _nextId = _AtomicLong(0L)
|
||||||
|
}
|
||||||
|
|
||||||
|
public object ObserveToStdout : Observer {
|
||||||
|
override fun observeState(instance: CloseableReferenceCounter_Debug, actions: String) {
|
||||||
|
_Platform.jvm_assertNotNull(instance, "param: instance")
|
||||||
|
_Platform.jvm_assertNotNull(actions, "param: actions")
|
||||||
|
print("${instance} ${actions}\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,145 @@
|
|||||||
|
@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 <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 {
|
||||||
|
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 "<ref counter [closed]>"
|
||||||
|
else
|
||||||
|
return "<ref counter [${refcntCached}]>"
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("LEAKED_IN_PLACE_LAMBDA", "WRONG_INVOCATION_KIND")
|
||||||
|
@JvmName("child")
|
||||||
|
public fun <R> 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 <R> 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package ru.landrafhomyak.utility.reference_counter
|
package ru.landgrafhomyak.utility.reference_counter
|
||||||
|
|
||||||
internal expect class _AtomicLong {
|
internal expect class _AtomicLong {
|
||||||
constructor(initial: Long)
|
constructor(initial: Long)
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package ru.landrafhomyak.utility.reference_counter
|
package ru.landgrafhomyak.utility.reference_counter
|
||||||
|
|
||||||
import kotlin.jvm.JvmStatic
|
import kotlin.jvm.JvmStatic
|
||||||
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package ru.landrafhomyak.utility.reference_counter
|
package ru.landgrafhomyak.utility.reference_counter
|
||||||
|
|
||||||
import kotlin.jvm.JvmStatic
|
import kotlin.jvm.JvmStatic
|
||||||
|
|
||||||
@ -1,29 +1,37 @@
|
|||||||
package ru.landrafhomyak.utility.reference_counter
|
package ru.landrafhomyak.utility.reference_counter
|
||||||
|
|
||||||
|
import kotlin.contracts.InvocationKind
|
||||||
|
import kotlin.contracts.contract
|
||||||
import kotlin.jvm.JvmName
|
import kotlin.jvm.JvmName
|
||||||
import kotlin.jvm.JvmStatic
|
import kotlin.jvm.JvmStatic
|
||||||
|
import ru.landgrafhomyak.utility.reference_counter._Platform
|
||||||
|
import ru.landgrafhomyak.utility.reference_counter.CloseableReferenceCounter as moved_CloseableReferenceCounter
|
||||||
|
|
||||||
|
@Suppress("DEPRECATION_ERROR")
|
||||||
|
@Deprecated(
|
||||||
|
message = "Class moved to another package",
|
||||||
|
level = DeprecationLevel.ERROR
|
||||||
|
)
|
||||||
public class CloseableReferenceCounter : MayBeClosedReferenceCounter {
|
public class CloseableReferenceCounter : MayBeClosedReferenceCounter {
|
||||||
public constructor(errMessageClosed: String) : super(errMessageClosed)
|
public constructor(errMessageClosed: String) : super(moved_CloseableReferenceCounter(errMessageClosed))
|
||||||
|
|
||||||
@Suppress("INAPPLICABLE_JVM_NAME")
|
@Suppress("INAPPLICABLE_JVM_NAME", "NON_FINAL_MEMBER_IN_FINAL_CLASS")
|
||||||
@JvmName("close")
|
@JvmName("close")
|
||||||
public override fun close(errExistRefs: String) {
|
public open fun close(errExistRefs: String) {
|
||||||
super.close(errExistRefs)
|
(this._moved as moved_CloseableReferenceCounter).close(errExistRefs)
|
||||||
}
|
}
|
||||||
|
|
||||||
public companion object {
|
public companion object {
|
||||||
|
@Suppress("LEAKED_IN_PLACE_LAMBDA", "WRONG_INVOCATION_KIND")
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@JvmName("autoClosed")
|
@JvmName("autoClosed")
|
||||||
public fun <R> autoClosed(errMessageClosed: String, errExistRefs: String, scope: (MayBeClosedReferenceCounter) -> R): R {
|
public fun <R> autoClosed(errMessageClosed: String, errExistRefs: String, scope: (MayBeClosedReferenceCounter) -> R): R {
|
||||||
_Platform.jvm_assertNotNull(errMessageClosed, "param: errMessageClosed")
|
contract {
|
||||||
_Platform.jvm_assertNotNull(errExistRefs, "param: errExistRefs")
|
callsInPlace(scope, InvocationKind.EXACTLY_ONCE)
|
||||||
|
}
|
||||||
_Platform.jvm_assertNotNull(scope, "param: scope")
|
_Platform.jvm_assertNotNull(scope, "param: scope")
|
||||||
|
|
||||||
val refcnt = CloseableReferenceCounter(errMessageClosed)
|
return moved_CloseableReferenceCounter.autoClosed(errMessageClosed, errExistRefs, WrapperReferenceCounter.wrapperLambda(scope))
|
||||||
val ret = scope(refcnt)
|
|
||||||
refcnt.close(errExistRefs)
|
|
||||||
return ret
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5,70 +5,57 @@ package ru.landrafhomyak.utility.reference_counter
|
|||||||
import kotlin.contracts.ExperimentalContracts
|
import kotlin.contracts.ExperimentalContracts
|
||||||
import kotlin.contracts.InvocationKind
|
import kotlin.contracts.InvocationKind
|
||||||
import kotlin.contracts.contract
|
import kotlin.contracts.contract
|
||||||
|
import kotlin.jvm.JvmField
|
||||||
import kotlin.jvm.JvmName
|
import kotlin.jvm.JvmName
|
||||||
import ru.landgrafhomyak.utility.highlevel_try_finally.safeAutoClose1
|
import ru.landgrafhomyak.utility.reference_counter.CloseableReferenceCounter_Debug as moved_CloseableReferenceCounter_Debug
|
||||||
import ru.landgrafhomyak.utility.highlevel_try_finally.safeAutoClose2
|
|
||||||
|
|
||||||
|
@Suppress("DEPRECATION_ERROR")
|
||||||
|
@Deprecated(
|
||||||
|
message = "Class moved to another package",
|
||||||
|
level = DeprecationLevel.ERROR
|
||||||
|
)
|
||||||
|
@OptIn(moved_CloseableReferenceCounter_Debug.RequiresExplicitDebug::class)
|
||||||
@CloseableReferenceCounter_Debug.RequiresExplicitDebug
|
@CloseableReferenceCounter_Debug.RequiresExplicitDebug
|
||||||
public class CloseableReferenceCounter_Debug {
|
public class CloseableReferenceCounter_Debug {
|
||||||
public fun interface Observer {
|
public fun interface Observer {
|
||||||
public fun observeState(instance: CloseableReferenceCounter_Debug, actions: String)
|
public fun observeState(instance: CloseableReferenceCounter_Debug, actions: String)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ObserverAdapter(private val old: Observer) : moved_CloseableReferenceCounter_Debug.Observer {
|
||||||
|
lateinit var wrapper: CloseableReferenceCounter_Debug
|
||||||
|
override fun observeState(instance: moved_CloseableReferenceCounter_Debug, actions: String) {
|
||||||
|
this.old.observeState(this.wrapper, actions)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@RequiresOptIn(level = RequiresOptIn.Level.WARNING)
|
@RequiresOptIn(level = RequiresOptIn.Level.WARNING)
|
||||||
@Retention(AnnotationRetention.BINARY)
|
@Retention(AnnotationRetention.BINARY)
|
||||||
public annotation class RequiresExplicitDebug
|
public annotation class RequiresExplicitDebug
|
||||||
|
|
||||||
private val _dbgName: String
|
@PublishedApi
|
||||||
private val _errMessage: String
|
@JvmField
|
||||||
private val _logger: Observer?
|
internal val _moved: moved_CloseableReferenceCounter_Debug
|
||||||
private val _value: _AtomicLong
|
|
||||||
private val _id: Long
|
|
||||||
|
|
||||||
public constructor(dbgName: String, errMessage: String, logger: Observer? = null) {
|
public constructor(dbgName: String, errMessage: String, logger: Observer? = null) {
|
||||||
_Platform.jvm_assertNotNull(dbgName, "param: dbgName")
|
val obs = logger?.let(::ObserverAdapter)
|
||||||
_Platform.jvm_assertNotNull(errMessage, "param: errMessage")
|
this._moved = moved_CloseableReferenceCounter_Debug(dbgName, errMessage, obs)
|
||||||
|
obs?.wrapper = this
|
||||||
this._dbgName = dbgName
|
|
||||||
this._errMessage = dbgName
|
|
||||||
this._logger = logger
|
|
||||||
this._value = _AtomicLong(0L)
|
|
||||||
@Suppress("RemoveRedundantQualifierName")
|
|
||||||
this._id = CloseableReferenceCounter_Debug._nextId.getAndUpdate(Long::inc)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Suppress("NOTHING_TO_INLINE")
|
|
||||||
private inline fun _throwErrors(valueToCheck: Long) {
|
|
||||||
when {
|
|
||||||
valueToCheck >= 0 || valueToCheck == _Misc.CLOSED_STATE_VALUE -> {}
|
|
||||||
valueToCheck < _Misc.CLOSED_STATE_VALUE -> throw RuntimeException("Too many references")
|
|
||||||
valueToCheck > _Misc.CLOSED_STATE_VALUE -> throw RuntimeException(".decref called more times than .incref")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresExplicitDebug
|
@RequiresExplicitDebug
|
||||||
@JvmName("throwErrors")
|
@JvmName("throwErrors")
|
||||||
public fun throwErrors() {
|
public fun throwErrors() {
|
||||||
this._throwErrors(this._value.get())
|
this._moved.throwErrors()
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmName("throwClosed")
|
@JvmName("throwClosed")
|
||||||
public fun throwClosed() {
|
public fun throwClosed() {
|
||||||
throw IllegalStateException(this._errMessage)
|
this._moved.throwClosed()
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmName("incref")
|
@JvmName("incref")
|
||||||
public fun incref() {
|
public fun incref() {
|
||||||
this._value.update { o ->
|
this._moved.incref()
|
||||||
if (o < 0) {
|
|
||||||
this._throwErrors(o)
|
|
||||||
this.throwClosed()
|
|
||||||
this._throwErrors(o + 1)
|
|
||||||
}
|
|
||||||
return@update o + 1
|
|
||||||
}
|
|
||||||
this._logger?.observeState(this, "incref")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmName("tryIncref\$kt")
|
@JvmName("tryIncref\$kt")
|
||||||
@ -76,26 +63,17 @@ public class CloseableReferenceCounter_Debug {
|
|||||||
contract {
|
contract {
|
||||||
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
|
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
|
||||||
}
|
}
|
||||||
this.incref()
|
return this._moved.tryIncref(block)
|
||||||
return safeAutoClose2(onError = this::decref, action = block)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmName("assertNotClosed")
|
@JvmName("assertNotClosed")
|
||||||
public fun assertNotClosed() {
|
public fun assertNotClosed() {
|
||||||
if (this._value.get() < 0) this.throwClosed()
|
this._moved.assertNotClosed()
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmName("decref")
|
@JvmName("decref")
|
||||||
public fun decref() {
|
public fun decref() {
|
||||||
this._value.update { o ->
|
this._moved.decref()
|
||||||
if (o < 0) {
|
|
||||||
this._throwErrors(o)
|
|
||||||
this.throwClosed()
|
|
||||||
this._throwErrors(o - 1)
|
|
||||||
}
|
|
||||||
return@update o - 1
|
|
||||||
}
|
|
||||||
this._logger?.observeState(this, "decref")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmName("tryDecref\$kt")
|
@JvmName("tryDecref\$kt")
|
||||||
@ -103,59 +81,34 @@ public class CloseableReferenceCounter_Debug {
|
|||||||
contract {
|
contract {
|
||||||
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
|
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
|
||||||
}
|
}
|
||||||
this.assertNotClosed()
|
return this._moved.tryDecref(block)
|
||||||
return safeAutoClose2(onSuccess = this::decref, action = block)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@get:JvmName("isClosed")
|
@get:JvmName("isClosed")
|
||||||
public val isClosed: Boolean
|
public val isClosed: Boolean
|
||||||
get() {
|
get() = this._moved.isClosed
|
||||||
val state = this._value.get()
|
|
||||||
this._throwErrors(state)
|
|
||||||
return state < 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@JvmName("close")
|
@JvmName("close")
|
||||||
public fun close(errExistRefs: String) {
|
public fun close(errExistRefs: String) {
|
||||||
_Platform.jvm_assertNotNull(errExistRefs, "param: errExistRefs")
|
this._moved.close(errExistRefs)
|
||||||
val state = this._value.compareAndExchange(0, _Misc.CLOSED_STATE_VALUE)
|
|
||||||
this._throwErrors(state)
|
|
||||||
when {
|
|
||||||
state > 0 -> throw IllegalStateException(errExistRefs)
|
|
||||||
state < 0 -> this.throwClosed()
|
|
||||||
}
|
|
||||||
this._logger?.observeState(this, "closed")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmName("withRef\$kt")
|
@JvmName("withRef\$kt")
|
||||||
public inline fun <R> withRef(protected: () -> R): R {
|
public inline fun <R> withRef(protected: () -> R): R {
|
||||||
this.incref()
|
contract {
|
||||||
return safeAutoClose1(finally = this::decref, action = protected)
|
callsInPlace(protected, InvocationKind.EXACTLY_ONCE)
|
||||||
|
}
|
||||||
|
return this._moved.withRef(protected)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
val refcntCached = this._value.get()
|
val orig = this._moved.toString()
|
||||||
val stateRepr: String
|
return orig.substring(0, orig.length - 1) + " !deprecated class used!>"
|
||||||
@Suppress("LiftReturnOrAssignment")
|
|
||||||
when {
|
|
||||||
refcntCached >= 0 -> stateRepr = refcntCached.toString()
|
|
||||||
refcntCached == _Misc.CLOSED_STATE_VALUE -> stateRepr = "closed"
|
|
||||||
refcntCached < _Misc.CLOSED_STATE_VALUE -> stateRepr = "overflow"
|
|
||||||
refcntCached > _Misc.CLOSED_STATE_VALUE -> stateRepr = "underflow"
|
|
||||||
else -> throw Error("Unreachable")
|
|
||||||
}
|
|
||||||
return "<ref counter \"${this._dbgName}@${this._id}\" [${stateRepr}]>"
|
|
||||||
}
|
|
||||||
|
|
||||||
public companion object {
|
|
||||||
private val _nextId = _AtomicLong(0L)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public object ObserveToStdout : Observer {
|
public object ObserveToStdout : Observer {
|
||||||
override fun observeState(instance: CloseableReferenceCounter_Debug, actions: String) {
|
override fun observeState(instance: CloseableReferenceCounter_Debug, actions: String) {
|
||||||
_Platform.jvm_assertNotNull(instance, "param: instance")
|
moved_CloseableReferenceCounter_Debug.ObserveToStdout.observeState(instance._moved, actions)
|
||||||
_Platform.jvm_assertNotNull(actions, "param: actions")
|
|
||||||
print("${instance} ${actions}\n")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5,31 +5,36 @@ package ru.landrafhomyak.utility.reference_counter
|
|||||||
import kotlin.contracts.ExperimentalContracts
|
import kotlin.contracts.ExperimentalContracts
|
||||||
import kotlin.contracts.InvocationKind
|
import kotlin.contracts.InvocationKind
|
||||||
import kotlin.contracts.contract
|
import kotlin.contracts.contract
|
||||||
|
import kotlin.jvm.JvmField
|
||||||
import kotlin.jvm.JvmName
|
import kotlin.jvm.JvmName
|
||||||
import ru.landgrafhomyak.utility.highlevel_try_finally.safeAutoClose1
|
import ru.landgrafhomyak.utility.reference_counter._Platform
|
||||||
import ru.landgrafhomyak.utility.highlevel_try_finally.safeAutoClose2
|
import ru.landgrafhomyak.utility.reference_counter.MayBeClosedReferenceCounter as moved_MayBeClosedReferenceCounter
|
||||||
|
|
||||||
|
@Deprecated(
|
||||||
|
message = "Class moved to another package",
|
||||||
|
/*replaceWith = ReplaceWith(
|
||||||
|
imports = ["ru.landgrafhomyak.utility.reference_counter.MayBeClosedReferenceCounter"],
|
||||||
|
expression = "MayBeClosedReferenceCounter"
|
||||||
|
),*/
|
||||||
|
level = DeprecationLevel.ERROR
|
||||||
|
)
|
||||||
public sealed class MayBeClosedReferenceCounter {
|
public sealed class MayBeClosedReferenceCounter {
|
||||||
private val _value: _AtomicLong
|
@PublishedApi
|
||||||
private val _errMessageClosed: String
|
@JvmField
|
||||||
|
internal val _moved: moved_MayBeClosedReferenceCounter
|
||||||
|
|
||||||
protected constructor(errMessageClosed: String) {
|
protected constructor(moved: moved_MayBeClosedReferenceCounter) {
|
||||||
_Platform.jvm_assertNotNull(errMessageClosed, "param: errMessageClosed")
|
this._moved = moved
|
||||||
this._errMessageClosed = errMessageClosed
|
|
||||||
this._value = _AtomicLong(0L)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmName("throwClosed")
|
@JvmName("throwClosed")
|
||||||
public fun throwClosed() {
|
public fun throwClosed() {
|
||||||
throw IllegalStateException(this._errMessageClosed)
|
this._moved.throwClosed()
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmName("incref")
|
@JvmName("incref")
|
||||||
public fun incref() {
|
public fun incref() {
|
||||||
this._value.update { o ->
|
this._moved.incref()
|
||||||
if (o < 0) this.throwClosed()
|
|
||||||
return@update o + 1
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmName("tryIncref\$kt")
|
@JvmName("tryIncref\$kt")
|
||||||
@ -37,18 +42,17 @@ public sealed class MayBeClosedReferenceCounter {
|
|||||||
contract {
|
contract {
|
||||||
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
|
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
|
||||||
}
|
}
|
||||||
this.incref()
|
return this._moved.tryIncref(block)
|
||||||
return safeAutoClose2(onError = this::decref, action = block)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmName("assertNotClosed")
|
@JvmName("assertNotClosed")
|
||||||
public fun assertNotClosed() {
|
public fun assertNotClosed() {
|
||||||
if (this._value.get() < 0) this.throwClosed()
|
this._moved.assertNotClosed()
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmName("decref")
|
@JvmName("decref")
|
||||||
public fun decref() {
|
public fun decref() {
|
||||||
this._value.update(Long::dec)
|
this._moved.decref()
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmName("tryDecref\$kt")
|
@JvmName("tryDecref\$kt")
|
||||||
@ -56,36 +60,49 @@ public sealed class MayBeClosedReferenceCounter {
|
|||||||
contract {
|
contract {
|
||||||
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
|
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
|
||||||
}
|
}
|
||||||
this.assertNotClosed()
|
return this._moved.tryDecref(block)
|
||||||
return safeAutoClose2(onSuccess = this::decref, action = block)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@get:JvmName("isClosed")
|
@get:JvmName("isClosed")
|
||||||
public val isClosed: Boolean get() = this._value.get() < 0
|
public val isClosed: Boolean get() =
|
||||||
|
this._moved.isClosed
|
||||||
@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")
|
@JvmName("withRef\$kt")
|
||||||
public inline fun <R> withRef(protected: () -> R): R {
|
public inline fun <R> withRef(protected: () -> R): R {
|
||||||
this.incref()
|
contract {
|
||||||
return safeAutoClose1(finally = this::decref, action = protected)
|
callsInPlace(protected, InvocationKind.EXACTLY_ONCE)
|
||||||
|
}
|
||||||
|
return this._moved.withRef(protected)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
val refcntCached = this._value.get()
|
val orig = this._moved.toString()
|
||||||
@Suppress("LiftReturnOrAssignment")
|
return orig.substring(0, orig.length - 1) + " !deprecated class used!>"
|
||||||
if (refcntCached < 0)
|
}
|
||||||
return "<ref counter [closed]>"
|
|
||||||
else
|
@Suppress("LEAKED_IN_PLACE_LAMBDA", "WRONG_INVOCATION_KIND", "DEPRECATION_ERROR")
|
||||||
return "<ref counter [${refcntCached}]>"
|
@JvmName("child")
|
||||||
|
public fun <R> 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")
|
||||||
|
|
||||||
|
return this._moved.child(errMessageClosed, errExistRefs, WrapperReferenceCounter.wrapperLambda(scope))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("LEAKED_IN_PLACE_LAMBDA", "WRONG_INVOCATION_KIND", "DEPRECATION_ERROR")
|
||||||
|
@JvmName("child_inheritErrMessage")
|
||||||
|
public fun <R> child_inheritErrMessage(errExistRefs: String, scope: (MayBeClosedReferenceCounter) -> R): R {
|
||||||
|
contract {
|
||||||
|
callsInPlace(scope, InvocationKind.EXACTLY_ONCE)
|
||||||
|
}
|
||||||
|
|
||||||
|
_Platform.jvm_assertNotNull(scope, "param: scope")
|
||||||
|
|
||||||
|
return this._moved.child_inheritErrMessage(errExistRefs, WrapperReferenceCounter.wrapperLambda(scope))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
package ru.landrafhomyak.utility.reference_counter
|
||||||
|
|
||||||
|
import kotlin.jvm.JvmStatic
|
||||||
|
import ru.landgrafhomyak.utility.reference_counter.MayBeClosedReferenceCounter as moved_MayBeClosedReferenceCounter
|
||||||
|
|
||||||
|
@Suppress("DEPRECATION_ERROR")
|
||||||
|
@Deprecated(
|
||||||
|
message = "Utility class for deprecated refcounters",
|
||||||
|
level = DeprecationLevel.ERROR
|
||||||
|
)
|
||||||
|
internal class WrapperReferenceCounter : MayBeClosedReferenceCounter {
|
||||||
|
constructor(refcnt: moved_MayBeClosedReferenceCounter) : super(refcnt)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@JvmStatic
|
||||||
|
fun <R> wrapperLambda(old: (MayBeClosedReferenceCounter) -> R): (moved_MayBeClosedReferenceCounter) -> R {
|
||||||
|
return w@{ moved -> return@w old(WrapperReferenceCounter(moved)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package ru.landrafhomyak.utility.reference_counter
|
package ru.landgrafhomyak.utility.reference_counter
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicLong
|
import java.util.concurrent.atomic.AtomicLong
|
||||||
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package ru.landrafhomyak.utility.reference_counter
|
package ru.landgrafhomyak.utility.reference_counter
|
||||||
|
|
||||||
import java.util.Objects
|
import java.util.Objects
|
||||||
import kotlin.contracts.contract
|
import kotlin.contracts.contract
|
||||||
@ -1,11 +1,11 @@
|
|||||||
package ru.landrafhomyak.utility.reference_counter.tests
|
package ru.landgrafhomyak.utility.reference_counter.tests
|
||||||
|
|
||||||
import java.lang.AssertionError
|
import java.lang.AssertionError
|
||||||
import org.testng.annotations.Test
|
import org.testng.annotations.Test
|
||||||
import org.testng.asserts.Assertion
|
import org.testng.asserts.Assertion
|
||||||
import ru.landgrafhomyak.utility.highlevel_try_finally.safeAutoClose1
|
import ru.landgrafhomyak.utility.highlevel_try_finally.safeAutoClose1
|
||||||
import ru.landrafhomyak.utility.reference_counter.CloseableReferenceCounter
|
import ru.landgrafhomyak.utility.reference_counter.CloseableReferenceCounter
|
||||||
import ru.landrafhomyak.utility.reference_counter.CloseableReferenceCounter_Debug
|
import ru.landgrafhomyak.utility.reference_counter.CloseableReferenceCounter_Debug
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
class KotlinStdlibDependencyTest {
|
class KotlinStdlibDependencyTest {
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package ru.landrafhomyak.utility.reference_counter
|
package ru.landgrafhomyak.utility.reference_counter
|
||||||
|
|
||||||
import kotlinx.atomicfu.AtomicLong
|
import kotlinx.atomicfu.AtomicLong
|
||||||
import kotlinx.atomicfu.atomic
|
import kotlinx.atomicfu.atomic
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package ru.landrafhomyak.utility.reference_counter
|
package ru.landgrafhomyak.utility.reference_counter
|
||||||
|
|
||||||
|
|
||||||
@PublishedApi
|
@PublishedApi
|
||||||
Loading…
Reference in New Issue
Block a user