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

scala.reactive.container.ReactContainer.scala Maven / Gradle / Ivy

The newest version!
package scala.reactive
package container






trait ReactContainer[@spec(Int, Long, Double) T] extends ReactMutable.Subscriptions {
  self =>

  def inserts: Reactive[T]
  
  def removes: Reactive[T]

  def react: ReactContainer.Lifted[T]

  def foreach(f: T => Unit): Unit

  def size: Int

  def count(p: T => Boolean): Int = {
    var num = 0
    for (v <- this) if (p(v)) num += 1
    num
  }

  def forall(p: T => Boolean): Boolean = count(p) == size

  def exists(p: T => Boolean): Boolean = count(p) > 0

  def fold(m: Monoid[T]): T = {
    var agg = m.zero
    for (v <- this) agg = m.operator(agg, v)
    agg
  }

  def map[@spec(Int, Long, Double) S](f: T => S): ReactContainer[S] =
    new ReactContainer.Map(this, f)

  def filter(p: T => Boolean): ReactContainer[T] =
    new ReactContainer.Filter(this, p)

  def collect[S <: AnyRef](pf: PartialFunction[T, S])(implicit e: T <:< AnyRef): ReactContainer[S] =
    new ReactContainer.Collect(this, pf)

  def union(that: ReactContainer[T])(implicit count: ReactContainer.Union.Count[T], a: Arrayable[T], b: CanBeBuffered): ReactContainer[T] =
    new ReactContainer.Union(this, that, count)

  def to[That <: ReactContainer[T]](implicit factory: ReactBuilder.Factory[T, That]): That = {
    val builder = factory()
    for (x <- this) builder += x
    builder.container
  }

}


object ReactContainer {

  trait Lifted[@spec(Int, Long, Double) T] {
    val container: ReactContainer[T]

    /* queries */

    def size: Signal[Int] with Reactive.Subscription =
      new Size(container)

    def count(p: T => Boolean): Signal[Int] with Reactive.Subscription =
      new Signal.Default[Int] with Reactive.ProxySubscription {
        private[reactive] var value = container.count(p)
        def apply() = value
        val subscription = Reactive.CompositeSubscription(
          container.inserts onEvent { x => if (p(x)) { value += 1; reactAll(value) } },
          container.removes onEvent { x => if (p(x)) { value -= 1; reactAll(value) } }
        )
      }

    def exists(p: T => Boolean): Signal[Boolean] with Reactive.Subscription = count(p).map(_ > 0)

    def forall(p: T => Boolean): Signal[Boolean] with Reactive.Subscription =
      new Signal.Default[Boolean] with Reactive.ProxySubscription {
        private[reactive] var value = container.count(p)
        def apply() = value == container.size
        val subscription = Reactive.CompositeSubscription(
          container.inserts onEvent { x => if (p(x)) value += 1; reactAll(value == container.size) },
          container.removes onEvent { x => if (p(x)) value -= 1; reactAll(value == container.size) }
        )
      }

    def foreach(f: T => Unit): Reactive[Unit] with Reactive.Subscription = {
      container.foreach(f)
      container.inserts.foreach(f)
    }
    
    def monoidFold(implicit m: Monoid[T]): Signal[T] with Reactive.Subscription = new Aggregate(container, MonoidCatamorph[T])

    def commuteFold(implicit c: Commutoid[T]): Signal[T] with Reactive.Subscription = new Aggregate(container, CommuteCatamorph[T])

    def abelianFold(implicit ab: Abelian[T], a: Arrayable[T]): Signal[T] with Reactive.Subscription = new Aggregate(container, AbelianCatamorph[T])

    def mutate(m: ReactMutable)(insert: T => Unit)(remove: T => Unit): Reactive.Subscription = new Mutate(container, insert, remove)

    /* transformers */
  
    def to[That <: ReactContainer[T]](implicit factory: ReactBuilder.Factory[T, That]): That = {
      val builder = factory()
      val result = builder.container
  
      result.subscriptions += container.inserts.mutate(builder) {
        builder += _
      }
      result.subscriptions += container.removes.mutate(builder) {
        builder -= _
      }
  
      result
    }

  }

  object Lifted {
    class Default[@spec(Int, Long, Double) T](val container: ReactContainer[T])
    extends Lifted[T]

    class Eager[@spec(Int, Long, Double) T](val container: ReactContainer[T])
    extends Lifted[T] {
      override val size: Signal[Int] with Reactive.Subscription =
        new Signal.Default[Int] with Reactive.ProxySubscription {
          private[reactive] var value = 0
          def apply() = value
          val subscription = Reactive.CompositeSubscription(
            container.inserts on { value += 1; reactAll(value) },
            container.removes on { value -= 1; reactAll(value) }
          )
        }
    }
  }

  trait Default[@spec(Int, Long, Double) T] extends ReactContainer[T] {
    val react = new Lifted.Default[T](this)
  }

  trait Eager[@spec(Int, Long, Double) T] extends ReactContainer[T] {
    val react = new Lifted.Eager[T](this)
  }

  class Size[@spec(Int, Long, Double) T](self: ReactContainer[T])
  extends Signal.Default[Int] with Reactive.ProxySubscription {
    private[reactive] var value = self.size
    def apply() = value
    val subscription = Reactive.CompositeSubscription(
      self.inserts on { value += 1; reactAll(value) },
      self.removes on { value -= 1; reactAll(value) }
    )
  }

  class Mutate[@spec(Int, Long, Double) T](self: ReactContainer[T], insert: T => Unit, remove: T => Unit)
  extends Reactive.ProxySubscription {
    val subscription = Reactive.CompositeSubscription(
      self.inserts.mutate(self)(insert),
      self.removes.mutate(self)(remove)
    )
  }

