Compare commits

..

27 Commits

Author SHA1 Message Date
5f6823cfb9 SpinLockSynchronizedState.close now synchronized too 2025-10-03 20:05:40 +03:00
6ea651ce6d SpinLockSynchronizedState 2025-10-03 19:49:01 +03:00
5e9e741b51 withUseIfNotClosed 2025-09-15 01:39:27 +03:00
8fc08d3e26 startUsageIfNotClosed 2025-09-15 01:37:12 +03:00
4ff6c0beb3 'Destructor' annotation 2025-09-15 00:48:10 +03:00
129cee26ca minor fix 2025-09-05 19:40:18 +03:00
e578517821 autoClosed not inline anymore 2025-09-05 18:32:11 +03:00
4b799c0ecf More access to HandleWrapper members because it anyway must be wrapped 2025-09-05 00:49:19 +03:00
bdb1fe56fa HandleWrapper 2025-09-04 21:19:18 +03:00
6bbade401f v1.1 2025-08-24 17:26:08 +03:00
7d56a44323 Fixes to remove kotlin-stdlib dependency 2025-08-24 17:15:55 +03:00
c078394921 Java implementation of CloseableWrapper 2025-08-24 16:48:00 +03:00
96931fda41 Close-on-exit feature 2025-08-24 04:18:54 +03:00
7131a38bd4 Removed excess atomic functions and minor fixes 2025-08-24 03:59:16 +03:00
999ff63ccf Replacement of AutoCloseable.use{} 2025-08-24 02:05:20 +03:00
826f286404 Improved 'owner' property in corresponding states 2025-08-24 01:48:20 +03:00
ad87bb7904 ErrorOnConcurrentAccessState expect class, java8 -> java9 and minor fixes 2025-08-24 01:36:49 +03:00
98d76569cc UsagesCounter expect class and ErrorOnConcurrentAccessState java implementation 2025-08-24 01:25:10 +03:00
c30c585f76 UsagesCounter implementation on java 2025-08-24 00:43:25 +03:00
ed06e6c2a0 Removed 'throw*' methods 2025-08-24 00:10:33 +03:00
05b9fc6078 Some missed 'final' modifiers 2025-08-23 23:47:13 +03:00
8f277853bd Fixed typo in ES impl and CloseableWrapper 2025-08-23 23:42:34 +03:00
131dd44d38 Add generation id to package and artifact name 2025-08-23 23:35:55 +03:00
953af111b4 v1.0 2025-08-22 14:40:13 +03:00
e8d899928e Missed expect functions for atomics and tests 2025-08-22 14:26:37 +03:00
860ffa98e0 Inlined atomics (no wrapper class anymore) 2025-08-22 05:35:40 +03:00
d4db1907d9 Unified all classes to common interface 2025-08-22 02:47:45 +03:00
52 changed files with 1516 additions and 946 deletions

View File

