Unified all classes to common interface

This commit is contained in:
Andrew Golovashevich 2025-08-22 02:47:45 +03:00
parent 0332e3eef7
commit d4db1907d9
30 changed files with 592 additions and 839 deletions

View File

@ -0,0 +1,72 @@
package ru.landgrafhomyak.utility.closeable_state
import kotlin.jvm.JvmField
public sealed class ChildCloseableState<T : CloseableState> : CloseableState {
@JvmField
protected val _parent: CloseableState
@JvmField
protected val _state: T
protected constructor(parent: CloseableState, state: T) {
this._parent = parent
this._state = state
}
override fun throwClosed(): Nothing =
this._state.throwClosed()
override fun throwInUse(): Nothing =
this._state.throwInUse()
override fun assertNotClosed(): Unit =
this._state.assertNotClosed()
override val isClosed: Boolean
get() = this._state.isClosed
@ManualStateManipulation
override fun startUsage(): Unit =
this._state.startUsage()
@ManualStateManipulation
override fun finishUsage(): Unit =
this._state.finishUsage()
@ManualStateManipulation
override fun close() {
this._parent.tryFinishUsage {
this._state.finishUsage()
}
}
abstract override fun toString(): String
public class AllowsConcurrency : ChildCloseableState<CloseableState.AllowsConcurrency>, CloseableState.AllowsConcurrency {
public constructor(parent: CloseableState, state: CloseableState.AllowsConcurrency) : super(parent, state)
override fun toString(): String {
when {
this._state is OwnedUsagesCounter || this._state::class === UsagesCounter::class -> {
val base = this._state.toString()
return base.substring(0, base.length - 1) + " (child of ${this._parent})>"
}
else -> return "<child closeable state ${this._state} (parent if ${this._parent})>"
}
}
}
public class ExternallySynchronized : ChildCloseableState<CloseableState.ExternallySynchronized>, CloseableState.ExternallySynchronized {
public constructor(parent: CloseableState, state: CloseableState.ExternallySynchronized) : super(parent, state)
override val isInUse: Boolean
get() = this._state.isInUse
override fun toString(): String {
TODO("Not yet implemented")
}
}
}

View File

@ -0,0 +1,27 @@
package ru.landgrafhomyak.utility.closeable_state
public interface CloseableState : AutoCloseable {
public fun throwClosed(): Nothing
public fun throwInUse(): Nothing
public fun assertNotClosed()
public val isClosed: Boolean
@ManualStateManipulation
public fun startUsage()
@ManualStateManipulation
public fun finishUsage()
@ManualStateManipulation
public override fun close()
public interface AllowsConcurrency : CloseableState {
}
public interface ExternallySynchronized : CloseableState {
public val isInUse: Boolean
}
}

View File

@ -0,0 +1,70 @@
package ru.landgrafhomyak.utility.closeable_state
import ru.landgrafhomyak.utility.closeable_state.internal.AtomicReference
public open class ErrorOnConcurrentAccessState : CloseableState.ExternallySynchronized {
private enum class State {
OPEN, IN_USE, CLOSED
}
private val _state = AtomicReference(State.OPEN)
final override val isInUse: Boolean
get() = this._state.get() === State.IN_USE
open override fun throwClosed(): Nothing {
throw IllegalStateException("Object is closed")
}
open override fun throwInUse(): Nothing {
throw IllegalStateException("Failed close object because it is in use")
}
public open fun throwConcurrent(): Nothing {
throw IllegalStateException("Object is in use by another thread")
}
final override fun assertNotClosed() {
if (this._state.get() === State.CLOSED)
this.throwClosed()
}
final override val isClosed: Boolean
get() = this._state.get() === State.CLOSED
@ManualStateManipulation
final override fun startUsage() {
when (this._state.compareAndExchange(State.OPEN, State.IN_USE)) {
State.OPEN -> {}
State.IN_USE -> this.throwConcurrent()
State.CLOSED -> this.throwClosed()
}
}
@ManualStateManipulation
override fun finishUsage() {
when (this._state.compareAndExchange(State.IN_USE, State.OPEN)) {
State.OPEN -> throw IllegalStateException("Can't finish usage because not it not started")
State.IN_USE -> {}
State.CLOSED -> this.throwClosed()
}
}
@ManualStateManipulation
override fun close() {
when (this._state.compareAndExchange(State.OPEN, State.CLOSED)) {
State.OPEN -> {}
State.IN_USE -> this.throwConcurrent()
State.CLOSED -> this.throwClosed()
}
}
override fun toString(): String =
when (this._state.get()) {
State.OPEN -> "<closeable error-on-concurrent-access state [free]>"
State.IN_USE -> "<closeable error-on-concurrent-access state [in use]>"
State.CLOSED -> "<closeable error-on-concurrent-access state [close]>"
}
}

View File

@ -0,0 +1,7 @@
package ru.landgrafhomyak.utility.closeable_state
@RequiresOptIn(
message = "Manual state control is unsafe, are you sure to do this",
level = RequiresOptIn.Level.ERROR
)
public annotation class ManualStateManipulation

View File

@ -0,0 +1,30 @@
@file:OptIn(ExperimentalContracts::class)
package ru.landgrafhomyak.utility.closeable_state
import kotlin.contracts.ExperimentalContracts
public class OwnedErrorOnConcurrentAccesState : ErrorOnConcurrentAccessState {
public val _owner: Any
public constructor(owner: Any) : super() {
this._owner = owner
}
override fun throwClosed(): Nothing {
throw IllegalStateException("Object is closed: ${this._owner}")
}
override fun throwInUse(): Nothing {
throw IllegalStateException("Failed close object because it is in use: ${this._owner}")
}
override fun throwConcurrent(): Nothing {
throw IllegalStateException("Object is in use by another thread: ${this._owner}")
}
override fun toString(): String {
val base = super.toString()
return base.substring(0, base.length - 1) + " of ${this._owner}>"
}
}

View File

@ -0,0 +1,26 @@
@file:OptIn(ExperimentalContracts::class)
package ru.landgrafhomyak.utility.closeable_state
import kotlin.contracts.ExperimentalContracts
public class OwnedUsagesCounter : UsagesCounter {
public val _owner: Any
public constructor(owner: Any) : super() {
this._owner = owner
}
override fun throwClosed(): Nothing {
throw IllegalStateException("Object is closed: ${this._owner}")
}
override fun throwInUse(): Nothing {
throw IllegalStateException("Failed close object because it is in use: ${this._owner}")
}
override fun toString(): String {
val base = super.toString()
return base.substring(0, base.length - 1) + " of ${this._owner}>"
}
}

View File

@ -0,0 +1,61 @@
@file:OptIn(ExperimentalContracts::class)
package ru.landgrafhomyak.utility.closeable_state
import kotlin.contracts.ExperimentalContracts
import ru.landgrafhomyak.utility.closeable_state.internal.AtomicLong
import ru.landgrafhomyak.utility.closeable_state.internal.Misc
public open class UsagesCounter : CloseableState.AllowsConcurrency {
private val _value: AtomicLong = AtomicLong(0L)
public constructor()
public fun getCurrentUsagesCount(): Long = this._value.get()
public open override fun throwClosed(): Nothing {
throw IllegalStateException("Object is closed")
}
public open override fun throwInUse(): Nothing {
throw IllegalStateException("Failed close object because it is in use")
}
public final override val isClosed: Boolean get() = this._value.get() < 0
public final override fun assertNotClosed() {
if (this._value.get() < 0) this.throwClosed()
}
@ManualStateManipulation
public final override fun startUsage() {
this._value.update { o ->
if (o < 0) this.throwClosed()
return@update o + 1
}
}
@ManualStateManipulation
public final override fun finishUsage() {
this._value.update(Long::dec)
}
@ManualStateManipulation
public final override fun close() {
val state = this._value.compareAndExchange(0, Misc.CLOSED_STATE_VALUE)
when {
state > 0 -> this.throwInUse()
state < 0 -> this.throwClosed()
}
}
override fun toString(): String {
val cached = this._value.get()
@Suppress("LiftReturnOrAssignment")
if (cached < 0)
return "<closeable usages counter [closed]>"
else
return "<closeable usages counter [${cached}]>"
}
}

