<commit_before>package rescala.graph

import rescala.synchronization.{TurnLock, Pessimistic}
import rescala.turns.Turn

trait Commitable {
  def commit(implicit turn: Turn): Unit
  def release(implicit turn: Turn): Unit
}

object Buffer {
  def apply[A](default: A, commitStrategy: (A, A) => A, writeLock: TurnLock): Buffer[A] = new SimpleBuffer[A](default, commitStrategy, writeLock)
}

trait Buffer[A] extends Commitable {
  /** these methods are only used for initialisation and are unsafe to call when the reactive is in use */
  def initCurrent(value: A): Unit
  def initStrategy(strategy: (A, A) => A): Unit

  def transform(f: (A) => A)(implicit turn: Turn): A
  def set(value: A)(implicit turn: Turn): Unit
  def base(implicit turn: Turn): A
  def get(implicit turn: Turn): A
  def release(implicit turn: Turn): Unit
  def commit(implicit turn: Turn): Unit
}

final class SimpleBuffer[A](initialValue: A, initialStrategy: (A, A) => A, writeLock: TurnLock) extends Buffer[A] {

  @volatile var current: A = initialValue
  @volatile private var update: Option[A] = None
  @volatile private var owner: Turn = null
  @volatile var commitStrategy: (A, A) => A = initialStrategy

  override def initCurrent(value: A): Unit = current = value
  override def initStrategy(strategy: (A, A) => A): Unit =  commitStrategy = strategy


  def transform(f: (A) => A)(implicit turn: Turn): A = {
    val value = f(get)
    set(value)
    value
  }
  def set(value: A)(implicit turn: Turn): Unit = {
    assert(owner == null || owner == turn, s"buffer owned by $owner written by $turn")
    turn match {
      case pessimistic: Pessimistic => assert(writeLock == null || writeLock.hasWriteAccess(pessimistic.key), s"buffer owned by $owner, controlled by $writeLock with owner ${writeLock.getOwner} was written by $turn who locks with ${pessimistic.key}")
      case _ =>
    }
    update = Some(value)
    owner = turn
    turn.plan(this)
  }
  def base(implicit turn: Turn): A = current
  def get(implicit turn: Turn): A = if(turn eq owner) update.getOrElse(current) else current
  def release(implicit turn: Turn): Unit = {
    update = None
    owner = null
  }
  def commit(implicit turn: Turn): Unit = {
    current = commitStrategy(current, get)
    release
  }
}



final class STMBuffer[A](initialValue: A, initialStrategy: (A, A) => A, writeLock: TurnLock) extends Buffer[A] {

  @volatile private var current: A = initialValue
  @volatile private var update: Option[A] = None
  @volatile private var owner: Turn = null
  private var commitStrategy: (A, A) => A = initialStrategy

  /** these methods are only used for initialisation and are unsafe to call when the reactive is in use */
  override def initCurrent(value: A): Unit = current = value
  override def initStrategy(strategy: (A, A) => A): Unit = commitStrategy = strategy


  def transform(f: (A) => A)(implicit turn: Turn): A = {
    val value = f(get)
    set(value)
    value
  }
  def set(value: A)(implicit turn: Turn): Unit = {
    assert(owner == null || owner == turn, s"buffer owned by $owner written by $turn")
    turn match {
      case pessimistic: Pessimistic => assert(writeLock == null || writeLock.hasWriteAccess(pessimistic.key), s"buffer owned by $owner, controlled by $writeLock with owner ${writeLock.getOwner} was written by $turn who locks with ${pessimistic.key}")
      case _ =>
    }
    update = Some(value)
    owner = turn
    turn.plan(this)
  }
  def base(implicit turn: Turn) = current
  def get(implicit turn: Turn): A = if(turn eq owner) update.getOrElse(current) else current
  def release(implicit turn: Turn): Unit = {
    update = None
    owner = null
  }
  def commit(implicit turn: Turn): Unit = {
    current = commitStrategy(current, get)
    release
  }
}<commit_msg>add first draft of STMBuffer<commit_after>package rescala.graph

