|
| 1 | +@file:OptIn(ExperimentalContracts::class) |
| 2 | + |
1 | 3 | package arrow.atomic
|
2 | 4 |
|
| 5 | +import kotlin.contracts.ExperimentalContracts |
| 6 | +import kotlin.contracts.InvocationKind |
| 7 | +import kotlin.contracts.contract |
| 8 | + |
3 | 9 | public class AtomicBoolean(value: Boolean) {
|
4 | 10 | private val inner = AtomicInt(value.toInt())
|
5 | 11 |
|
@@ -28,31 +34,55 @@ public class AtomicBoolean(value: Boolean) {
|
28 | 34 | /**
|
29 | 35 | * Infinite loop that reads this atomic variable and performs the specified [action] on its value.
|
30 | 36 | */
|
31 |
| -public inline fun AtomicBoolean.loop(action: (Boolean) -> Unit): Nothing { while(true) { action(value) } } |
| 37 | +public inline fun AtomicBoolean.loop(action: (Boolean) -> Unit): Nothing { |
| 38 | + contract { callsInPlace(action, InvocationKind.AT_LEAST_ONCE) } |
| 39 | + do { action(value) } while(true) |
| 40 | +} |
32 | 41 |
|
33 |
| -public inline fun AtomicBoolean.tryUpdate(function: (Boolean) -> Boolean): Boolean = tryUpdate(function) { _, _ -> } |
| 42 | +public inline fun AtomicBoolean.tryUpdate(function: (Boolean) -> Boolean): Boolean { |
| 43 | + contract { callsInPlace(function, InvocationKind.EXACTLY_ONCE) } |
| 44 | + return tryUpdate(function) { _, _ -> } |
| 45 | +} |
34 | 46 |
|
35 |
| -public inline fun AtomicBoolean.update(function: (Boolean) -> Boolean): Unit = update(function) { _, _ -> } |
| 47 | +public inline fun AtomicBoolean.update(function: (Boolean) -> Boolean) { |
| 48 | + contract { callsInPlace(function, InvocationKind.AT_LEAST_ONCE) } |
| 49 | + update(function) { _, _ -> } |
| 50 | +} |
36 | 51 |
|
37 | 52 | /**
|
38 | 53 | * Updates variable atomically using the specified [function] of its value and returns its old value.
|
39 | 54 | */
|
40 |
| -public inline fun AtomicBoolean.getAndUpdate(function: (Boolean) -> Boolean): Boolean = update(function) { old, _ -> old } |
| 55 | +public inline fun AtomicBoolean.getAndUpdate(function: (Boolean) -> Boolean): Boolean { |
| 56 | + contract { callsInPlace(function, InvocationKind.AT_LEAST_ONCE) } |
| 57 | + return update(function) { old, _ -> old } |
| 58 | +} |
41 | 59 |
|
42 | 60 | /**
|
43 | 61 | * Updates variable atomically using the specified [function] of its value and returns its new value.
|
44 | 62 | */
|
45 |
| -public inline fun AtomicBoolean.updateAndGet(function: (Boolean) -> Boolean): Boolean = update(function) { _, new -> new } |
| 63 | +public inline fun AtomicBoolean.updateAndGet(function: (Boolean) -> Boolean): Boolean { |
| 64 | + contract { callsInPlace(function, InvocationKind.AT_LEAST_ONCE) } |
| 65 | + return update(function) { _, new -> new } |
| 66 | +} |
46 | 67 |
|
47 | 68 | @PublishedApi
|
48 | 69 | internal inline fun <R> AtomicBoolean.update(function: (Boolean) -> Boolean, transform: (old: Boolean, new: Boolean) -> R): R {
|
49 |
| - while (true) { |
50 |
| - tryUpdate(function) { old, new -> return transform(old, new) } |
| 70 | + contract { |
| 71 | + callsInPlace(function, InvocationKind.AT_LEAST_ONCE) |
| 72 | + callsInPlace(transform, InvocationKind.AT_MOST_ONCE) |
| 73 | + } |
| 74 | + loop { cur -> |
| 75 | + val upd = function(value) |
| 76 | + if(compareAndSet(cur, upd)) return transform(cur, upd) |
51 | 77 | }
|
52 | 78 | }
|
53 | 79 |
|
54 | 80 | @PublishedApi
|
55 | 81 | internal inline fun AtomicBoolean.tryUpdate(function: (Boolean) -> Boolean, onUpdated: (old: Boolean, new: Boolean) -> Unit): Boolean {
|
| 82 | + contract { |
| 83 | + callsInPlace(function, InvocationKind.EXACTLY_ONCE) |
| 84 | + callsInPlace(onUpdated, InvocationKind.AT_MOST_ONCE) |
| 85 | + } |
56 | 86 | val cur = value
|
57 | 87 | val upd = function(cur)
|
58 | 88 | return compareAndSet(cur, upd).also { if (it) onUpdated(cur, upd) }
|
|
0 commit comments