@ -15,7 +15,7 @@ buildscript {
} }
group = "ru.landgrafhomyak.utility" group = "ru.landgrafhomyak.utility"
version = "0.5" version = "1.4"
repositories { repositories {
mavenCentral() mavenCentral()
@ -37,11 +37,12 @@ xomrk {
compilations.configureEach { compilations.configureEach {
compileJavaTaskProvider?.configure { compileJavaTaskProvider?.configure {
targetCompatibility = "1.8" targetCompatibility = "9"
sourceCompatibility = "9"
} }
compileTaskProvider.configure { compileTaskProvider.configure {
compilerOptions { compilerOptions {
jvmTarget = JvmTarget.JVM_1_8 jvmTarget = JvmTarget.JVM_9
freeCompilerArgs.addAll( freeCompilerArgs.addAll(
"-Xno-call-assertions", "-Xno-call-assertions",
"-Xno-param-assertions", "-Xno-param-assertions",
@ -64,13 +65,25 @@ xomrk {
val commonMain by getting { val commonMain by getting {
dependencies { dependencies {
compileOnly(kotlinStdlibDependency) compileOnly(kotlinStdlibDependency)
implementation("ru.landgrafhomyak.utility:highlevel-try-finally:0.5") implementation("ru.landgrafhomyak.utility:highlevel-try-finally:0.6")
} }
} }
val commonTest by getting {
dependencies {
compileOnly("org.jetbrains.kotlin:kotlin-test:${this@kotlin.coreLibrariesVersion}")
}
}
val jvmMain by getting { val jvmMain by getting {
dependsOn(commonMain) dependsOn(commonMain)
dependencies { dependencies {
compileOnly(kotlinStdlibDependency) }
}
jvmTest {
dependencies {
implementation(kotlinStdlibDependency)
implementation("org.testng:testng:7.5.1")
} }
} }
@ -82,11 +95,6 @@ xomrk {
} }
} }
jvmTest {
dependencies {
implementation("org.testng:testng:7.5.1")
}
}
configureEach { configureEach {
when { when {
@ -103,7 +111,7 @@ xomrk {
publishing { publishing {
repositories { repositories {
defineXomrkGiteaMavenRepo() defineXomrkGiteaMavenRepo(user="LanguageUtilities")
} }
} }
} }

@ -1 +1 @@
Subproject commit 099c3fad269770649d5a67acd3cd07e378bc9f37 Subproject commit 6cfa6bddd04a041ae02ec8098c478762313c71de

View File

@ -1,3 +1,3 @@
rootProject.name = "reference-counter" rootProject.name = "closeable-state-1"
includeBuild("./highlevel-try-finally") includeBuild("./highlevel-try-finally")

View File

@ -0,0 +1,82 @@
package ru.landgrafhomyak.utility.closeable_state_1
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 assertNotClosed(): Unit =
this._state.assertNotClosed()
override val isClosed: Boolean
get() = this._state.isClosed
@ManualStateManipulation
override fun startUsage(): Unit =
this._state.startUsage()
@ManualStateManipulation
override fun startUsageIfNotClosed(): Boolean =
this._state.startUsageIfNotClosed()
@ManualStateManipulation
override fun finishUsage(): Unit =
this._state.finishUsage()
@Destructor
@ManualStateManipulation
override fun close() {
this._state.finishUsage()
this._parent.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
@ManualStateManipulation
override fun finishUsage(close: Boolean) {
this._state.finishUsage(close)
}
override fun toString(): String {
when {
this._state is OwnedErrorOnConcurrentAccessState || this._state::class === ErrorOnConcurrentAccessState::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})>"
}
}
}
}

View File

@ -0,0 +1,35 @@
package ru.landgrafhomyak.utility.closeable_state_1
public interface CloseableState {
public val isClosed: Boolean
public fun assertNotClosed()
@ManualStateManipulation
public fun startUsage()
/**
* Tries to start usage and returns `false` if entered or `true` if closed.
* Doesn't prevent from throwing error if this state forbids concurrent access.
*/
@ManualStateManipulation
public fun startUsageIfNotClosed(): Boolean
@ManualStateManipulation
public fun finishUsage()
@Destructor
@ManualStateManipulation
public fun close()
public interface AllowsConcurrency : CloseableState {
}
public interface ExternallySynchronized : CloseableState {
public val isInUse: Boolean
@ManualStateManipulation
public fun finishUsage(close: Boolean)
}
}

View File

@ -0,0 +1,30 @@
package ru.landgrafhomyak.utility.closeable_state_1
public expect class CloseableStateCloseableWrapper : CloseableState.ExternallySynchronized {
public constructor(parent: CloseableState.ExternallySynchronized, self: CloseableState.ExternallySynchronized)
override val isInUse: Boolean
override val isClosed: Boolean
override fun assertNotClosed()
@ManualStateManipulation
override fun startUsage()
@ManualStateManipulation
override fun startUsageIfNotClosed(): Boolean
@ManualStateManipulation
override fun finishUsage()
@ManualStateManipulation
override fun finishUsage(close: Boolean)
@Destructor
@ManualStateManipulation
override fun close()
override fun toString(): String
}

View File

@ -0,0 +1,8 @@
package ru.landgrafhomyak.utility.closeable_state_1
/**
* Utility annotation to simplify searching method that closes/destructs/deallocs object.
*/
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.SOURCE)
public annotation class Destructor()

View File

@ -0,0 +1,36 @@
package ru.landgrafhomyak.utility.closeable_state_1
public expect open class ErrorOnConcurrentAccessState : CloseableState.ExternallySynchronized {
public constructor()
public final override val isInUse: Boolean
protected open fun throwClosed(): Nothing
protected open fun throwInUse(): Nothing
protected open fun throwConcurrent(): Nothing
public final override fun assertNotClosed()
public final override val isClosed: Boolean
@ManualStateManipulation
public final override fun startUsage()
@ManualStateManipulation
public final override fun startUsageIfNotClosed(): Boolean
@ManualStateManipulation
public final override fun finishUsage()
@ManualStateManipulation
public final override fun finishUsage(close: Boolean)
@Destructor
@ManualStateManipulation
public final override fun close()
@Suppress("RedundantModalityModifier")
public open override fun toString(): String
}

View File

@ -0,0 +1,26 @@
package ru.landgrafhomyak.utility.closeable_state_1
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
public class HandleWrapper<H>(
public val handle: H,
public val state: CloseableState,
) {
public fun <R> useHandle(method: (H) -> R): R {
contract {
callsInPlace(method, InvocationKind.EXACTLY_ONCE)
}
return this.state.withUse { method(this.handle) }
}
@Destructor
@ManualStateManipulation
public fun close() {
this.state.close()
}
override fun toString(): String = "<wrapper of handle=${this.handle} protected with state=${this.state}>"
}

View File

@ -0,0 +1,7 @@
package ru.landgrafhomyak.utility.closeable_state_1
@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,41 @@
@file:OptIn(ExperimentalContracts::class)
package ru.landgrafhomyak.utility.closeable_state_1
import kotlin.contracts.ExperimentalContracts
public class OwnedErrorOnConcurrentAccessState : ErrorOnConcurrentAccessState {
private var _owner: Any?
public constructor() : super() {
this._owner = null
}
public constructor(owner: Any) : super() {
this._owner = owner
}
public var owner: Any
get() = this._owner ?: throw IllegalStateException("Owner not set yet")
set(value) {
if (this._owner != null) throw IllegalStateException("Owner already initialized")
this._owner = value
}
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,37 @@
@file:OptIn(ExperimentalContracts::class)
package ru.landgrafhomyak.utility.closeable_state_1
import kotlin.contracts.ExperimentalContracts
public class OwnedUsagesCounter : UsagesCounter {
private var _owner: Any?
public constructor() : super() {
this._owner = null
}
public constructor(owner: Any) : super() {
this._owner = owner
}
public var owner: Any
get() = this._owner ?: throw IllegalStateException("Owner not set yet")
set(value) {
if (this._owner != null) throw IllegalStateException("Owner already initialized")
this._owner = value
}
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,34 @@
@file:OptIn(ExperimentalContracts::class)
package ru.landgrafhomyak.utility.closeable_state_1
import kotlin.contracts.ExperimentalContracts
public expect open class UsagesCounter : CloseableState.AllowsConcurrency {
public constructor()
protected open fun throwClosed(): Nothing
protected open fun throwInUse(): Nothing
public final override val isClosed: Boolean
public final override fun assertNotClosed()
@ManualStateManipulation
public final override fun startUsage()
@ManualStateManipulation
public final override fun startUsageIfNotClosed(): Boolean
@ManualStateManipulation
public final override fun finishUsage()
@Destructor
@ManualStateManipulation
public final override fun close()
@Suppress("RedundantModalityModifier")
public open override fun toString(): String
}

View File

@ -0,0 +1,5 @@
package ru.landgrafhomyak.utility.closeable_state_1
internal object _MiscMultiplatform {
internal const val CLOSED_STATE_VALUE = -0x4000_0000_0000_0000L
}

View File

@ -0,0 +1,55 @@
@file:JvmName("ChildrenScopesKt")
package ru.landgrafhomyak.utility.closeable_state_1
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
)
}
@OptIn(ManualStateManipulation::class)
public inline fun <R> CloseableState.ExternallySynchronized.closeableWrapper(
crossinline constructor: () -> CloseableState.ExternallySynchronized = ::ErrorOnConcurrentAccessState,
noinline scope: (CloseableState.ExternallySynchronized) -> R,
): R {
contract {
callsInPlace(constructor, InvocationKind.EXACTLY_ONCE)
callsInPlace(scope, InvocationKind.EXACTLY_ONCE)
}
return autoClosed(
constructor = { CloseableStateCloseableWrapper(this, constructor()) },
scope = scope
)
}

View File

@ -0,0 +1,117 @@
@file:JvmName("UsageScopesKt")
package ru.landgrafhomyak.utility.closeable_state_1
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("autoClosed\$kt")
public fun <S : CloseableState, R> autoClosed(
constructor: () -> S,
scope: (S) -> R,
): R {
contract {
callsInPlace(constructor, InvocationKind.EXACTLY_ONCE)
callsInPlace(scope, InvocationKind.EXACTLY_ONCE)
}
val state = constructor()
return safeAutoClose1(
action = { scope(state) },
finally = state::close
)
}
@OptIn(ManualStateManipulation::class)
@JvmName("withUse\$kt")
public inline fun <R> CloseableState.withUse(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)
}
return safeAutoClose2(action = block, onSuccess = this::finishUsage)
}
@OptIn(ManualStateManipulation::class)
@JvmName("withUseThenClose\$kt")
public inline fun CloseableState.ExternallySynchronized.withUseThenClose(block: () -> Boolean) {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
this.startUsage()
var needClose = false
return safeAutoClose1(
action = { needClose = block() },
finally = { this.finishUsage(needClose) }
)
}
@ManualStateManipulation
@JvmName("tryFinishUsageThenClose\$kt")
public inline fun <R> CloseableState.ExternallySynchronized.tryFinishUsageThenClose(close: Boolean, block: () -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return safeAutoClose2(action = block, onSuccess = { this.finishUsage(close) })
}
@ManualStateManipulation
@JvmName("tryFinishUsageThenClose\$kt")
public inline fun CloseableState.ExternallySynchronized.tryFinishUsageThenClose(block: () -> Boolean) {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
var needClose = false
return safeAutoClose2(
action = { needClose = block() },
onSuccess = { this.finishUsage(needClose) }
)
}
@OptIn(ManualStateManipulation::class)
@JvmName("withUseIfNotClosed\$kt")
public inline fun <R> CloseableState.withUseIfNotClosed(ifClosed: R, block: () -> R): R {
contract {
callsInPlace(block, InvocationKind.AT_MOST_ONCE)
}
if (this.startUsageIfNotClosed())
return ifClosed
return safeAutoClose1(action = block, finally = { this.finishUsage() })
}
@OptIn(ManualStateManipulation::class)
@JvmName("withUseIfNotClosed\$kt")
public inline fun <R> CloseableState.withUseIfNotClosed(ifClosed: () -> R, block: () -> R): R {
contract {
callsInPlace(ifClosed, InvocationKind.AT_MOST_ONCE)
callsInPlace(block, InvocationKind.AT_MOST_ONCE)
}
if (this.startUsageIfNotClosed())
return ifClosed()
return safeAutoClose1(action = block, finally = { 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,15 +0,0 @@
package ru.landgrafhomyak.utility.reference_counter
internal expect class _AtomicLong {
constructor(initial: Long)
fun get(): Long
inline fun update(operator: (Long) -> Long)
inline fun getAndUpdate(operator: (Long) -> Long): Long
fun compareAndSet(expected: Long, newValue: Long): Boolean
fun compareAndExchange(expected: Long, newValue: Long): Long
}

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

@ -0,0 +1,10 @@
package ru.landgrafhomyak.utility.closeable_state_1
import kotlin.test.Test
internal class ErrorOnConcurrentAccessStateTest: _CloseableStateExternallySynchronizedAbstractTestSet() {
override fun createState(): CloseableState = ErrorOnConcurrentAccessState()
@Test
fun test() {}
}

View File

@ -0,0 +1,4 @@
package ru.landgrafhomyak.utility.closeable_state_1
internal class TestThrowable: Throwable("If this throwable isn't caught then test is bad written") {
}

View File

@ -0,0 +1,10 @@
package ru.landgrafhomyak.utility.closeable_state_1
import kotlin.test.Test
internal class UsagesCounterTest: _CloseableStateAllowsConcurrencyAbstractTestSet() {
override fun createState(): CloseableState = UsagesCounter()
@Test
fun test() {}
}

View File

@ -0,0 +1,91 @@
package ru.landgrafhomyak.utility.closeable_state_1
import kotlin.test.Test
@OptIn(ManualStateManipulation::class)
internal abstract class _CloseableStateAbstractTestSet {
abstract fun createState(): CloseableState
@Test
fun testInstantClose() {
this.createState().close()
}
@Test
fun testOneManual() {
val s = this.createState()
s.startUsage()
s.finishUsage()
s.close()
}
@Test
fun testOneAuto() {
val s = this.createState()
s.withUse { }
s.close()
}
@Test
fun testSubsequentManual() {
val s = this.createState()
s.startUsage()
s.finishUsage()
s.startUsage()
s.finishUsage()
s.startUsage()
s.finishUsage()
s.close()
}
@Test
fun testSubsequentAuto() {
val s = this.createState()
s.withUse { }
s.withUse { }
s.withUse { }
s.close()
}
@Test
fun testTryStartSuccess() {
val s = this.createState()
s.tryStartUsage { }
s.finishUsage()
s.close()
}
@Test
fun testTryStartFailed() {
val s = this.createState()
try {
s.tryStartUsage { throw TestThrowable() }
} catch (_: TestThrowable) {
}
s.close()
}
@Test
fun testTryFinishSuccess() {
val s = this.createState()
s.startUsage()
s.tryFinishUsage { }
s.close()
}
@Test
fun testTryFinishFailed() {
val s = this.createState()
s.startUsage()
try {
s.tryFinishUsage { throw TestThrowable() }
} catch (_: TestThrowable) {
}
try {
s.close()
} catch (_: Throwable) {}
s.finishUsage()
s.close()
}
}

View File

@ -0,0 +1,25 @@
package ru.landgrafhomyak.utility.closeable_state_1
import kotlin.test.Test
@OptIn(ManualStateManipulation::class)
internal abstract class _CloseableStateAllowsConcurrencyAbstractTestSet: _CloseableStateAbstractTestSet() {
abstract override fun createState(): CloseableState
@Test
fun testRecursionManual() {
val s = this.createState()
s.startUsage()
s.startUsage()
s.finishUsage()
s.finishUsage()
s.close()
}
@Test
fun testRecursionAuto() {
val s = this.createState()
s.withUse { s.withUse { } }
s.close()
}
}

View File

@ -0,0 +1,32 @@
package ru.landgrafhomyak.utility.closeable_state_1
import kotlin.test.Test
@OptIn(ManualStateManipulation::class)
internal abstract class _CloseableStateExternallySynchronizedAbstractTestSet : _CloseableStateAbstractTestSet() {
abstract override fun createState(): CloseableState
@Test
fun testRecursionManual() {
val s = this.createState()
s.startUsage()
try {
s.startUsage()
} catch (_: Throwable) {
}
s.finishUsage()
s.close()
}
@Test
fun testRecursionAuto() {
val s = this.createState()
s.withUse {
try {
s.withUse {}
} catch (_: Throwable) {
}
}
s.close()
}
}

View File

@ -0,0 +1,110 @@
package ru.landgrafhomyak.utility.closeable_state_1;
import java.util.concurrent.atomic.AtomicReference;
public /* open */ class SpinLockSynchronizedState
extends SpinLockSynchronizedState$Errors
implements CloseableState.ExternallySynchronized {
private enum State {
OPEN, IN_USE, CLOSED
}
private final AtomicReference<State> _currentState;
public SpinLockSynchronizedState() {
this._currentState = new AtomicReference<>(State.OPEN);
}
@Override
public final boolean isInUse() {
return this._currentState.get() == State.IN_USE;
}
@Override
public final boolean isClosed() {
return this._currentState.get() == State.CLOSED;
}
@Override
public final void assertNotClosed() {
if (this.isClosed())
this.throwClosed();
}
@ManualStateManipulation
@Override
public final void startUsage() {
if (this.startUsageIfNotClosed())
this.throwClosed();
}
@ManualStateManipulation
@Override
public final boolean startUsageIfNotClosed() {
while (true) {
switch (this._currentState.compareAndExchange(State.OPEN, State.IN_USE)) {
case IN_USE:
Thread.onSpinWait();
continue;
case CLOSED:
return true;
case OPEN:
return false;
}
}
}
private void _finishUsage(State nextState) {
switch (this._currentState.compareAndExchange(State.IN_USE, nextState)) {
case OPEN:
throw new IllegalStateException("Can't finish usage because it isn't started");
case CLOSED:
this.throwClosed();
case IN_USE:
}
}
@ManualStateManipulation
@Override
public final void finishUsage() {
this._finishUsage(State.OPEN);
}
@ManualStateManipulation
@Override
public void finishUsage(boolean close) {
this._finishUsage(close ? State.CLOSED : State.OPEN);
}
@Destructor
@ManualStateManipulation
@Override
public final void close() {
while (true) {
switch (this._currentState.compareAndExchange(State.OPEN, State.CLOSED)) {
case CLOSED:
this.throwClosed();
case IN_USE:
Thread.onSpinWait();
continue;
case OPEN:
return;
}
}
}
@Override
public String toString() {
switch (this._currentState.get()) {
case CLOSED:
return "<closeable spinlock-synchronized state [free]>";
case IN_USE:
return "<closeable spinlock-synchronized state [in use]>";
case OPEN:
return "<closeable spinlock-synchronized state [closed]>";
}
throw new RuntimeException("Unreachable");
}
}

View File

@ -0,0 +1,97 @@
package ru.landgrafhomyak.utility.closeable_state_1;
import java.util.Objects;
public final class jCloseableStateCloseableWrapper
implements CloseableState.ExternallySynchronized {
private final CloseableState.ExternallySynchronized _parent;
private final CloseableState.ExternallySynchronized _self;
public jCloseableStateCloseableWrapper(CloseableState.ExternallySynchronized parent, CloseableState.ExternallySynchronized self) {
Objects.requireNonNull(parent, "param: parent");
Objects.requireNonNull(self, "param: self");
this._parent = parent;
this._self = self;
}
@Override
public boolean isInUse() {
return this._self.isInUse();
}
@Override
public boolean isClosed() {
return this._self.isClosed();
}
@Override
public void assertNotClosed() {
this._self.assertNotClosed();
}
@ManualStateManipulation
@Override
public void startUsage() {
this._self.startUsage();
try {
this._parent.startUsage();
} catch (Throwable e1) {
try {
this._self.finishUsage();
} catch (Throwable e2) {
e1.addSuppressed(e2);
}
throw e1;
}
}
@ManualStateManipulation
@Override
public boolean startUsageIfNotClosed() {
if (this._self.startUsageIfNotClosed())
return true;
try {
if (this._parent.startUsageIfNotClosed()) {
this._self.finishUsage();
return true;
}
} catch (Throwable e1) {
try {
this._self.finishUsage();
} catch (Throwable e2) {
e1.addSuppressed(e2);
}
throw e1;
}
return false;
}
@ManualStateManipulation
@Override
public void finishUsage() {
this._parent.finishUsage();
this._self.finishUsage();
}
@ManualStateManipulation
@Override
public void finishUsage(boolean close) {
this._parent.finishUsage();
this._self.finishUsage(close);
}
@Destructor
@ManualStateManipulation
@Override
public void close() {
this._self.close();
}
@Override
public String toString() {
return "<closeable state " + this._parent + " wrapped with " + this._self + ">";
}
}

View File

@ -0,0 +1,104 @@
package ru.landgrafhomyak.utility.closeable_state_1;
import java.util.concurrent.atomic.AtomicReference;
public /* open */ class jErrorOnConcurrentAccessState
extends jErrorOnConcurrentAccessState$Errors
implements CloseableState.ExternallySynchronized {
private enum State {
OPEN, IN_USE, CLOSED
}
private final AtomicReference<State> _currentState;
public jErrorOnConcurrentAccessState() {
this._currentState = new AtomicReference<>(State.OPEN);
}
@Override
public final boolean isInUse() {
return this._currentState.get() == State.IN_USE;
}
@Override
public final boolean isClosed() {
return this._currentState.get() == State.CLOSED;
}
@Override
public final void assertNotClosed() {
if (this.isClosed())
this.throwClosed();
}
@ManualStateManipulation
@Override
public final void startUsage() {
if (this.startUsageIfNotClosed())
this.throwClosed();
}
@ManualStateManipulation
@Override
public final boolean startUsageIfNotClosed() {
switch (this._currentState.compareAndExchange(State.OPEN, State.IN_USE)) {
case IN_USE:
this.throwConcurrent();
case CLOSED:
return true;
case OPEN:
return false;
}
throw new RuntimeException("Unreachable");
}
private void _finishUsage(State nextState) {
switch (this._currentState.compareAndExchange(State.IN_USE, nextState)) {
case OPEN:
throw new IllegalStateException("Can't finish usage because it isn't started");
case CLOSED:
this.throwClosed();
case IN_USE:
}
}
@ManualStateManipulation
@Override
public final void finishUsage() {
this._finishUsage(State.OPEN);
}
@ManualStateManipulation
@Override
public void finishUsage(boolean close) {
this._finishUsage(close ? State.CLOSED : State.OPEN);
}
@Destructor
@ManualStateManipulation
@Override
public final void close() {
switch (this._currentState.compareAndExchange(State.OPEN, State.CLOSED)) {
case CLOSED:
this.throwClosed();
case IN_USE:
this.throwInUse();
case OPEN:
}
}
@Override
public String toString() {
switch (this._currentState.get()) {
case CLOSED:
return "<closeable error-on-concurrent-access state [free]>";
case IN_USE:
return "<closeable error-on-concurrent-access state [in use]>";
case OPEN:
return "<closeable error-on-concurrent-access state [closed]>";
}
throw new RuntimeException("Unreachable");
}
}

View File

@ -0,0 +1,85 @@
package ru.landgrafhomyak.utility.closeable_state_1;
import java.util.concurrent.atomic.AtomicLong;
public /* open */ class jUsagesCounter
extends jUsagesCounter$Errors
implements CloseableState.AllowsConcurrency {
private final AtomicLong _currentUsagesCount;
public jUsagesCounter() {
this._currentUsagesCount = new AtomicLong(0);
}
@Override
public final boolean isClosed() {
return this._currentUsagesCount.get() < 0;
}
@Override
public final void assertNotClosed() {
if (this._currentUsagesCount.get() < 0)
this.throwClosed();
}
@ManualStateManipulation
@Override
public final void startUsage() {
if (this.startUsageIfNotClosed())
this.throwClosed();
}
@ManualStateManipulation
@Override
public final boolean startUsageIfNotClosed() {
while (true) {
final long cur = this._currentUsagesCount.get();
if (cur < 0) {
return true;
}
if (this._currentUsagesCount.compareAndSet(cur, cur + 1))
return false;
}
}
@ManualStateManipulation
@Override
public final void finishUsage() {
while (true) {
final long cur = this._currentUsagesCount.get();
if (cur < 0) {
this.throwClosed();
return;
}
if (this._currentUsagesCount.compareAndSet(cur, cur - 1))
return;
}
}
@Destructor
@ManualStateManipulation
@Override
public final void close() {
long currentReferencesCount;
while (true) {
currentReferencesCount = this._currentUsagesCount.get();
if (currentReferencesCount != 0) break;
if (this._currentUsagesCount.compareAndSet(currentReferencesCount, _MiscMultiplatform.CLOSED_STATE_VALUE))
break;
}
if (currentReferencesCount > 0) this.throwInUse();
if (currentReferencesCount < 0) this.throwClosed();
}
@Override
public String toString() {
final long cached = this._currentUsagesCount.get();
if (cached < 0)
return "<closeable usages counter [closed]>";
else
return "<closeable usages counter [" + cached + "]>";
}
}

View File

@ -0,0 +1,33 @@
@file:OptIn(ExperimentalContracts::class)
package ru.landgrafhomyak.utility.closeable_state_1
import kotlin.contracts.ExperimentalContracts
public class OwnedSpinLockSynchronizedState : SpinLockSynchronizedState {
private var _owner: Any?
public constructor() : super() {
this._owner = null
}
public constructor(owner: Any) : super() {
this._owner = owner
}
public var owner: Any
get() = this._owner ?: throw IllegalStateException("Owner not set yet")
set(value) {
if (this._owner != null) throw IllegalStateException("Owner already initialized")
this._owner = value
}
override fun throwClosed(): Nothing {
throw IllegalStateException("Object is closed: ${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,7 @@
package ru.landgrafhomyak.utility.closeable_state_1
internal abstract class `SpinLockSynchronizedState$Errors` : CloseableState.ExternallySynchronized {
protected open fun throwClosed(): Nothing {
throw IllegalStateException("Object is closed")
}
}

View File

@ -0,0 +1,5 @@
package ru.landgrafhomyak.utility.closeable_state_1
public actual typealias UsagesCounter = jUsagesCounter
public actual typealias ErrorOnConcurrentAccessState = jErrorOnConcurrentAccessState
public actual typealias CloseableStateCloseableWrapper = jCloseableStateCloseableWrapper

View File

@ -0,0 +1,15 @@
package ru.landgrafhomyak.utility.closeable_state_1
internal abstract class `jErrorOnConcurrentAccessState$Errors` : CloseableState.ExternallySynchronized {
protected open fun throwClosed(): Nothing {
throw IllegalStateException("Object is closed")
}
protected open fun throwInUse(): Nothing {
throw IllegalStateException("Failed close object because it is in use")
}
protected open fun throwConcurrent(): Nothing {
throw IllegalStateException("Object is in use by another thread")
}
}

View File

@ -0,0 +1,11 @@
package ru.landgrafhomyak.utility.closeable_state_1
internal abstract class `jUsagesCounter$Errors` {
protected open fun throwClosed(): Nothing {
throw IllegalStateException("Object is closed")
}
protected open fun throwInUse(): Nothing {
throw IllegalStateException("Failed close object because it is in use")
}
}

View File

@ -1,58 +0,0 @@
package ru.landgrafhomyak.utility.reference_counter
import java.util.concurrent.atomic.AtomicLong
internal actual /*value*/ class _AtomicLong {
private val _native: AtomicLong
actual constructor(initial: Long) {
this._native = AtomicLong(initial)
}
actual fun get() = this._native.get()
actual inline fun update(operator: (Long) -> Long) {
while (true) {
val cur = this._native.get()
val upd = operator(cur)
if (this._native.compareAndSet(cur, upd)) return
}
}
actual inline fun getAndUpdate(operator: (Long) -> Long): Long {
while (true) {
val cur = this._native.get()
val upd = operator(cur)
if (this._native.compareAndSet(cur, upd)) return cur
}
}
actual fun compareAndSet(expected: Long, newValue: Long): Boolean =
this._native.compareAndSet(expected, newValue)
actual fun compareAndExchange(expected: Long, newValue: Long): Long {
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 {
@JvmField
val _isNativeCompareAndExchangeExists = run {
val a = AtomicLong()
try {
a.compareAndExchange(0, 0)
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_1.tests
import org.testng.annotations.Test
import ru.landgrafhomyak.utility.highlevel_try_finally.safeAutoClose1
import ru.landgrafhomyak.utility.closeable_state_1.ManualStateManipulation
import ru.landgrafhomyak.utility.closeable_state_1.UsagesCounter
import ru.landgrafhomyak.utility.closeable_state_1.withUse
@Test(enabled = false)
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.withUse {
return@withUse CustomUnit
}
refcnt.withUse w1@{
return@w1 refcnt.withUse 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.withUse {
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

@ -0,0 +1,78 @@
package ru.landgrafhomyak.utility.closeable_state_1
public actual class CloseableStateCloseableWrapper : CloseableState.ExternallySynchronized {
private val _parent: CloseableState.ExternallySynchronized
private val _self: CloseableState.ExternallySynchronized
public actual constructor(
parent: CloseableState.ExternallySynchronized,
self: CloseableState.ExternallySynchronized,
) {
this._parent = parent
this._self = self
}
actual override val isInUse: Boolean
get() = this._self.isInUse
actual override val isClosed: Boolean
get() = this._self.isClosed
actual override fun assertNotClosed(): Unit =
this._self.assertNotClosed()
@ManualStateManipulation
actual override fun startUsage() {
this._self.startUsage()
try {
this._parent.startUsage()
} catch (e1: Throwable) {
try {
this._self.finishUsage()
} catch (e2: Throwable) {
e1.addSuppressed(e2)
}
throw e1
}
}
@ManualStateManipulation
actual override fun startUsageIfNotClosed(): Boolean {
if (this._self.startUsageIfNotClosed())
return true
try {
if (this._parent.startUsageIfNotClosed()) {
this._self.finishUsage()
return true
}
} catch (e1: Throwable) {
try {
this._self.finishUsage()
} catch (e2: Throwable) {
e1.addSuppressed(e2)
}
throw e1
}
return false;
}
@ManualStateManipulation
actual override fun finishUsage() {
this._parent.finishUsage()
this._self.finishUsage()
}
@ManualStateManipulation
actual override fun finishUsage(close: Boolean) {
this._parent.finishUsage()
this._self.finishUsage(close)
}
@Destructor
@ManualStateManipulation
actual override fun close() {
this._self.close()
}
actual override fun toString(): String = "<closeable state ${this._parent} wrapped with ${this._self}>"
}

View File

@ -0,0 +1,86 @@
package ru.landgrafhomyak.utility.closeable_state_1
import kotlinx.atomicfu.atomic
import ru.landgrafhomyak.utility.closeable_state_1._MiscNonJvm.compareAndExchange
public actual open class ErrorOnConcurrentAccessState : CloseableState.ExternallySynchronized {
private enum class State {
OPEN, IN_USE, CLOSED
}
private val _state = atomic(State.OPEN)
public actual final override val isInUse: Boolean
get() = this._state.value === State.IN_USE
protected actual open fun throwClosed(): Nothing {
throw IllegalStateException("Object is closed")
}
protected actual open fun throwInUse(): Nothing {
throw IllegalStateException("Failed close object because it is in use")
}
protected actual open fun throwConcurrent(): Nothing {
throw IllegalStateException("Object is in use by another thread")
}
public actual final override fun assertNotClosed() {
if (this._state.value === State.CLOSED)
this.throwClosed()
}
public actual final override val isClosed: Boolean
get() = this._state.value === State.CLOSED
@ManualStateManipulation
public actual final override fun startUsage() {
if (this.startUsageIfNotClosed())
this.throwClosed()
}
@ManualStateManipulation
public actual final override fun startUsageIfNotClosed(): Boolean {
when (this._state.compareAndExchange(State.OPEN, State.IN_USE)) {
State.OPEN -> return false;
State.IN_USE -> this.throwConcurrent()
State.CLOSED -> return true
}
}
@ManualStateManipulation
private fun _finishUsage(nextState: State) {
when (this._state.compareAndExchange(State.IN_USE, nextState)) {
State.OPEN -> throw IllegalStateException("Can't finish usage because it isn't started")
State.IN_USE -> {}
State.CLOSED -> this.throwClosed()
}
}
@ManualStateManipulation
public actual final override fun finishUsage(): Unit =
this._finishUsage(State.OPEN)
@ManualStateManipulation
public actual final override fun finishUsage(close: Boolean): Unit =
this._finishUsage(if (close) State.CLOSED else State.OPEN)
@Destructor
@ManualStateManipulation
public actual final override fun close() {
when (this._state.compareAndExchange(State.OPEN, State.CLOSED)) {
State.OPEN -> {}
State.IN_USE -> this.throwInUse()
State.CLOSED -> this.throwClosed()
}
}
@Suppress("RedundantModalityModifier")
public actual open override fun toString(): String =
when (this._state.value) {
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 [closed]>"
}
}

View File

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

View File

@ -0,0 +1,24 @@
package ru.landgrafhomyak.utility.closeable_state_1
import kotlin.jvm.JvmStatic
import kotlinx.atomicfu.AtomicLong
import kotlinx.atomicfu.AtomicRef
import kotlinx.atomicfu.getAndUpdate
internal object _MiscNonJvm {
@JvmStatic
internal fun AtomicLong.compareAndExchange(expected: Long, newValue: Long): Long {
return this.getAndUpdate { old ->
if (old != expected) return@compareAndExchange old
return@getAndUpdate newValue
}
}
@JvmStatic
internal fun <T> AtomicRef<T>.compareAndExchange(expected: T, newValue: T): T {
return this.getAndUpdate { old ->
if (old != expected) return@compareAndExchange old
return@getAndUpdate newValue
}
}
}

View File

@ -1,35 +0,0 @@
package ru.landgrafhomyak.utility.reference_counter
import kotlinx.atomicfu.AtomicLong
import kotlinx.atomicfu.atomic
import kotlinx.atomicfu.getAndUpdate
import kotlinx.atomicfu.update
internal actual class _AtomicLong {
val _atomicfu: AtomicLong
actual constructor(initial: Long) {
this._atomicfu = atomic(0L)
}
actual fun get() =
this._atomicfu.value
actual inline fun update(operator: (Long) -> Long) =
this._atomicfu.update(operator)
actual inline fun getAndUpdate(operator: (Long) -> Long) =
this._atomicfu.getAndUpdate(operator)
actual fun compareAndSet(expected: Long, newValue: Long): Boolean =
this._atomicfu.compareAndSet(expected, newValue)
actual fun compareAndExchange(expected: Long, newValue: Long): Long {
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) {
}
}