Skip to content

Commit

Permalink
AtomicBoolean support
Browse files Browse the repository at this point in the history
Fixes #6
  • Loading branch information
SokolovaMaria committed Jul 18, 2018
1 parent 9547b95 commit 4778c58
Show file tree
Hide file tree
Showing 6 changed files with 286 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,17 @@ public expect fun atomic(initial: Int): AtomicInt
*/
public expect fun atomic(initial: Long): AtomicLong

/**
* Creates atomic [Boolean] with a given [initial] value.
*
* It can only be used in initialize of private read-only property, like this:
*
* ```
* private val f = atomic(initialBoolean)
* ```
*/
public expect fun atomic(initial: Boolean): AtomicBoolean

// ==================================== AtomicRef ====================================

/**
Expand Down Expand Up @@ -120,6 +131,79 @@ public inline fun <T> AtomicRef<T>.updateAndGet(function: (T) -> T): T {
}
}


// ==================================== AtomicBoolean ====================================

/**
* Atomic reference to a [Boolean] variable with volatile reads/writes via
* [value] property and various atomic read-modify-write operations
* like [compareAndSet] and others.
*/
public expect class AtomicBoolean {
/**
* Reading/writing this property maps to read/write of volatile variable.
*/
public var value: Boolean

/**
* Maps to [AtomicIntegerFieldUpdater.lazySet].
*/
public fun lazySet(value: Boolean)

/**
* Maps to [AtomicIntegerFieldUpdater.compareAndSet].
*/
public fun compareAndSet(expect: Boolean, update: Boolean): Boolean

/**
* Maps to [AtomicIntegerFieldUpdater.getAndSet].
*/
public fun getAndSet(value: Boolean): Boolean

}

/**
* Infinite loop that reads this atomic variable and performs the specified [action] on its value.
*/
public inline fun AtomicBoolean.loop(action: (Boolean) -> Unit): Nothing {
while (true) {
action(value)
}
}

/**
* Updates variable atomically using the specified [function] of its value.
*/
public inline fun AtomicBoolean.update(function: (Boolean) -> Boolean) {
while (true) {
val cur = value
val upd = function(cur)
if (compareAndSet(cur, upd)) return
}
}

/**
* Updates variable atomically using the specified [function] of its value and returns its old value.
*/
public inline fun AtomicBoolean.getAndUpdate(function: (Boolean) -> Boolean): Boolean {
while (true) {
val cur = value
val upd = function(cur)
if (compareAndSet(cur, upd)) return cur
}
}

/**
* Updates variable atomically using the specified [function] of its value and returns its new value.
*/
public inline fun AtomicBoolean.updateAndGet(function: (Boolean) -> Boolean): Boolean {
while (true) {
val cur = value
val upd = function(cur)
if (compareAndSet(cur, upd)) return upd
}
}

// ==================================== AtomicInt ====================================

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,17 @@ class ArithmeticTest {
check(a.decrementAndGet() == 7L)
check(a.x == 7L)
}

@Test
fun testBoolean() {
val a = BooleanArithmetic()
check(!a.x)
a.lazySet(true)
check(a.x)
check(a.getAndSet(false))
a.compareAndSet(false, true)
check(a.x)
}
}

class IntArithmetic {
Expand Down Expand Up @@ -91,4 +102,13 @@ class LongArithmetic {
fun addAndGet(v: Long) = _x.addAndGet(v)
fun incrementAndGet() = _x.incrementAndGet()
fun decrementAndGet() = _x.decrementAndGet()
}

class BooleanArithmetic {
private val _x = atomic(false)
val x get() = _x.value

fun lazySet(v: Boolean) = _x.lazySet(v)
fun getAndSet(v: Boolean) = _x.getAndSet(v)
fun compareAndSet(e: Boolean, u: Boolean) = _x.compareAndSet(e, u)
}
23 changes: 23 additions & 0 deletions atomicfu-js/src/main/kotlin/kotlinx/atomicfu/AtomicFU.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ package kotlinx.atomicfu
public actual fun <T> atomic(initial: T): AtomicRef<T> = AtomicRef<T>(initial)
public actual fun atomic(initial: Int): AtomicInt = AtomicInt(initial)
public actual fun atomic(initial: Long): AtomicLong = AtomicLong(initial)
public actual fun atomic(initial: Boolean): AtomicBoolean = AtomicBoolean(initial)

// ==================================== AtomicRef ====================================

Expand All @@ -44,6 +45,28 @@ public actual class AtomicRef<T> internal constructor(value: T) {
override fun toString(): String = value.toString()
}

// ==================================== AtomicBoolean ====================================

public actual class AtomicBoolean internal constructor(value: Boolean) {
public actual var value: Boolean = value

public actual inline fun lazySet(value: Boolean) {
this.value = value
}

public actual inline fun compareAndSet(expect: Boolean, update: Boolean): Boolean {
if (value != expect) return false
value = update
return true
}

public actual fun getAndSet(value: Boolean): Boolean {
val oldValue = this.value
this.value = value
return oldValue
}
}

// ==================================== AtomicInt ====================================

public actual class AtomicInt internal constructor(value: Int) {
Expand Down
Loading

0 comments on commit 4778c58

Please sign in to comment.