Skip to content

Commit

Permalink
Add Atomic module, and StateShift (#2817)
Browse files Browse the repository at this point in the history
* Two small deprecations

* Add Atomic module, and StateShift. Implement ior through StateShift

* Fix build

* Fix atomic knit

* Fix knit attempt #2

* Update API files

* Remove references to shift
  • Loading branch information
nomisRev authored Nov 17, 2022
1 parent c5e122d commit f4054c7
Show file tree
Hide file tree
Showing 47 changed files with 465 additions and 821 deletions.
20 changes: 20 additions & 0 deletions arrow-libs/core/arrow-atomic/api/arrow-atomic.api
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
public abstract interface class arrow/atomic/Atomic {
public abstract fun compareAndSet (Ljava/lang/Object;Ljava/lang/Object;)Z
public abstract fun getAndSet (Ljava/lang/Object;)Ljava/lang/Object;
public abstract fun getValue ()Ljava/lang/Object;
public abstract fun setAndGet (Ljava/lang/Object;)Ljava/lang/Object;
public abstract fun setValue (Ljava/lang/Object;)V
}

public final class arrow/atomic/AtomicActual {
public static final fun Atomic (Ljava/lang/Object;)Larrow/atomic/Atomic;
}

public final class arrow/atomic/AtomicKt {
public static final fun getAndUpdate (Larrow/atomic/Atomic;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun loop (Larrow/atomic/Atomic;Lkotlin/jvm/functions/Function1;)Ljava/lang/Void;
public static final fun tryUpdate (Larrow/atomic/Atomic;Lkotlin/jvm/functions/Function1;)Z
public static final fun update (Larrow/atomic/Atomic;Lkotlin/jvm/functions/Function1;)V
public static final fun updateAndGet (Larrow/atomic/Atomic;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
}

47 changes: 47 additions & 0 deletions arrow-libs/core/arrow-atomic/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
plugins {
id(libs.plugins.kotlin.multiplatform.get().pluginId)
alias(libs.plugins.arrowGradleConfig.kotlin)
alias(libs.plugins.arrowGradleConfig.publish)
}

apply(plugin = "io.kotest.multiplatform")
apply(from = property("TEST_COVERAGE"))
apply(from = property("ANIMALSNIFFER_MPP"))

val enableCompatibilityMetadataVariant =
providers.gradleProperty("kotlin.mpp.enableCompatibilityMetadataVariant")
.forUseAtConfigurationTime().orNull?.toBoolean() == true

if (enableCompatibilityMetadataVariant) {
tasks.withType<Test>().configureEach {
exclude("**/*")
}
}

kotlin {
sourceSets {
commonMain {
dependencies {
api(libs.kotlin.stdlibCommon)
}
}

jvmMain {
dependencies {
implementation(libs.kotlin.stdlibJDK8)
}
}

jvmTest {
dependencies {
implementation(projects.arrowFxCoroutines)
}
}

jsMain {
dependencies {
implementation(libs.kotlin.stdlibJS)
}
}
}
}
4 changes: 4 additions & 0 deletions arrow-libs/core/arrow-atomic/gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Maven publishing configuration
pom.name=Arrow Atomic
# Build configuration
kapt.incremental.apt=false
5 changes: 5 additions & 0 deletions arrow-libs/core/arrow-atomic/knit.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
knit.package=arrow.atomic.examples
knit.dir=src/jvmTest/kotlin/examples/

test.package=arrow.atomic.examples.test
test.dir=src/jvmTest/kotlin/examples/autogenerated/
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package arrow.atomic

public expect fun <A> Atomic(initialValue: A): Atomic<A>

/**
* [Atomic] value of [A].
*
* ```kotlin
* import arrow.atomic.Atomic
* import arrow.atomic.update
* import arrow.fx.coroutines.parTraverse
* suspend fun main() {
* val count = Atomic(0)
* (0 until 20_000).parTraverse {
* count.update(Int::inc)
* }
* println(count.value)
* }
* ```
* <!--- KNIT example-atomic-01.kt -->
*
* [Atomic] also offers some other interesting operators such as [loop], [update], [tryUpdate], etc.
*/
public interface Atomic<A> {
public var value: A
public fun getAndSet(value: A): A
public fun setAndGet(value: A): A
public fun compareAndSet(expected: A, new: A): Boolean
}

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

public fun <V> Atomic<V>.tryUpdate(function: (V) -> V): Boolean {
val cur = value
val upd = function(cur)
return compareAndSet(cur, upd)
}

public inline fun <V> Atomic<V>.update(function: (V) -> V) {
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 <V> Atomic<V>.getAndUpdate(function: (V) -> V): V {
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 <V> Atomic<V>.updateAndGet(function: (V) -> V): V {
while (true) {
val cur = value
val upd = function(cur)
if (compareAndSet(cur, upd)) return upd
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package arrow.atomic

public actual fun <A> Atomic(initialValue: A): Atomic<A> =
AtomicRef(initialValue)

private class AtomicRef<V>(private var internalValue: V) : Atomic<V> {

/**
* Compare current value with expected and set to new if they're the same. Note, 'compare' is checking
* the actual object id, not 'equals'.
*/
override fun compareAndSet(expected: V, new: V): Boolean {
return if (expected === internalValue) {
internalValue = new
true
} else {
false
}
}

override fun getAndSet(value: V): V {
val oldValue = internalValue
internalValue = value
return oldValue
}

override fun setAndGet(value: V): V {
this.internalValue = value
return value
}


override var value: V
get() = internalValue
set(value) {
internalValue = value
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
@file:JvmName("AtomicActual")

package arrow.atomic

import java.util.concurrent.atomic.AtomicReference

public actual fun <A> Atomic(initialValue: A): Atomic<A> =
AtomicRef(AtomicReference(initialValue))

private class AtomicRef<A> constructor(private val atom: AtomicReference<A>) : Atomic<A> {

override var value: A
get() = atom.get()
set(value) {
atom.set(value)
}

override fun compareAndSet(expected: A, new: A): Boolean = atom.compareAndSet(expected, new)

override fun getAndSet(value: A): A = atom.getAndSet(value)

override fun setAndGet(value: A): A {
atom.set(value)
return value
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
// This file was automatically generated from Atomic.kt by Knit tool. Do not edit.
package arrow.fx.coroutines.examples.exampleAtomic01

import arrow.fx.coroutines.*
package arrow.atomic.examples.exampleAtomic01

import arrow.atomic.Atomic
import arrow.atomic.update
import arrow.fx.coroutines.parTraverse
suspend fun main() {
val count = Atomic(0)

(0 until 20_000).parTraverse {
count.update(Int::inc)
}
println(count.get())
println(count.value)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package arrow.atomic

import kotlin.native.concurrent.AtomicReference
import kotlin.native.concurrent.freeze
import kotlin.native.concurrent.isFrozen

public actual fun <A> Atomic(initialValue: A): Atomic<A> =
AtomicRef(AtomicReference(initialValue.freeze()))

private class AtomicRef<V>(private val atom: AtomicReference<V>): Atomic<V> {

override fun getAndSet(value: V): V {
if (atom.isFrozen) value.freeze()
while (true) {
val cur = atom.value
if (cur === value) return cur
if (atom.compareAndSwap(cur, value) === cur) return cur
}
}

override fun compareAndSet(expected: V, new: V): Boolean =
atom.compareAndSet(expected, new.freeze())

override var value: V
get() = atom.value
set(value) {
atom.value = value.freeze()
}

override fun setAndGet(value: V): V {
this.value = value
return value
}
}

59 changes: 48 additions & 11 deletions arrow-libs/core/arrow-core/api/arrow-core.api
Original file line number Diff line number Diff line change
Expand Up @@ -2578,13 +2578,6 @@ public final class arrow/core/computations/result {
public final fun invoke-IoAF18A (Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
}

public final class arrow/core/continuations/AtomicRefKt {
public static final fun getAndUpdate (Ljava/util/concurrent/atomic/AtomicReference;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun loop (Ljava/util/concurrent/atomic/AtomicReference;Lkotlin/jvm/functions/Function1;)Ljava/lang/Void;
public static final fun update (Ljava/util/concurrent/atomic/AtomicReference;Lkotlin/jvm/functions/Function1;)V
public static final fun updateAndGet (Ljava/util/concurrent/atomic/AtomicReference;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
}

public final class arrow/core/continuations/DefaultRaise : arrow/core/continuations/Raise {
public fun <init> ()V
public fun bind (Larrow/core/Either;)Ljava/lang/Object;
Expand All @@ -2603,6 +2596,29 @@ public final class arrow/core/continuations/DefaultRaise : arrow/core/continuati
public fun recover (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
}

public final class arrow/core/continuations/DefaultStateRaise : arrow/atomic/Atomic, arrow/core/continuations/Raise, arrow/core/continuations/StateRaise {
public fun <init> (Larrow/atomic/Atomic;Larrow/core/continuations/Raise;)V
public fun bind (Larrow/core/Either;)Ljava/lang/Object;
public fun bind (Larrow/core/Option;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
public fun bind (Larrow/core/Validated;)Ljava/lang/Object;
public fun bind (Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public fun bind (Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public fun bind (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun catch (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
public fun catch (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun compareAndSet (Ljava/lang/Object;Ljava/lang/Object;)Z
public fun getAndSet (Ljava/lang/Object;)Ljava/lang/Object;
public fun getValue ()Ljava/lang/Object;
public fun invoke (Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public fun invoke (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun raise (Ljava/lang/Object;)Ljava/lang/Object;
public fun recover (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
public fun recover (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun recover (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun setAndGet (Ljava/lang/Object;)Ljava/lang/Object;
public fun setValue (Ljava/lang/Object;)V
}

public final class arrow/core/continuations/Effect {
public static final fun _fold (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun _foldOrThrow (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
Expand Down Expand Up @@ -2648,7 +2664,7 @@ public final class arrow/core/continuations/EffectKt {
}

public final class arrow/core/continuations/IorRaise : arrow/core/continuations/Raise, arrow/typeclasses/Semigroup {
public fun <init> (Larrow/typeclasses/Semigroup;Larrow/core/continuations/Raise;)V
public fun <init> (Larrow/typeclasses/Semigroup;Larrow/core/continuations/StateRaise;)V
public fun bind (Larrow/core/Either;)Ljava/lang/Object;
public final fun bind (Larrow/core/Ior;)Ljava/lang/Object;
public fun bind (Larrow/core/Option;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
Expand All @@ -2659,8 +2675,7 @@ public final class arrow/core/continuations/IorRaise : arrow/core/continuations/
public fun catch (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
public fun catch (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun combine (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
public final fun getLeftState ()Ljava/util/concurrent/atomic/AtomicReference;
public final fun invoke (Lkotlin/jvm/functions/Function1;)Larrow/core/Ior;
public final fun getEffect ()Larrow/core/continuations/StateRaise;
public fun invoke (Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public fun invoke (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun maybeCombine (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
Expand All @@ -2669,7 +2684,6 @@ public final class arrow/core/continuations/IorRaise : arrow/core/continuations/
public fun recover (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
public fun recover (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun recover (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public final fun setLeftState (Ljava/util/concurrent/atomic/AtomicReference;)V
}

public final class arrow/core/continuations/NullableRaise : arrow/core/continuations/Raise {
Expand Down Expand Up @@ -2847,6 +2861,29 @@ public final class arrow/core/continuations/ResultRaise : arrow/core/continuatio
public final synthetic fun unbox-impl ()Larrow/core/continuations/Raise;
}

public abstract interface class arrow/core/continuations/StateRaise : arrow/atomic/Atomic, arrow/core/continuations/Raise {
}

public final class arrow/core/continuations/StateRaise$DefaultImpls {
public static fun bind (Larrow/core/continuations/StateRaise;Larrow/core/Either;)Ljava/lang/Object;
public static fun bind (Larrow/core/continuations/StateRaise;Larrow/core/Option;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
public static fun bind (Larrow/core/continuations/StateRaise;Larrow/core/Validated;)Ljava/lang/Object;
public static fun bind (Larrow/core/continuations/StateRaise;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static fun bind (Larrow/core/continuations/StateRaise;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static fun bind (Larrow/core/continuations/StateRaise;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static fun catch (Larrow/core/continuations/StateRaise;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
public static fun catch (Larrow/core/continuations/StateRaise;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static fun invoke (Larrow/core/continuations/StateRaise;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static fun invoke (Larrow/core/continuations/StateRaise;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static fun recover (Larrow/core/continuations/StateRaise;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
public static fun recover (Larrow/core/continuations/StateRaise;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static fun recover (Larrow/core/continuations/StateRaise;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
}

public final class arrow/core/continuations/StateRaiseKt {
public static final fun fold (Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
}

public abstract interface class arrow/typeclasses/Monoid : arrow/typeclasses/Semigroup {
public static final field Companion Larrow/typeclasses/Monoid$Companion;
public static fun Boolean ()Larrow/typeclasses/Monoid;
Expand Down
1 change: 1 addition & 0 deletions arrow-libs/core/arrow-core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ kotlin {
commonMain {
dependencies {
api(projects.arrowContinuations)
api(projects.arrowAtomic)
api(projects.arrowAnnotations)
api(libs.kotlin.stdlibCommon)
}
Expand Down
Loading

0 comments on commit f4054c7

Please sign in to comment.