commit be4c578491d39492126c114f62e25eadd8eedef8 Author: Andrew Golovashevich Date: Tue Mar 18 20:28:40 2025 +0300 [history] Functionality extracted from some class diff --git a/src/commonMain/kotlin/ru/landrafhomyak/utility/reference_counter/CloseableReferenceCounter.kt b/src/commonMain/kotlin/ru/landrafhomyak/utility/reference_counter/CloseableReferenceCounter.kt new file mode 100644 index 0000000..f5f49d0 --- /dev/null +++ b/src/commonMain/kotlin/ru/landrafhomyak/utility/reference_counter/CloseableReferenceCounter.kt @@ -0,0 +1,56 @@ +package ru.landrafhomyak.utility.reference_counter + +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.safeAutoClose2 + +internal class CloseableReferenceCounter(private val _errMessage: String) { + private val _value: AtomicLong = atomic(0L) + + fun throwClosed() { + throw IllegalStateException(this._errMessage) + } + + fun incref() { + this._value.update { o -> + if (o < 0) this.throwClosed() + return@update o + 1 + } + } + + inline fun tryIncref(block: () -> R): R { + this.incref() + return safeAutoClose2(onError = this::decref, action = block) + } + + fun checkNotClosed() { + if (this._value.value < 0) this.throwClosed() + } + + fun decref() { + this._value.update(Long::dec) + } + + fun close(errExistRefs: String) { + val state = this._value.compareAndExchange(0, -1) + when { + state > 0 -> throw IllegalStateException(errExistRefs) + state < 0 -> this.throwClosed() + } + } + + inline fun withRef(protected: () -> R): R { + this.incref() + return safeAutoClose1(finally = this::decref, action = protected) + } + + private fun AtomicLong.compareAndExchange(expected: Long, newValue: Long): Long { + while (true) { + val old = this@compareAndExchange.value + if (old != expected) return old + if (this@compareAndExchange.compareAndSet(old, newValue)) return old + } + } +} \ No newline at end of file