import rescala.synchronization.{TurnLock, Pessimistic}
import rescala.turns.Turn

import scala.concurrent.stm.{InTxn, Ref}
import scala.language.implicitConversions

trait Commitable {
  def commit(implicit turn: Turn): Unit
  def release(implicit turn: Turn): Unit
}

object Buffer {
  def apply[A](default: A, commitStrategy: (A, A) => A, writeLock: TurnLock): Buffer[A] = new SimpleBuffer[A](default, commitStrategy, writeLock)
}

trait Buffer[A] extends Commitable {
  /** these methods are only used for initialisation and are unsafe to call when the reactive is in use */
  def initCurrent(value: A): Unit
  def initStrategy(strategy: (A, A) => A): Unit

  def transform(f: (A) => A)(implicit turn: Turn): A
  def set(value: A)(implicit turn: Turn): Unit
  def base(implicit turn: Turn): A
  def get(implicit turn: Turn): A
  def release(implicit turn: Turn): Unit
  def commit(implicit turn: Turn): Unit
}

final class SimpleBuffer[A](initialValue: A, initialStrategy: (A, A) => A, writeLock: TurnLock) extends Buffer[A] {

  @volatile var current: A = initialValue
  @volatile private var update: Option[A] = None
  @volatile private var owner: Turn = null
  @volatile var commitStrategy: (A, A) => A = initialStrategy

  override def initCurrent(value: A): Unit = current = value
  override def initStrategy(strategy: (A, A) => A): Unit =  commitStrategy = strategy


  def transform(f: (A) => A)(implicit turn: Turn): A = {
    val value = f(get)
    set(value)
    value
  }
  def set(value: A)(implicit turn: Turn): Unit = {
    assert(owner == null || owner == turn, s"buffer owned by $owner written by $turn")
    turn match {
      case pessimistic: Pessimistic => assert(writeLock == null || writeLock.hasWriteAccess(pessimistic.key), s"buffer owned by $owner, controlled by $writeLock with owner ${writeLock.getOwner} was written by $turn who locks with ${pessimistic.key}")
      case _ =>
    }
    update = Some(value)
    owner = turn
    turn.plan(this)
  }
  def base(implicit turn: Turn): A = current
  def get(implicit turn: Turn): A = if(turn eq owner) update.getOrElse(current) else current
  def release(implicit turn: Turn): Unit = {
    update = None
    owner = null
  }
  def commit(implicit turn: Turn): Unit = {
    current = commitStrategy(current, get)
    release
  }
}



final class STMBuffer[A](initialValue: A, initialStrategy: (A, A) => A) extends Buffer[A] {

  private val current: Ref[A] = Ref(initialValue)
  private val update: Ref[Option[A]] = Ref(None)
  private var commitStrategy: (A, A) => A = initialStrategy

  /** these methods are only used for initialisation and are unsafe to call when the reactive is in use */
  override def initCurrent(value: A): Unit = current.single.set(value)
  override def initStrategy(strategy: (A, A) => A): Unit = commitStrategy = strategy

  implicit def inTxn(implicit turn: Turn): InTxn = turn match {
    case pessimistic: Pessimistic => pessimistic.asInstanceOf[InTxn]
    case _ => throw new IllegalStateException(s"$turn has invalid type for $this")
  }

  def transform(f: (A) => A)(implicit turn: Turn): A = {
    val value = f(get)
    set(value)
    value
  }
  def set(value: A)(implicit turn: Turn): Unit = {
    update.set(Some(value))
    turn.plan(this)
  }
  def base(implicit turn: Turn) = current.get
  def get(implicit turn: Turn): A = update.get.getOrElse(current.get)
  def release(implicit turn: Turn): Unit = {
    update.set(None)
  }
  def commit(implicit turn: Turn): Unit = {
    current.set(commitStrategy(current.get, get))
    release
  }
}
{'fraction_non_alphanumeric': 0.11979448350459708, 'fraction_numerical': 0.0, 'mean_word_length': 3.954454119223041, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 33, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2349942', 'n_tokens_mistral': 2350, 'n_tokens_neox': 2299, 'n_words': 797}