  class Map[@spec(Int, Long, Double) T, @spec(Int, Long, Double) S](self: ReactContainer[T], f: T => S)
  extends ReactContainer.Default[S] {
    val inserts = self.inserts.map(f)
    val removes = self.removes.map(f)
    def size = self.size
    def foreach(g: S => Unit) = self.foreach(x => g(f(x)))
  }

  class Filter[@spec(Int, Long, Double) T](self: ReactContainer[T], p: T => Boolean)
  extends ReactContainer.Default[T] {
    val inserts = self.inserts.filter(p)
    val removes = self.removes.filter(p)
    def size = self.count(p)
    def foreach(f: T => Unit) = self.foreach(x => if (p(x)) f(x))
  }

  class Collect[T, S <: AnyRef](self: ReactContainer[T], pf: PartialFunction[T, S])(implicit e: T <:< AnyRef)
  extends ReactContainer.Default[S] {
    val inserts = self.inserts.collect(pf)
    val removes = self.removes.collect(pf)
    def size = self.count(pf.isDefinedAt)
    def foreach(f: S => Unit) = self.foreach(x => if (pf.isDefinedAt(x)) f(pf(x)))
  }

  class Union[@spec(Int, Long, Double) T]
    (self: ReactContainer[T], that: ReactContainer[T], count: Union.Count[T])(implicit at: Arrayable[T])
  extends ReactContainer.Default[T] {
    val inserts = new Reactive.BindEmitter[T]
    val removes = new Reactive.BindEmitter[T]
    var countSignal: Signal.Mutable[Union.Count[T]] = new Signal.Mutable(count)
    var insertSubscription = (self.inserts union that.inserts).mutate(countSignal, inserts) { x =>
      if (count.inc(x)) inserts += x
    }
    var removeSubscription = (self.removes union that.removes).mutate(countSignal, removes) { x =>
      if (count.dec(x)) removes += x
    }
    def computeUnion = {
      val s = ReactHashSet[T]
      for (v <- self) s += v
      for (v <- that) s += v
      s
    }
    def size = computeUnion.size
    def foreach(f: T => Unit) = computeUnion.foreach(f)
  }

  object Union {
    trait Count[@spec(Int, Long, Double) T] {
      def inc(x: T): Boolean
      def dec(x: T): Boolean
    }

    class PrimitiveCount[@spec(Int, Long, Double) T](implicit val at: Arrayable[T]) extends Count[T] {
      val table = ReactHashValMap[T, Int](at, Arrayable.nonZeroInt)
      def inc(x: T) = {
        val curr = table.applyOrNil(x)
        table(x) = curr + 1
        if (curr == 0) true
        else false
      }
      def dec(x: T) = {
        val curr = table.applyOrNil(x)
        if (curr <= 1) {
          table.remove(x)
          true
        } else {
          table(x) = curr - 1
          false
        }
      }
    }

    sealed trait Numeral {
      def inc: Numeral
      def dec: Numeral
    }
    object Zero extends Numeral {
      def inc = One
      def dec = Zero
    }
    object One extends Numeral {
      def inc = Two
      def dec = Zero
    }
    object Two extends Numeral {
      def inc = Two
      def dec = One
    }

    class RefCount[T](implicit val at: Arrayable[T]) extends Count[T] {
      val table = ReactHashValMap[T, Numeral]
      def inc(x: T) = {
        val curr = table.applyOrElse(x, Zero)
        table(x) = curr.inc
        if (curr == Zero) true
        else false
      }
      def dec(x: T) = {
        val curr = table.applyOrElse(x, Zero)
        val next = curr.dec
        if (next == Zero) {
          table.remove(x)
          true
        } else {
          table(x) = next
          false
        }
      }
    }

    implicit def intCount = new PrimitiveCount[Int]

    implicit def longCount = new PrimitiveCount[Long]

    implicit def doubleCount = new PrimitiveCount[Double]

    implicit def refCount[T >: Null <: AnyRef](implicit at: Arrayable[T]) = new RefCount[T]

  }

  class Aggregate[@spec(Int, Long, Double) T]
    (val container: ReactContainer[T], val catamorph: ReactCatamorph[T, T])
  extends Signal.Proxy[T] with Reactive.ProxySubscription {
    commuted =>
    val id = (v: T) => v
    var subscription: Reactive.Subscription = _
    var proxy: Signal[T] = _

    def init(c: ReactContainer[T]) {
      proxy = catamorph.signal
      for (v <- container) catamorph += v
      subscription = Reactive.CompositeSubscription(
        container.inserts onEvent { v => catamorph += v },
        container.removes onEvent { v => catamorph -= v }
      )
    }

    init(container)
  }

  /* default containers */

  class Emitter[@spec(Int, Long, Double) T]
    (private val foreachF: (T => Unit) => Unit, private val sizeF: () => Int)
  extends ReactContainer[T] {
    private[reactive] var insertsEmitter: Reactive.Emitter[T] = null
    private[reactive] var removesEmitter: Reactive.Emitter[T] = null

    private def init(dummy: ReactContainer.Emitter[T]) {
      insertsEmitter = new Reactive.Emitter[T]
      removesEmitter = new Reactive.Emitter[T]
    }

    init(this)

    def inserts = insertsEmitter

    def removes = removesEmitter

    def foreach(f: T => Unit) = foreachF(f)

    def size = sizeF()

    def react = new ReactContainer.Lifted.Default(this)

  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy