closeable-state.kt/src/commonMain/kotlin/ru/landgrafhomyak/utility/closeable_state/UsagesCounter.kt

65 lines
1.8 KiB
Kotlin

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