Skip to content

Instantly share code, notes, and snippets.

@ChristopherDavenport
Created January 22, 2022 04:22
Show Gist options
  • Save ChristopherDavenport/f16cde9e04c8770f422818864123754d to your computer and use it in GitHub Desktop.
Save ChristopherDavenport/f16cde9e04c8770f422818864123754d to your computer and use it in GitHub Desktop.
Unsafe Ref - For when you need it
import cats.effect._
import cats.syntax.all._
import java.util.concurrent.atomic.AtomicReference
import scala.annotation.tailrec
trait UnsafeRef[A]{
def get: A
def set(a: A): Unit
def getAndSet(a: A): A
def getAndUpdate(f: A => A): A
def tryUpdate(f: A => A): Boolean
def tryModify[B](f: A => (A, B)): Option[B]
def update(f: A => A): Unit
def updateAndGet(f: A => A): A
def modify[B](f: A => (A, B)): B
}
object UnsafeRef {
// Do whatever you want, but make sure its wrapped in a sync block
def of[A](a: A): UnsafeRef[A] = new SyncRef[A](new AtomicReference[A](a))
final private class SyncRef[A](ar: AtomicReference[A]) extends UnsafeRef[A]{
def get: A = ar.get
def set(a: A): Unit = ar.set(a)
def getAndSet(a: A): A = ar.getAndSet(a)
def getAndUpdate(f: A => A): A = {
@tailrec
def spin: A = {
val a = ar.get
val u = f(a)
if (!ar.compareAndSet(a, u)) spin
else a
}
spin
}
def tryUpdate(f: A => A): Boolean =
tryModify(a => (f(a), ())).isDefined
def tryModify[B](f: A => (A, B)): Option[B] = {
val c = ar.get
val (u, b) = f(c)
if (ar.compareAndSet(c, u)) Some(b)
else None
}
def update(f: A => A): Unit = {
@tailrec
def spin(): Unit = {
val a = ar.get
val u = f(a)
if (!ar.compareAndSet(a, u)) spin()
}
spin()
}
override def updateAndGet(f: A => A): A = {
@tailrec
def spin: A = {
val a = ar.get
val u = f(a)
if (!ar.compareAndSet(a, u)) spin
else u
}
spin
}
def modify[B](f: A => (A, B)): B = {
@tailrec
def spin: B = {
val c = ar.get
val (u, b) = f(c)
if (!ar.compareAndSet(c, u)) spin
else b
}
spin
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment