All Downloads are FREE. Search and download functionalities are using the official Maven repository.

libretto.util.atomic.package.scala Maven / Gradle / Ivy

The newest version!
package libretto.util.atomic

import java.util.concurrent.atomic.AtomicReference
import scala.annotation.tailrec

extension [A <: AnyRef](ref: AtomicReference[A]) {
  def modifyOpaque[C](f: A => (A, C)): C = {
    @tailrec def go(expected: A): C = {
      val res: (A, C) = f(expected)
      val changed: A = compareAndSetOpaque[A](ref, expected, res._1)
      if (changed eq res._1)
        res._2
      else
        go(changed)
    }

    go(ref.getOpaque())
  }

  def modifyOpaqueWith[B, C](b: B, f: (A, B) => (A, C)): C = {
    @tailrec def go(expected: A): C = {
      val res: (A, C) = f(expected, b)
      val changed: A = compareAndSetOpaque[A](ref, expected, res._1)
      if (changed eq res._1) // success
        res._2
      else
        go(changed)
    }

    go(ref.getOpaque())
  }
}

/** Returns the value of `ref` afterwards.
  * If it is `next`, it means the operation was successful. Otherwise, the value has changed.
  */
@tailrec private def compareAndSetOpaque[A <: AnyRef](
  ref: AtomicReference[A],
  expected: A,
  next: A,
): A = {
  if (ref.weakCompareAndSetPlain(expected, next)) {
    next // success
  } else {
    val current = ref.getOpaque()
    if (current eq expected)
      compareAndSetOpaque(ref, expected, next)
    else
      current
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy