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 } } }