View File

@ -0,0 +1,40 @@
@file:JvmName("ChildrenScopesKt")
package ru.landgrafhomyak.utility.closeable_state
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
import kotlin.jvm.JvmName
import ru.landgrafhomyak.utility.highlevel_try_finally.safeAutoClose1
@OptIn(ManualStateManipulation::class)
public inline fun <R> CloseableState.childAC(
constructor: () -> CloseableState.AllowsConcurrency = ::UsagesCounter,
scope: (CloseableState.AllowsConcurrency) -> R,
): R {
contract {
callsInPlace(constructor, InvocationKind.EXACTLY_ONCE)
callsInPlace(scope, InvocationKind.EXACTLY_ONCE)
}
val childState = this.tryStartUsage { ChildCloseableState.AllowsConcurrency(this, constructor()) }
return safeAutoClose1(
action = { scope(childState) },
finally = childState::close
)
}
@OptIn(ManualStateManipulation::class)
public inline fun <R> CloseableState.childES(
constructor: () -> CloseableState.ExternallySynchronized = ::ErrorOnConcurrentAccessState,
scope: (CloseableState.ExternallySynchronized) -> R,
): R {
contract {
callsInPlace(constructor, InvocationKind.EXACTLY_ONCE)
callsInPlace(scope, InvocationKind.EXACTLY_ONCE)
}
val childState = this.tryStartUsage { ChildCloseableState.ExternallySynchronized(this, constructor()) }
return safeAutoClose1(
action = { scope(childState) },
finally = childState::close
)
}

View File

@ -1,6 +1,6 @@
package ru.landgrafhomyak.utility.reference_counter package ru.landgrafhomyak.utility.closeable_state.internal
internal expect class _AtomicLong { internal expect class AtomicLong {
constructor(initial: Long) constructor(initial: Long)
fun get(): Long fun get(): Long

View File

@ -0,0 +1,15 @@
package ru.landgrafhomyak.utility.closeable_state.internal
internal expect class AtomicReference<T> {
constructor(initial: T)
fun get(): T
inline fun update(operator: (T) -> T)
inline fun getAndUpdate(operator: (T) -> T): T
fun compareAndSet(expected: T, newValue: T): Boolean
fun compareAndExchange(expected: T, newValue: T): T
}

View File

@ -0,0 +1,16 @@
package ru.landgrafhomyak.utility.closeable_state.internal
import kotlin.jvm.JvmStatic
internal object Misc {
@JvmStatic
internal inline fun <T> _compareAndExchange(get: () -> T, cas: (T, T) -> Boolean, expected: T, newValue: T): T {
while (true) {
val old = get()
if (old != expected) return old
if (cas(old, newValue)) return old
}
}
internal const val CLOSED_STATE_VALUE = -0x4000_0000_0000_0000L
}

View File

@ -0,0 +1,40 @@
@file:JvmName("UsageScopesKt")
package ru.landgrafhomyak.utility.closeable_state
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
@OptIn(ManualStateManipulation::class)
@JvmName("use\$kt")
public inline fun <R> CloseableState.use(block: () -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
this.startUsage()
return safeAutoClose1(action = block, finally = this::finishUsage)
}
@ManualStateManipulation
@JvmName("tryStartUsage\$kt")
public inline fun <R> CloseableState.tryStartUsage(block: () -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
this.startUsage()
return safeAutoClose2(action = block, onError = this::finishUsage)
}
@ManualStateManipulation
@JvmName("tryFinishUsage\$kt")
public inline fun <R> CloseableState.tryFinishUsage(block: () -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
this.assertNotClosed()
return safeAutoClose2(action = block, onSuccess = this::finishUsage)
}

View File

@ -1,19 +0,0 @@
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)
}
}
}

View File

@ -1,35 +0,0 @@
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
}
}
}

View File

@ -1,164 +0,0 @@
@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")
}
}
}

View File

@ -1,145 +0,0 @@
@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)
}
}

View File

@ -1,17 +0,0 @@
package ru.landgrafhomyak.utility.reference_counter
import kotlin.jvm.JvmStatic
@Suppress("ClassName")
internal object _Misc {
@JvmStatic
internal inline fun _compareAndExchange(get: () -> Long, cas: (Long, Long) -> Boolean, expected: Long, newValue: Long): Long {
while (true) {
val old = get()
if (old != expected) return old
if (cas(old, newValue)) return old
}
}
internal const val CLOSED_STATE_VALUE = -0x4000_0000_0000_0000L
}

View File

@ -1,9 +0,0 @@
package ru.landgrafhomyak.utility.reference_counter
import kotlin.jvm.JvmStatic
@PublishedApi
internal expect object _Platform {
@PublishedApi
internal inline fun jvm_assertNotNull(x: Any?, name: String)
}

View File

@ -1,37 +0,0 @@
package ru.landrafhomyak.utility.reference_counter
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
import kotlin.jvm.JvmName
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 constructor(errMessageClosed: String) : super(moved_CloseableReferenceCounter(errMessageClosed))
@Suppress("INAPPLICABLE_JVM_NAME", "NON_FINAL_MEMBER_IN_FINAL_CLASS")
@JvmName("close")
public open fun close(errExistRefs: String) {
(this._moved as moved_CloseableReferenceCounter).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(scope, "param: scope")
return moved_CloseableReferenceCounter.autoClosed(errMessageClosed, errExistRefs, WrapperReferenceCounter.wrapperLambda(scope))
}
}
}

View File

@ -1,114 +0,0 @@
@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.JvmField
import kotlin.jvm.JvmName
import ru.landgrafhomyak.utility.reference_counter.CloseableReferenceCounter_Debug as moved_CloseableReferenceCounter_Debug
@Suppress("DEPRECATION_ERROR")
@Deprecated(
message = "Class moved to another package",
level = DeprecationLevel.ERROR
)
@OptIn(moved_CloseableReferenceCounter_Debug.RequiresExplicitDebug::class)
@CloseableReferenceCounter_Debug.RequiresExplicitDebug
public class CloseableReferenceCounter_Debug {
public fun interface Observer {
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)
@Retention(AnnotationRetention.BINARY)
public annotation class RequiresExplicitDebug
@PublishedApi
@JvmField
internal val _moved: moved_CloseableReferenceCounter_Debug
public constructor(dbgName: String, errMessage: String, logger: Observer? = null) {
val obs = logger?.let(::ObserverAdapter)
this._moved = moved_CloseableReferenceCounter_Debug(dbgName, errMessage, obs)
obs?.wrapper = this
}
@RequiresExplicitDebug
@JvmName("throwErrors")
public fun throwErrors() {
this._moved.throwErrors()
}
@JvmName("throwClosed")
public fun throwClosed() {
this._moved.throwClosed()
}
@JvmName("incref")
public fun incref() {
this._moved.incref()
}
@JvmName("tryIncref\$kt")
public inline fun <R> tryIncref(block: () -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return this._moved.tryIncref(block)
}
@JvmName("assertNotClosed")
public fun assertNotClosed() {
this._moved.assertNotClosed()
}
@JvmName("decref")
public fun decref() {
this._moved.decref()
}
@JvmName("tryDecref\$kt")
public inline fun <R> tryDecref(block: () -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return this._moved.tryDecref(block)
}
@get:JvmName("isClosed")
public val isClosed: Boolean
get() = this._moved.isClosed
@JvmName("close")
public fun close(errExistRefs: String) {
this._moved.close(errExistRefs)
}
@JvmName("withRef\$kt")
public inline fun <R> withRef(protected: () -> R): R {
contract {
callsInPlace(protected, InvocationKind.EXACTLY_ONCE)
}
return this._moved.withRef(protected)
}
override fun toString(): String {
val orig = this._moved.toString()
return orig.substring(0, orig.length - 1) + " !deprecated class used!>"
}
public object ObserveToStdout : Observer {
override fun observeState(instance: CloseableReferenceCounter_Debug, actions: String) {
moved_CloseableReferenceCounter_Debug.ObserveToStdout.observeState(instance._moved, actions)
}
}
}

