startUsageIfNotClosed

This commit is contained in:
Andrew Golovashevich 2025-09-15 01:27:28 +03:00
parent 4ff6c0beb3
commit 8fc08d3e26
12 changed files with 110 additions and 7 deletions

View File

@ -82,6 +82,7 @@ xomrk {
jvmTest {
dependencies {
implementation(kotlinStdlibDependency)
implementation("org.testng:testng:7.5.1")
}
}

View File

@ -25,6 +25,10 @@ public sealed class ChildCloseableState<T : CloseableState> : CloseableState {
override fun startUsage(): Unit =
this._state.startUsage()
@ManualStateManipulation
override fun startUsageIfNotClosed(): Boolean =
this._state.startUsageIfNotClosed()
@ManualStateManipulation
override fun finishUsage(): Unit =
this._state.finishUsage()

View File

@ -8,6 +8,13 @@ public interface CloseableState {
@ManualStateManipulation
public fun startUsage()
/**
* Tries to start usage and returns `false` if entered or `true` if closed.
* Doesn't prevent from throwing error if this state forbids concurrent access.
*/
@ManualStateManipulation
public fun startUsageIfNotClosed(): Boolean
@ManualStateManipulation
public fun finishUsage()

View File

@ -13,6 +13,9 @@ public expect class CloseableStateCloseableWrapper : CloseableState.ExternallySy
@ManualStateManipulation
override fun startUsage()
@ManualStateManipulation
override fun startUsageIfNotClosed(): Boolean
@ManualStateManipulation
override fun finishUsage()

View File

@ -18,6 +18,9 @@ public expect open class ErrorOnConcurrentAccessState : CloseableState.Externall
@ManualStateManipulation
public final override fun startUsage()
@ManualStateManipulation
public final override fun startUsageIfNotClosed(): Boolean
@ManualStateManipulation
public final override fun finishUsage()

View File

@ -19,6 +19,9 @@ public expect open class UsagesCounter : CloseableState.AllowsConcurrency {
@ManualStateManipulation
public final override fun startUsage()
@ManualStateManipulation
public final override fun startUsageIfNotClosed(): Boolean
@ManualStateManipulation
public final override fun finishUsage()

View File

@ -31,6 +31,7 @@ public final class jCloseableStateCloseableWrapper
this._self.assertNotClosed();
}
@ManualStateManipulation
@Override
public void startUsage() {
this._self.startUsage();
@ -46,12 +47,35 @@ public final class jCloseableStateCloseableWrapper
}
}
@ManualStateManipulation
@Override
public boolean startUsageIfNotClosed() {
if (this._self.startUsageIfNotClosed())
return true;
try {
if (this._parent.startUsageIfNotClosed()) {
this._self.finishUsage();
return true;
}
} catch (Throwable e1) {
try {
this._self.finishUsage();
} catch (Throwable e2) {
e1.addSuppressed(e2);
}
throw e1;
}
return false;
}
@ManualStateManipulation
@Override
public void finishUsage() {
this._parent.finishUsage();
this._self.finishUsage();
}
@ManualStateManipulation
@Override
public void finishUsage(boolean close) {
this._parent.finishUsage();
@ -59,6 +83,7 @@ public final class jCloseableStateCloseableWrapper
}
@Destructor
@ManualStateManipulation
@Override
public void close() {
this._self.close();
@ -68,4 +93,5 @@ public final class jCloseableStateCloseableWrapper
public String toString() {
return "<closeable state " + this._parent + " wrapped with " + this._self + ">";
}
}

View File

@ -32,16 +32,25 @@ public /* open */ class jErrorOnConcurrentAccessState
this.throwClosed();
}
@ManualStateManipulation
@Override
public final void startUsage() {
if (this.startUsageIfNotClosed())
this.throwClosed();
}
@ManualStateManipulation
@Override
public final boolean startUsageIfNotClosed() {
switch (this._currentState.compareAndExchange(State.OPEN, State.IN_USE)) {
case IN_USE:
this.throwConcurrent();
case CLOSED:
this.throwClosed();
return true;
case OPEN:
break;
return false;
}
throw new RuntimeException("Unreachable");
}
private void _finishUsage(State nextState) {
@ -55,17 +64,20 @@ public /* open */ class jErrorOnConcurrentAccessState
}
@ManualStateManipulation
@Override
public final void finishUsage() {
this._finishUsage(State.OPEN);
}
@ManualStateManipulation
@Override
public void finishUsage(boolean close) {
this._finishUsage(close ? State.CLOSED : State.OPEN);
}
@Destructor
@ManualStateManipulation
@Override
public final void close() {
switch (this._currentState.compareAndExchange(State.OPEN, State.CLOSED)) {

View File

@ -22,20 +22,28 @@ public /* open */ class jUsagesCounter
this.throwClosed();
}
@ManualStateManipulation
@Override
public final void startUsage() {
if (this.startUsageIfNotClosed())
this.throwClosed();
}
@ManualStateManipulation
@Override
public final boolean startUsageIfNotClosed() {
while (true) {
final long cur = this._currentUsagesCount.get();
if (cur < 0) {
this.throwClosed();
return;
return true;
}
if (this._currentUsagesCount.compareAndSet(cur, cur + 1))
return;
return false;
}
}
@ManualStateManipulation
@Override
public final void finishUsage() {
while (true) {
@ -51,6 +59,7 @@ public /* open */ class jUsagesCounter
}
@Destructor
@ManualStateManipulation
@Override
public final void close() {
long currentReferencesCount;

View File

@ -36,6 +36,26 @@ public actual class CloseableStateCloseableWrapper : CloseableState.ExternallySy
}
}
@ManualStateManipulation
actual override fun startUsageIfNotClosed(): Boolean {
if (this._self.startUsageIfNotClosed())
return true
try {
if (this._parent.startUsageIfNotClosed()) {
this._self.finishUsage()
return true
}
} catch (e1: Throwable) {
try {
this._self.finishUsage()
} catch (e2: Throwable) {
e1.addSuppressed(e2)
}
throw e1
}
return false;
}
@ManualStateManipulation
actual override fun finishUsage() {
this._parent.finishUsage()

View File

@ -35,10 +35,16 @@ public actual open class ErrorOnConcurrentAccessState : CloseableState.Externall
@ManualStateManipulation
public actual final override fun startUsage() {
if (this.startUsageIfNotClosed())
this.throwClosed()
}
@ManualStateManipulation
public actual final override fun startUsageIfNotClosed(): Boolean {
when (this._state.compareAndExchange(State.OPEN, State.IN_USE)) {
State.OPEN -> {}
State.OPEN -> return false;
State.IN_USE -> this.throwConcurrent()
State.CLOSED -> this.throwClosed()
State.CLOSED -> return true
}
}

View File

@ -38,6 +38,15 @@ public actual open class UsagesCounter : CloseableState.AllowsConcurrency {
}
}
@ManualStateManipulation
public actual final override fun startUsageIfNotClosed(): Boolean {
this._value.update { o ->
if (o < 0) return true
return@update o + 1
}
return false
}
@ManualStateManipulation
public actual final override fun finishUsage() {
this._value.update(Long::dec)