Compare commits
No commits in common. "master" and "v0.1" have entirely different histories.
@ -1,4 +1,3 @@
|
|||||||
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
|
||||||
@ -15,10 +14,11 @@ buildscript {
|
|||||||
}
|
}
|
||||||
|
|
||||||
group = "ru.landgrafhomyak.utility"
|
group = "ru.landgrafhomyak.utility"
|
||||||
version = "0.2"
|
version = "0.1"
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
maven("https://maven.landgrafhomyak.ru/")
|
||||||
}
|
}
|
||||||
|
|
||||||
xomrk {
|
xomrk {
|
||||||
@ -26,78 +26,16 @@ xomrk {
|
|||||||
setCompatibilityWithKotlin(KotlinVersion.KOTLIN_2_0)
|
setCompatibilityWithKotlin(KotlinVersion.KOTLIN_2_0)
|
||||||
optInContracts()
|
optInContracts()
|
||||||
explicitApi()
|
explicitApi()
|
||||||
noWarnExpectActual()
|
|
||||||
warningsAsErrors()
|
|
||||||
|
|
||||||
defineAllMultiplatformTargets()
|
defineAllMultiplatformTargets()
|
||||||
|
|
||||||
jvmToolchain(11)
|
|
||||||
jvm {
|
|
||||||
withJava()
|
|
||||||
|
|
||||||
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 {
|
sourceSets {
|
||||||
// if use kotlin("stdlib") gitea ui brokes at paragraph with dependency versions
|
commonMain {
|
||||||
val kotlinStdlibDependency = "org.jetbrains.kotlin:kotlin-stdlib:${this@kotlin.coreLibrariesVersion}"
|
|
||||||
|
|
||||||
val commonMain by getting {
|
|
||||||
dependencies {
|
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")
|
implementation("org.jetbrains.kotlinx:atomicfu:0.27.0")
|
||||||
|
implementation("ru.landgrafhomyak.utility:highlevel-try-finally:0.4")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1 @@
|
|||||||
kotlin.stdlib.default.dependency=false
|
kotlin.code.style=official
|
||||||
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 099c3fad269770649d5a67acd3cd07e378bc9f37
|
Subproject commit 88c8da21e4ec11c9755b6770565685bdc29acbca
|
@ -5,26 +5,19 @@ package ru.landrafhomyak.utility.reference_counter
|
|||||||
import kotlin.contracts.ExperimentalContracts
|
import kotlin.contracts.ExperimentalContracts
|
||||||
import kotlin.contracts.InvocationKind
|
import kotlin.contracts.InvocationKind
|
||||||
import kotlin.contracts.contract
|
import kotlin.contracts.contract
|
||||||
import kotlin.jvm.JvmName
|
import kotlinx.atomicfu.AtomicLong
|
||||||
|
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 {
|
public class CloseableReferenceCounter(private val _errMessage: String) {
|
||||||
private val _value: _AtomicLong
|
private val _value: AtomicLong = atomic(0L)
|
||||||
private val _errMessageClosed: String
|
|
||||||
|
|
||||||
public constructor(errMessageClosed: String) {
|
|
||||||
_Platform.jvm_assertNotNull(errMessageClosed, "param: errMessageClosed")
|
|
||||||
this._errMessageClosed = errMessageClosed
|
|
||||||
this._value = _AtomicLong(0L)
|
|
||||||
}
|
|
||||||
|
|
||||||
@JvmName("throwClosed")
|
|
||||||
public fun throwClosed() {
|
public fun throwClosed() {
|
||||||
throw IllegalStateException(this._errMessageClosed)
|
throw IllegalStateException(this._errMessage)
|
||||||
}
|
}
|
||||||
|
|
||||||
@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()
|
||||||
@ -32,7 +25,6 @@ public class CloseableReferenceCounter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@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)
|
||||||
@ -41,17 +33,14 @@ public class CloseableReferenceCounter {
|
|||||||
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.get() < 0) this.throwClosed()
|
if (this._value.value < 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)
|
||||||
@ -60,27 +49,21 @@ public class CloseableReferenceCounter {
|
|||||||
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) {
|
||||||
_Platform.jvm_assertNotNull(errExistRefs, "param: errExistRefs")
|
val state = _CloseableReferenceCounter_LowLevel.compareAndExchange(this._value, 0, _CloseableReferenceCounter_LowLevel.CLOSED_STATE_VALUE)
|
||||||
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.get()
|
val refcntCached = this._value.value
|
||||||
@Suppress("LiftReturnOrAssignment")
|
@Suppress("LiftReturnOrAssignment")
|
||||||
if (refcntCached < 0)
|
if (refcntCached < 0)
|
||||||
return "<ref counter [closed]>"
|
return "<ref counter [closed]>"
|
||||||
|
@ -5,12 +5,19 @@ package ru.landrafhomyak.utility.reference_counter
|
|||||||
import kotlin.contracts.ExperimentalContracts
|
import kotlin.contracts.ExperimentalContracts
|
||||||
import kotlin.contracts.InvocationKind
|
import kotlin.contracts.InvocationKind
|
||||||
import kotlin.contracts.contract
|
import kotlin.contracts.contract
|
||||||
import kotlin.jvm.JvmName
|
import kotlinx.atomicfu.AtomicLong
|
||||||
|
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)
|
||||||
}
|
}
|
||||||
@ -19,46 +26,30 @@ 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
|
|
||||||
|
|
||||||
public constructor(dbgName: String, errMessage: String, logger: Observer? = null) {
|
private val _value: AtomicLong = atomic(0L)
|
||||||
_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")
|
@Suppress("RemoveRedundantQualifierName")
|
||||||
this._id = CloseableReferenceCounter_Debug._nextId.getAndUpdate(Long::inc)
|
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 == _Misc.CLOSED_STATE_VALUE -> {}
|
valueToCheck >= 0 || valueToCheck == _CloseableReferenceCounter_LowLevel.CLOSED_STATE_VALUE -> {}
|
||||||
valueToCheck < _Misc.CLOSED_STATE_VALUE -> throw RuntimeException("Too many references")
|
valueToCheck < _CloseableReferenceCounter_LowLevel.CLOSED_STATE_VALUE -> throw RuntimeException("Too many references")
|
||||||
valueToCheck > _Misc.CLOSED_STATE_VALUE -> throw RuntimeException(".decref called more times than .incref")
|
valueToCheck > _CloseableReferenceCounter_LowLevel.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.get())
|
this._throwErrors(this._value.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
@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) {
|
||||||
@ -71,7 +62,6 @@ 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)
|
||||||
@ -80,12 +70,10 @@ 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.get() < 0) this.throwClosed()
|
if (this._value.value < 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) {
|
||||||
@ -98,7 +86,6 @@ 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)
|
||||||
@ -107,18 +94,8 @@ 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) {
|
||||||
_Platform.jvm_assertNotNull(errExistRefs, "param: errExistRefs")
|
val state = _CloseableReferenceCounter_LowLevel.compareAndExchange(this._value, 0, _CloseableReferenceCounter_LowLevel.CLOSED_STATE_VALUE)
|
||||||
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)
|
||||||
@ -127,34 +104,31 @@ 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.get()
|
val refcntCached = this._value.value
|
||||||
val stateRepr: String
|
val stateRepr: String
|
||||||
@Suppress("LiftReturnOrAssignment")
|
@Suppress("LiftReturnOrAssignment")
|
||||||
when {
|
when {
|
||||||
refcntCached >= 0 -> stateRepr = refcntCached.toString()
|
refcntCached >= 0 -> stateRepr = refcntCached.toString()
|
||||||
refcntCached == _Misc.CLOSED_STATE_VALUE -> stateRepr = "closed"
|
refcntCached == _CloseableReferenceCounter_LowLevel.CLOSED_STATE_VALUE -> stateRepr = "closed"
|
||||||
refcntCached < _Misc.CLOSED_STATE_VALUE -> stateRepr = "overflow"
|
refcntCached < _CloseableReferenceCounter_LowLevel.CLOSED_STATE_VALUE -> stateRepr = "overflow"
|
||||||
refcntCached > _Misc.CLOSED_STATE_VALUE -> stateRepr = "underflow"
|
refcntCached > _CloseableReferenceCounter_LowLevel.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 = _AtomicLong(0L)
|
private val _nextId = atomic(0uL)
|
||||||
}
|
}
|
||||||
|
|
||||||
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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
@ -0,0 +1,16 @@
|
|||||||
|
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
|
||||||
|
}
|
@ -1,17 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
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)
|
|
||||||
}
|
|
@ -1,58 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,130 +0,0 @@
|
|||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,35 +0,0 @@
|
|||||||
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
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
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) {
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user