View File

@ -1,108 +0,0 @@
@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.JvmField
import kotlin.jvm.JvmName
import ru.landgrafhomyak.utility.reference_counter._Platform
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 {
@PublishedApi
@JvmField
internal val _moved: moved_MayBeClosedReferenceCounter
protected constructor(moved: moved_MayBeClosedReferenceCounter) {
this._moved = moved
}
@JvmName("throwClosed")
public fun throwClosed() {
this._moved.throwClosed()
}
@JvmName("incref")
public fun incref() {
this._moved.incref()
}
@JvmName("tryIncref\$kt")
public inline fun <R> tryIncref(block: () -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return this._moved.tryIncref(block)
}
@JvmName("assertNotClosed")
public fun assertNotClosed() {
this._moved.assertNotClosed()
}
@JvmName("decref")
public fun decref() {
this._moved.decref()
}
@JvmName("tryDecref\$kt")
public inline fun <R> tryDecref(block: () -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return this._moved.tryDecref(block)
}
@get:JvmName("isClosed")
public val isClosed: Boolean get() =
this._moved.isClosed
@JvmName("withRef\$kt")
public inline fun <R> withRef(protected: () -> R): R {
contract {
callsInPlace(protected, InvocationKind.EXACTLY_ONCE)
}
return this._moved.withRef(protected)
}
override fun toString(): String {
val orig = this._moved.toString()
return orig.substring(0, orig.length - 1) + " !deprecated class used!>"
}
@Suppress("LEAKED_IN_PLACE_LAMBDA", "WRONG_INVOCATION_KIND", "DEPRECATION_ERROR")
@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))
}
}

View File

@ -1,20 +0,0 @@
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)) }
}
}
}

View File

