Compare commits

...

11 Commits
v0.1 ... master

14 changed files with 443 additions and 58 deletions

View File

@ -1,3 +1,4 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion import org.jetbrains.kotlin.gradle.dsl.KotlinVersion
import ru.landgrafhomyak.kotlin.kmp_gradle_build_helper.* import ru.landgrafhomyak.kotlin.kmp_gradle_build_helper.*
import ru.landgrafhomyak.kotlin.kmp_gradle_build_helper.plugin.xomrk import ru.landgrafhomyak.kotlin.kmp_gradle_build_helper.plugin.xomrk
@ -14,11 +15,10 @@ buildscript {
} }
group = "ru.landgrafhomyak.utility" group = "ru.landgrafhomyak.utility"
version = "0.1" version = "0.2"
repositories { repositories {
mavenCentral() mavenCentral()
maven("https://maven.landgrafhomyak.ru/")
} }
xomrk { xomrk {
@ -26,15 +26,77 @@ xomrk {
setCompatibilityWithKotlin(KotlinVersion.KOTLIN_2_0) setCompatibilityWithKotlin(KotlinVersion.KOTLIN_2_0)
optInContracts() optInContracts()
explicitApi() explicitApi()
noWarnExpectActual()
warningsAsErrors()
defineAllMultiplatformTargets() defineAllMultiplatformTargets()
sourceSets { jvmToolchain(11)
commonMain { jvm {
dependencies { withJava()
implementation("org.jetbrains.kotlinx:atomicfu:0.27.0")
implementation("ru.landgrafhomyak.utility:highlevel-try-finally:0.4") compilations.configureEach {
compileJavaTaskProvider?.configure {
targetCompatibility = "1.8"
} }
compileTaskProvider.configure {
compilerOptions {
jvmTarget = JvmTarget.JVM_1_8
freeCompilerArgs.addAll(
"-Xno-call-assertions",
"-Xno-param-assertions",
"-Xno-receiver-assertions"
)
}
}
}
tasks.named { t -> t == "${this@jvm.name}Test" }.configureEach {
this as Test
useTestNG()
}
}
sourceSets {
// if use kotlin("stdlib") gitea ui brokes at paragraph with dependency versions
val kotlinStdlibDependency = "org.jetbrains.kotlin:kotlin-stdlib:${this@kotlin.coreLibrariesVersion}"
val commonMain by getting {
dependencies {
compileOnly(kotlinStdlibDependency)
implementation("ru.landgrafhomyak.utility:highlevel-try-finally:0.5")
}
}
val jvmMain by getting {
dependsOn(commonMain)
dependencies {
compileOnly(kotlinStdlibDependency)
}
}
val nonJvmMain by creating {
dependsOn(commonMain)
dependencies {
implementation(kotlinStdlibDependency)
implementation("org.jetbrains.kotlinx:atomicfu:0.27.0")
}
}
jvmTest {
dependencies {
implementation("org.testng:testng:7.5.1")
}
}
configureEach {
when {
// commonMain !in dependsOn -> return@configureEach
!name.endsWith("Main") -> return@configureEach
this@configureEach === commonMain -> return@configureEach
this@configureEach === jvmMain -> return@configureEach
this@configureEach === nonJvmMain -> return@configureEach
}
dependsOn(nonJvmMain)
} }
} }
} }

View File

@ -1 +1,6 @@
kotlin.code.style=official kotlin.stdlib.default.dependency=false
kotlin.mpp.applyDefaultHierarchyTemplate=false
kotlin.native.enableKlibsCrossCompilation=true
# compileOnly dependencies from commonMain still throw warning
kotlin.suppressGradlePluginWarnings=IncorrectCompileOnlyDependencyWarning
kotlin.js.stdlib.dom.api.included=false

@ -1 +1 @@
Subproject commit 88c8da21e4ec11c9755b6770565685bdc29acbca Subproject commit 099c3fad269770649d5a67acd3cd07e378bc9f37

View File

@ -5,19 +5,26 @@ package ru.landrafhomyak.utility.reference_counter
import kotlin.contracts.ExperimentalContracts import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.InvocationKind import kotlin.contracts.InvocationKind
import kotlin.contracts.contract import kotlin.contracts.contract
import kotlinx.atomicfu.AtomicLong import kotlin.jvm.JvmName
import kotlinx.atomicfu.atomic
import kotlinx.atomicfu.update
import ru.landgrafhomyak.utility.highlevel_try_finally.safeAutoClose1 import ru.landgrafhomyak.utility.highlevel_try_finally.safeAutoClose1
import ru.landgrafhomyak.utility.highlevel_try_finally.safeAutoClose2 import ru.landgrafhomyak.utility.highlevel_try_finally.safeAutoClose2
public class CloseableReferenceCounter(private val _errMessage: String) { public class CloseableReferenceCounter {
private val _value: AtomicLong = atomic(0L) private val _value: _AtomicLong
private val _errMessageClosed: String
public fun throwClosed() { public constructor(errMessageClosed: String) {
throw IllegalStateException(this._errMessage) _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() { public fun incref() {
this._value.update { o -> this._value.update { o ->
if (o < 0) this.throwClosed() if (o < 0) this.throwClosed()
@ -25,6 +32,7 @@ public class CloseableReferenceCounter(private val _errMessage: String) {
} }
} }
@JvmName("tryIncref\$kt")
public inline fun <R> tryIncref(block: () -> R): R { public inline fun <R> tryIncref(block: () -> R): R {
contract { contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE) callsInPlace(block, InvocationKind.EXACTLY_ONCE)
@ -33,14 +41,17 @@ public class CloseableReferenceCounter(private val _errMessage: String) {
return safeAutoClose2(onError = this::decref, action = block) return safeAutoClose2(onError = this::decref, action = block)
} }
@JvmName("assertNotClosed")
public fun assertNotClosed() { public fun assertNotClosed() {
if (this._value.value < 0) this.throwClosed() if (this._value.get() < 0) this.throwClosed()
} }
@JvmName("decref")
public fun decref() { public fun decref() {
this._value.update(Long::dec) this._value.update(Long::dec)
} }
@JvmName("tryDecref\$kt")
public inline fun <R> tryDecref(block: () -> R): R { public inline fun <R> tryDecref(block: () -> R): R {
contract { contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE) callsInPlace(block, InvocationKind.EXACTLY_ONCE)
@ -49,21 +60,27 @@ public class CloseableReferenceCounter(private val _errMessage: String) {
return safeAutoClose2(onSuccess = this::decref, action = block) return safeAutoClose2(onSuccess = this::decref, action = block)
} }
@get:JvmName("isClosed")
public val isClosed: Boolean get() = this._value.get() < 0
@JvmName("close")
public fun close(errExistRefs: String) { public fun close(errExistRefs: String) {
val state = _CloseableReferenceCounter_LowLevel.compareAndExchange(this._value, 0, _CloseableReferenceCounter_LowLevel.CLOSED_STATE_VALUE) _Platform.jvm_assertNotNull(errExistRefs, "param: errExistRefs")
val state = this._value.compareAndExchange(0, _Misc.CLOSED_STATE_VALUE)
when { when {
state > 0 -> throw IllegalStateException(errExistRefs) state > 0 -> throw IllegalStateException(errExistRefs)
state < 0 -> this.throwClosed() state < 0 -> this.throwClosed()
} }
} }
@JvmName("withRef\$kt")
public inline fun <R> withRef(protected: () -> R): R { public inline fun <R> withRef(protected: () -> R): R {
this.incref() this.incref()
return safeAutoClose1(finally = this::decref, action = protected) return safeAutoClose1(finally = this::decref, action = protected)
} }
override fun toString(): String { override fun toString(): String {
val refcntCached = this._value.value val refcntCached = this._value.get()
@Suppress("LiftReturnOrAssignment") @Suppress("LiftReturnOrAssignment")
if (refcntCached < 0) if (refcntCached < 0)
return "<ref counter [closed]>" return "<ref counter [closed]>"

View File

@ -5,19 +5,12 @@ package ru.landrafhomyak.utility.reference_counter
import kotlin.contracts.ExperimentalContracts import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.InvocationKind import kotlin.contracts.InvocationKind
import kotlin.contracts.contract import kotlin.contracts.contract
import kotlinx.atomicfu.AtomicLong import kotlin.jvm.JvmName
import kotlinx.atomicfu.atomic
import kotlinx.atomicfu.getAndUpdate
import kotlinx.atomicfu.update
import ru.landgrafhomyak.utility.highlevel_try_finally.safeAutoClose1 import ru.landgrafhomyak.utility.highlevel_try_finally.safeAutoClose1
import ru.landgrafhomyak.utility.highlevel_try_finally.safeAutoClose2 import ru.landgrafhomyak.utility.highlevel_try_finally.safeAutoClose2
@CloseableReferenceCounter_Debug.RequiresExplicitDebug @CloseableReferenceCounter_Debug.RequiresExplicitDebug
public class CloseableReferenceCounter_Debug( public class CloseableReferenceCounter_Debug {
private val _dbgName: String,
private val _errMessage: String,
private val _logger: Observer? = null,
) {
public fun interface Observer { public fun interface Observer {
public fun observeState(instance: CloseableReferenceCounter_Debug, actions: String) public fun observeState(instance: CloseableReferenceCounter_Debug, actions: String)
} }
@ -26,30 +19,46 @@ public class CloseableReferenceCounter_Debug(
@Retention(AnnotationRetention.BINARY) @Retention(AnnotationRetention.BINARY)
public annotation class RequiresExplicitDebug public annotation class RequiresExplicitDebug
private val _dbgName: String
private val _errMessage: String
private val _logger: Observer?
private val _value: _AtomicLong
private val _id: Long
private val _value: AtomicLong = atomic(0L) 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("RemoveRedundantQualifierName")
private val _id = CloseableReferenceCounter_Debug._nextId.getAndUpdate(ULong::inc)
@Suppress("NOTHING_TO_INLINE") @Suppress("NOTHING_TO_INLINE")
private inline fun _throwErrors(valueToCheck: Long) { private inline fun _throwErrors(valueToCheck: Long) {
when { when {
valueToCheck >= 0 || valueToCheck == _CloseableReferenceCounter_LowLevel.CLOSED_STATE_VALUE -> {} valueToCheck >= 0 || valueToCheck == _Misc.CLOSED_STATE_VALUE -> {}
valueToCheck < _CloseableReferenceCounter_LowLevel.CLOSED_STATE_VALUE -> throw RuntimeException("Too many references") valueToCheck < _Misc.CLOSED_STATE_VALUE -> throw RuntimeException("Too many references")
valueToCheck > _CloseableReferenceCounter_LowLevel.CLOSED_STATE_VALUE -> throw RuntimeException(".decref called more times than .incref") valueToCheck > _Misc.CLOSED_STATE_VALUE -> throw RuntimeException(".decref called more times than .incref")
} }
} }
@RequiresExplicitDebug @RequiresExplicitDebug
@JvmName("throwErrors")
public fun throwErrors() { public fun throwErrors() {
this._throwErrors(this._value.value) this._throwErrors(this._value.get())
} }
@JvmName("throwClosed")
public fun throwClosed() { public fun throwClosed() {
throw IllegalStateException(this._errMessage) throw IllegalStateException(this._errMessage)
} }
@JvmName("incref")
public fun incref() { public fun incref() {
this._value.update { o -> this._value.update { o ->
if (o < 0) { if (o < 0) {
@ -62,6 +71,7 @@ public class CloseableReferenceCounter_Debug(
this._logger?.observeState(this, "incref") this._logger?.observeState(this, "incref")
} }
@JvmName("tryIncref\$kt")
public inline fun <R> tryIncref(block: () -> R): R { public inline fun <R> tryIncref(block: () -> R): R {
contract { contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE) callsInPlace(block, InvocationKind.EXACTLY_ONCE)
@ -70,10 +80,12 @@ public class CloseableReferenceCounter_Debug(
return safeAutoClose2(onError = this::decref, action = block) return safeAutoClose2(onError = this::decref, action = block)
} }
@JvmName("assertNotClosed")
public fun assertNotClosed() { public fun assertNotClosed() {
if (this._value.value < 0) this.throwClosed() if (this._value.get() < 0) this.throwClosed()
} }
@JvmName("decref")
public fun decref() { public fun decref() {
this._value.update { o -> this._value.update { o ->
if (o < 0) { if (o < 0) {
@ -86,6 +98,7 @@ public class CloseableReferenceCounter_Debug(
this._logger?.observeState(this, "decref") this._logger?.observeState(this, "decref")
} }
@JvmName("tryDecref\$kt")
public inline fun <R> tryDecref(block: () -> R): R { public inline fun <R> tryDecref(block: () -> R): R {
contract { contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE) callsInPlace(block, InvocationKind.EXACTLY_ONCE)
@ -94,8 +107,18 @@ public class CloseableReferenceCounter_Debug(
return safeAutoClose2(onSuccess = this::decref, action = block) 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) { public fun close(errExistRefs: String) {
val state = _CloseableReferenceCounter_LowLevel.compareAndExchange(this._value, 0, _CloseableReferenceCounter_LowLevel.CLOSED_STATE_VALUE) _Platform.jvm_assertNotNull(errExistRefs, "param: errExistRefs")
val state = this._value.compareAndExchange(0, _Misc.CLOSED_STATE_VALUE)
this._throwErrors(state) this._throwErrors(state)
when { when {
state > 0 -> throw IllegalStateException(errExistRefs) state > 0 -> throw IllegalStateException(errExistRefs)
@ -104,31 +127,34 @@ public class CloseableReferenceCounter_Debug(
this._logger?.observeState(this, "closed") this._logger?.observeState(this, "closed")
} }
@JvmName("withRef\$kt")
public inline fun <R> withRef(protected: () -> R): R { public inline fun <R> withRef(protected: () -> R): R {
this.incref() this.incref()
return safeAutoClose1(finally = this::decref, action = protected) return safeAutoClose1(finally = this::decref, action = protected)
} }
override fun toString(): String { override fun toString(): String {
val refcntCached = this._value.value val refcntCached = this._value.get()
val stateRepr: String val stateRepr: String
@Suppress("LiftReturnOrAssignment") @Suppress("LiftReturnOrAssignment")
when { when {
refcntCached >= 0 -> stateRepr = refcntCached.toString() refcntCached >= 0 -> stateRepr = refcntCached.toString()
refcntCached == _CloseableReferenceCounter_LowLevel.CLOSED_STATE_VALUE -> stateRepr = "closed" refcntCached == _Misc.CLOSED_STATE_VALUE -> stateRepr = "closed"
refcntCached < _CloseableReferenceCounter_LowLevel.CLOSED_STATE_VALUE -> stateRepr = "overflow" refcntCached < _Misc.CLOSED_STATE_VALUE -> stateRepr = "overflow"
refcntCached > _CloseableReferenceCounter_LowLevel.CLOSED_STATE_VALUE -> stateRepr = "underflow" refcntCached > _Misc.CLOSED_STATE_VALUE -> stateRepr = "underflow"
else -> throw Error("Unreachable") else -> throw Error("Unreachable")
} }
return "<ref counter \"${this._dbgName}@${this._id}\" [${stateRepr}]>" return "<ref counter \"${this._dbgName}@${this._id}\" [${stateRepr}]>"
} }
public companion object { public companion object {
private val _nextId = atomic(0uL) private val _nextId = _AtomicLong(0L)
} }
public object ObserveToStdout : Observer { public object ObserveToStdout : Observer {
override fun observeState(instance: CloseableReferenceCounter_Debug, actions: String) { override fun observeState(instance: CloseableReferenceCounter_Debug, actions: String) {
_Platform.jvm_assertNotNull(instance, "param: instance")
_Platform.jvm_assertNotNull(actions, "param: actions")
print("${instance} ${actions}\n") print("${instance} ${actions}\n")
} }
} }

View File

@ -0,0 +1,15 @@
package ru.landrafhomyak.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,16 +0,0 @@
package ru.landrafhomyak.utility.reference_counter
import kotlinx.atomicfu.AtomicLong
@Suppress("ClassName")
internal object _CloseableReferenceCounter_LowLevel {
internal fun compareAndExchange(atomic: AtomicLong, expected: Long, newValue: Long): Long {
while (true) {
val old = atomic.value
if (old != expected) return old
if (atomic.compareAndSet(old, newValue)) return old
}
}
internal const val CLOSED_STATE_VALUE = -0x4000_0000_0000_0000L
}

View File

@ -0,0 +1,17 @@
package ru.landrafhomyak.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

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

View File

@ -0,0 +1,58 @@
package ru.landrafhomyak.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

@ -0,0 +1,17 @@
package ru.landrafhomyak.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,130 @@
package ru.landrafhomyak.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.landrafhomyak.utility.reference_counter.CloseableReferenceCounter
import ru.landrafhomyak.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,35 @@
package ru.landrafhomyak.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

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