@ -1,8 +1,8 @@
package ru.landgrafhomyak.utility.reference_counter package ru.landgrafhomyak.utility.closeable_state.internal
import java.util.concurrent.atomic.AtomicLong import java.util.concurrent.atomic.AtomicLong
internal actual /*value*/ class _AtomicLong { internal actual /*value*/ class AtomicLong {
private val _native: AtomicLong private val _native: AtomicLong
actual constructor(initial: Long) { actual constructor(initial: Long) {
@ -31,11 +31,11 @@ internal actual /*value*/ class _AtomicLong {
this._native.compareAndSet(expected, newValue) this._native.compareAndSet(expected, newValue)
actual fun compareAndExchange(expected: Long, newValue: Long): Long { actual fun compareAndExchange(expected: Long, newValue: Long): Long {
if (_Linkage._isNativeCompareAndExchangeExists) { if (_Linkage.isNativeCompareAndExchangeExists) {
return this._native.compareAndExchange(expected, newValue) return this._native.compareAndExchange(expected, newValue)
} else { } else {
val a = this._native val a = this._native
return _Misc._compareAndExchange( return Misc._compareAndExchange(
get = a::get, get = a::get,
cas = a::compareAndSet, cas = a::compareAndSet,
expected = expected, newValue = newValue expected = expected, newValue = newValue
@ -44,8 +44,8 @@ internal actual /*value*/ class _AtomicLong {
} }
private object _Linkage { private object _Linkage {
@JvmField @JvmStatic
val _isNativeCompareAndExchangeExists = run { val isNativeCompareAndExchangeExists = run {
val a = AtomicLong() val a = AtomicLong()
try { try {
a.compareAndExchange(0, 0) a.compareAndExchange(0, 0)

View File

@ -0,0 +1,58 @@
package ru.landgrafhomyak.utility.closeable_state.internal
import java.util.concurrent.atomic.AtomicReference as jAtomicReference
internal actual /*value*/ class AtomicReference<T> {
private val _native: jAtomicReference<T>
actual constructor(initial: T) {
this._native = jAtomicReference(initial)
}
actual fun get() = this._native.get()
actual inline fun update(operator: (T) -> T) {
while (true) {
val cur = this._native.get()
val upd = operator(cur)
if (this._native.compareAndSet(cur, upd)) return
}
}
actual inline fun getAndUpdate(operator: (T) -> T): T {
while (true) {
val cur = this._native.get()
val upd = operator(cur)
if (this._native.compareAndSet(cur, upd)) return cur
}
}
actual fun compareAndSet(expected: T, newValue: T): Boolean =
this._native.compareAndSet(expected, newValue)
actual fun compareAndExchange(expected: T, newValue: T): T {
if (_Linkage.isNativeCompareAndExchangeExists) {
return this._native.compareAndExchange(expected, newValue)
} else {
val a = this._native
return Misc._compareAndExchange(
get = a::get,
cas = a::compareAndSet,
expected = expected, newValue = newValue
)
}
}
private object _Linkage {
@JvmStatic
val isNativeCompareAndExchangeExists = run {
val a = jAtomicReference(null)
try {
a.compareAndExchange(null, null)
return@run true
} catch (_: NoSuchMethodError) {
return@run false
}
}
}
}

View File

@ -1,17 +0,0 @@
package ru.landgrafhomyak.utility.reference_counter
import java.util.Objects
import kotlin.contracts.contract
@PublishedApi
internal actual object _Platform {
@Suppress("NOTHING_TO_INLINE")
@JvmStatic
@PublishedApi
internal actual inline fun jvm_assertNotNull(x: Any?, name: String) {
contract {
returns().implies(x != null)
}
Objects.requireNonNull(x, name)
}
}

View File

@ -0,0 +1,81 @@
package ru.landgrafhomyak.utility.closeable_state.tests
import org.testng.annotations.Test
import ru.landgrafhomyak.utility.highlevel_try_finally.safeAutoClose1
import ru.landgrafhomyak.utility.closeable_state.ManualStateManipulation
import ru.landgrafhomyak.utility.closeable_state.UsagesCounter
import ru.landgrafhomyak.utility.closeable_state.use
@Test
class KotlinStdlibDependencyTest {
@Test
fun testNoKotlinStdlib() {
try {
if (KotlinVersion.CURRENT.major != -1)
throw AssertionError("Kotlin stdlib still in runtime classpath")
} catch (_: LinkageError) {
}
}
private class CustomTestException : RuntimeException()
private object CustomUnit
private fun throw7throwFn() {
safeAutoClose1(finally = { throw CustomTestException() }, action = { throw CustomTestException() })
}
@Suppress("NOTHING_TO_INLINE")
private inline fun throw7throwIn() {
safeAutoClose1(finally = { throw CustomTestException() }, action = { throw CustomTestException() })
}
@OptIn(ManualStateManipulation::class)
@Test(dependsOnMethods = ["testNoKotlinStdlib"])
fun testIncrefDecrefClose() {
try {
val refcnt = UsagesCounter()
refcnt.startUsage()
refcnt.finishUsage()
refcnt.startUsage()
refcnt.startUsage()
refcnt.finishUsage()
refcnt.finishUsage()
refcnt.close()
} catch (le: LinkageError) {
throw AssertionError("CloseableReferenceCounter still has dependency on kotlin stdlib", le)
}
}
@OptIn(ManualStateManipulation::class)
@Test(dependsOnMethods = ["testNoKotlinStdlib", "testIncrefDecrefClose"])
fun testWithRef() {
try {
val refcnt = UsagesCounter()
refcnt.use {
return@use CustomUnit
}
refcnt.use w1@{
return@w1 refcnt.use w2@{
return@w2 CustomUnit
}
}
refcnt.close()
} catch (le: LinkageError) {
throw AssertionError("CloseableReferenceCounter still has dependency on kotlin stdlib", le)
}
}
@Test(dependsOnMethods = ["testNoKotlinStdlib", "testIncrefDecrefClose", "testWithRef"])
fun testWithRef_Err() {
try {
val refcnt = UsagesCounter()
refcnt.use {
throw CustomTestException()
}
} catch (_: CustomTestException) {
} catch (le: LinkageError) {
throw AssertionError("CloseableReferenceCounter still has dependency on kotlin stdlib", le)
}
}
}

View File

@ -1,130 +0,0 @@
package ru.landgrafhomyak.utility.reference_counter.tests
import java.lang.AssertionError
import org.testng.annotations.Test
import org.testng.asserts.Assertion
import ru.landgrafhomyak.utility.highlevel_try_finally.safeAutoClose1
import ru.landgrafhomyak.utility.reference_counter.CloseableReferenceCounter
import ru.landgrafhomyak.utility.reference_counter.CloseableReferenceCounter_Debug
@Test
class KotlinStdlibDependencyTest {
@Test
fun testNoKotlinStdlib() {
try {
if (KotlinVersion.CURRENT.major != -1)
throw AssertionError("Kotlin stdlib still in runtime classpath")
} catch (_: LinkageError) {
}
}
private class CustomTestException : RuntimeException()
private object CustomUnit
private fun throw7throwFn() {
safeAutoClose1(finally = { throw CustomTestException() }, action = { throw CustomTestException() })
}
@Suppress("NOTHING_TO_INLINE")
private inline fun throw7throwIn() {
safeAutoClose1(finally = { throw CustomTestException() }, action = { throw CustomTestException() })
}
@Test(dependsOnMethods = ["testNoKotlinStdlib"])
fun testIncrefDecrefClose() {
try {
val refcnt = CloseableReferenceCounter("")
refcnt.incref()
refcnt.decref()
refcnt.incref()
refcnt.incref()
refcnt.decref()
refcnt.decref()
refcnt.close("")
} catch (le: LinkageError) {
throw AssertionError("CloseableReferenceCounter still has dependency on kotlin stdlib", le)
}
}
@OptIn(CloseableReferenceCounter_Debug.RequiresExplicitDebug::class)
@Test(dependsOnMethods = ["testNoKotlinStdlib"])
fun testIncrefDecrefClose_Debug() {
try {
val refcnt = CloseableReferenceCounter_Debug("", "")
refcnt.incref()
refcnt.decref()
refcnt.incref()
refcnt.incref()
refcnt.decref()
refcnt.decref()
refcnt.close("")
} catch (le: LinkageError) {
throw AssertionError("CloseableReferenceCounter_Debug still has dependency on kotlin stdlib", le)
}
}
@Test(dependsOnMethods = ["testNoKotlinStdlib", "testIncrefDecrefClose"])
fun testWithRef() {
try {
val refcnt = CloseableReferenceCounter("")
refcnt.withRef {
return@withRef CustomUnit
}
refcnt.withRef w1@{
return@w1 refcnt.withRef w2@{
return@w2 CustomUnit
}
}
refcnt.close("")
} catch (le: LinkageError) {
throw AssertionError("CloseableReferenceCounter still has dependency on kotlin stdlib", le)
}
}
@OptIn(CloseableReferenceCounter_Debug.RequiresExplicitDebug::class)
@Test(dependsOnMethods = ["testNoKotlinStdlib", "testIncrefDecrefClose_Debug"])
fun testWithRef_Debug() {
try {
val refcnt = CloseableReferenceCounter_Debug("", "")
refcnt.withRef {
return@withRef CustomUnit
}
refcnt.withRef w1@{
return@w1 refcnt.withRef w2@{
return@w2 CustomUnit
}
}
refcnt.close("")
} catch (le: LinkageError) {
throw AssertionError("CloseableReferenceCounter_Debug still has dependency on kotlin stdlib", le)
}
}
@Test(dependsOnMethods = ["testNoKotlinStdlib", "testIncrefDecrefClose", "testWithRef"])
fun testWithRef_Err() {
try {
val refcnt = CloseableReferenceCounter("")
refcnt.withRef {
throw CustomTestException()
}
} catch (_: CustomTestException) {
} catch (le: LinkageError) {
throw AssertionError("CloseableReferenceCounter still has dependency on kotlin stdlib", le)
}
}
@OptIn(CloseableReferenceCounter_Debug.RequiresExplicitDebug::class)
@Test(dependsOnMethods = ["testNoKotlinStdlib", "testIncrefDecrefClose_Debug", "testWithRef_Debug"])
fun testWithRef_ErrDebug() {
try {
val refcnt = CloseableReferenceCounter_Debug("", "")
refcnt.withRef {
throw CustomTestException()
}
} catch (_: CustomTestException) {
} catch (le: LinkageError) {
throw AssertionError("CloseableReferenceCounter_Debug still has dependency on kotlin stdlib", le)
}
}
}

View File

@ -1,15 +1,15 @@
package ru.landgrafhomyak.utility.reference_counter package ru.landgrafhomyak.utility.closeable_state.internal
import kotlinx.atomicfu.AtomicLong import kotlinx.atomicfu.AtomicLong as kAtomicLing
import kotlinx.atomicfu.atomic import kotlinx.atomicfu.atomic
import kotlinx.atomicfu.getAndUpdate import kotlinx.atomicfu.getAndUpdate
import kotlinx.atomicfu.update import kotlinx.atomicfu.update
internal actual class _AtomicLong { internal actual class AtomicLong {
val _atomicfu: AtomicLong val _atomicfu: kAtomicLing
actual constructor(initial: Long) { actual constructor(initial: Long) {
this._atomicfu = atomic(0L) this._atomicfu = atomic(initial)
} }
actual fun get() = actual fun get() =
@ -26,7 +26,7 @@ internal actual class _AtomicLong {
actual fun compareAndExchange(expected: Long, newValue: Long): Long { actual fun compareAndExchange(expected: Long, newValue: Long): Long {
val a = this._atomicfu val a = this._atomicfu
return _Misc._compareAndExchange( return Misc._compareAndExchange(
get = a::value::get, get = a::value::get,
cas = a::compareAndSet, cas = a::compareAndSet,
expected = expected, newValue = newValue expected = expected, newValue = newValue

View File

@ -0,0 +1,35 @@
package ru.landgrafhomyak.utility.closeable_state.internal
import kotlinx.atomicfu.AtomicRef as kAtomicRef
import kotlinx.atomicfu.atomic
import kotlinx.atomicfu.getAndUpdate
import kotlinx.atomicfu.update
internal actual class AtomicReference<T> {
val _atomicfu: kAtomicRef<T>
actual constructor(initial: T) {
this._atomicfu = atomic(initial)
}
actual fun get() =
this._atomicfu.value
actual inline fun update(operator: (T) -> T) =
this._atomicfu.update(operator)
actual inline fun getAndUpdate(operator: (T) -> T) =
this._atomicfu.getAndUpdate(operator)
actual fun compareAndSet(expected: T, newValue: T): Boolean =
this._atomicfu.compareAndSet(expected, newValue)
actual fun compareAndExchange(expected: T, newValue: T): T {
val a = this._atomicfu
return Misc._compareAndExchange(
get = a::value::get,
cas = a::compareAndSet,
expected = expected, newValue = newValue
)
}
}

View File

@ -1,10 +0,0 @@
package ru.landgrafhomyak.utility.reference_counter
@PublishedApi
internal actual object _Platform {
@Suppress("NOTHING_TO_INLINE")
@PublishedApi
internal actual inline fun jvm_assertNotNull(x: Any?, name: String) {
}
}