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

com.rklaehn.interval.IntervalMap.scala Maven / Gradle / Ivy

The newest version!
package com.rklaehn.interval

import com.rklaehn.sonicreducer.Reducer

import language.implicitConversions
import spire.algebra._
import spire.math.Interval
import spire.math.interval._
import spire.algebra.Order.ordering
import spire.implicits._

import scala.collection.AbstractTraversable
import scala.collection.immutable.SortedSet

sealed abstract class IntervalMap[K, V] { lhs ⇒
  import IntervalMap._

  def belowAll: V

  def apply(k: K)(implicit K: Order[K]): V

  def at(k: K)(implicit K: Order[K]): V

  def below(k: K)(implicit K: Order[K]): V

  def above(k: K)(implicit K: Order[K]): V

  def unary_~(implicit b: Bool[V]): IntervalMap[K, V] = IntervalMap.negate[K, V](this)

  def ^(rhs: IntervalMap[K, V])(implicit K: Order[K], V: Value[V]): IntervalMap[K, V] = IntervalMap.xor(lhs, rhs)

  def &(rhs: IntervalMap[K, V])(implicit K: Order[K], V: Value[V]): IntervalMap[K, V] = IntervalMap.and(lhs, rhs)

  def |(rhs: IntervalMap[K, V])(implicit K: Order[K], V: Value[V]): IntervalMap[K, V] = IntervalMap.or(lhs, rhs)

  def mapValues[V2: Eq](f: V => V2): IntervalMap[K, V2]

  /**
    * Allows traversing over all keys (places where values change)
    */
  def keys: Traversable[K]

  /**
    * Allows traversing over all values. Note that the number of values is not the same as the number of keys or entries
    * There will always be at least one value (belowAll)
    */
  def values: Traversable[V]

  def entries(implicit o: Order[K], v: Eq[V]): Traversable[(Interval[K], V)]
}

private[interval] trait IntervalMap0 {

  implicit def monoid[K: Order, V: Monoid: Eq]: Monoid[IntervalMap[K, V]] = new Monoid[IntervalMap[K, V]] {
    def id = IntervalMap.constant(Monoid[V].id)
    def op(x: IntervalMap[K, V], y: IntervalMap[K, V]) = IntervalMap.combine(x, y)
  }
}

object IntervalMap extends IntervalMap0 {

  implicit def eqv[K: Order, V: Eq]: Eq[IntervalMap[K, V]] = new Eq[IntervalMap[K, V]] {
    def eqv(x: IntervalMap[K, V], y: IntervalMap[K, V]) = x == y
  }

  implicit def bool[K: Order, V: Value: Bool] = new Bool[IntervalMap[K, V]] {
    def zero = IntervalMap.constant(Value[V].zero)
    def one = IntervalMap.constant(Bool[V].one)
    def complement(a: IntervalMap[K, V]) = ~a
    def or(a: IntervalMap[K, V], b: IntervalMap[K, V]) = a | b
    def and(a: IntervalMap[K, V], b: IntervalMap[K, V]) = a & b
    override def xor(a: IntervalMap[K, V], b: IntervalMap[K, V]) = a ^ b
  }

  implicit def group[K: Order, V: Group: Eq]: Group[IntervalMap[K, V]] = new Group[IntervalMap[K, V]] {
    def id = IntervalMap.constant(Monoid[V].id)
    def op(x: IntervalMap[K, V], y: IntervalMap[K, V]) = IntervalMap.combine(x, y)
    def inverse(a: IntervalMap[K, V]) = a.mapValues(Group[V].inverse)
    override def opInverse(a: IntervalMap[K, V], b: IntervalMap[K, V]) = IntervalMap.remove(a, b)
  }

  /**
    * This does not implement Eq so it does not interfere with the default Eq instance
    * @tparam V
    */
  trait Value[V] {

    def eqv(a: V, b: V): Boolean

    def isOne(x: V): Boolean

    def isZero(x: V): Boolean

    def zero: V

    def xor(a: V, b: V): V

    def and(a: V, b: V): V

    def or(a: V, b: V): V
  }

  object Value {

    implicit object booleanIsValue extends Value[Boolean] {

      def eqv(x: Boolean, y: Boolean) = x == y

      def zero = false

      def or(a: Boolean, b: Boolean) = a | b

      def and(a: Boolean, b: Boolean) = a & b

      def xor(a: Boolean, b: Boolean) = a ^ b

      def isZero(x: Boolean) = !x

      def isOne(x: Boolean) = x
    }

    implicit def setIsValue[T]: Value[Set[T]] = new Value[Set[T]] {

      def eqv(x: Set[T], y: Set[T]) = x == y

      val zero = Set.empty[T]

      def or(a: Set[T], b: Set[T]) = a union b

      def and(a: Set[T], b: Set[T]) = a intersect b

      def xor(a: Set[T], b: Set[T]) = (a diff b) union (b diff a)

      def isZero(x: Set[T]) = x.isEmpty

      def isOne(x: Set[T]) = false
    }

    implicit def sortedSetIsValue[T: Order]: Value[SortedSet[T]] = new Value[SortedSet[T]] {

      def eqv(x: SortedSet[T], y: SortedSet[T]) = x == y

      val zero = SortedSet.empty[T]

      def or(a: SortedSet[T], b: SortedSet[T]) = a union b

      def and(a: SortedSet[T], b: SortedSet[T]) = a intersect b

      def xor(a: SortedSet[T], b: SortedSet[T]) = (a diff b) union (b diff a)

      def isZero(x: SortedSet[T]) = x.isEmpty

      def isOne(x: SortedSet[T]) = false
    }

    implicit def boolAndEqIsValue[T](implicit e: Eq[T], bool: Bool[T]): Value[T] = new Value[T] {

      def zero = Bool[T].zero

      def or(a: T, b: T) = bool.or(a, b)

      def isOne(x: T) = e.eqv(x, bool.one)

      def isZero(x: T) = e.eqv(x, bool.zero)

      def and(a: T, b: T) = a & b

      def xor(a: T, b: T) = a ^ b

      def eqv(x: T, y: T) = e.eqv(x, y)
    }

    implicit def apply[V: Value]: Value[V] = implicitly[Value[V]]
  }

  private implicit def intervalsSetIsImpl[K, V](x: IntervalMap[K, V]): Impl[K, V] =
    x.asInstanceOf[Impl[K, V]]

  private final class Impl[K, V](
      val belowAll: V,
      val edges: Array[IntervalMap.Edge[K, V]]
  ) extends IntervalMap[K, V] {
    lhs ⇒

    // $COVERAGE-OFF$
    private def isCanonical(implicit v: Eq[V]): Boolean = {
      var current = belowAll
      for(edge ← edges) {
        if(v.eqv(current, edge.at) && v.eqv(edge.at, edge.above))
          return false
        current = edge.above
      }
      true
    }
    // $COVERAGE-ON$

    private def binarySearch(key: K)(implicit K: Order[K]): Int = {
      var low = 0
      var high = edges.length - 1
      while (low <= high) {
        val mid = (low + high) >>> 1
        val midVal = edges(mid).x
        val c = K.compare(midVal, key)
        if (c < 0) {
          low = mid + 1
        }
        else if (c > 0) {
          high = mid - 1
        }
        else {
          // scalastyle:off return
          return mid
          // scalastyle:on return
        }
      }
      -(low + 1)
    }

    private def belowIndex(index: Int)(implicit K: Order[K]): V =
      if (index == 0)
        belowAll
      else
        edges(index - 1).above

    def at(value: K)(implicit K: Order[K]): V = {
      val index = binarySearch(value)
      if (index >= 0)
        edges(index).at
      else
        belowIndex(-index - 1)
    }

    def above(value: K)(implicit K: Order[K]): V = {
      val index = binarySearch(value)
      if (index >= 0)
        edges(index).above
      else
        belowIndex(-index - 1)
    }

    def below(value: K)(implicit K: Order[K]): V = {
      val index = binarySearch(value)
      if (index > 0)
        edges(index - 1).above
      else if (index == 0)
        belowAll
      else
        belowIndex(-index - 1)
    }

    def apply(value: K)(implicit K: Order[K]) = at(value)

    override def equals(rhs: Any) = rhs match {
      case rhs: Impl[K, V] =>
        lhs.belowAll == rhs.belowAll && lhs.edges === rhs.edges
      case _ ⇒
        false
    }

    override def hashCode: Int =
      (belowAll.hashCode, edges.toIndexedSeq.hashCode).hashCode

    def format(implicit K: Order[K], v: Eq[V]): String =
      entries
        .map { case (k, v) => s"$k -> $v" }
        .mkString("IntervalMap(", ",", ")")

    override def toString: String = {
      val dummyOrder: Order[K] = new Order[K] { def compare(x: K, y: K) = 0 }
      val dummyEq: Eq[V] = new Eq[V] { def eqv(x: V, y: V) = false }
      format(dummyOrder, dummyEq)
    }

    def entries(implicit ev0: Order[K], ev1: Eq[V]) = new AbstractTraversable[(Interval[K], V)] {
      override def foreach[U](f: ((Interval[K], V)) => U): Unit = foreachInterval(f)
    }

    def values = new AbstractTraversable[V] {
      override def foreach[U](f: V => U): Unit = foreachValue(f)
    }

    def keys = new AbstractTraversable[K] {
      override def foreach[U](f: K => U): Unit = foreachKey(f)
    }

    private def foreachKey[U](f: K => U): Unit = {
      for(edge <- edges) {
        f(edge.x)
      }
    }

    private def foreachValue[U](f: V => U): Unit = {
      f(belowAll)
      for(edge <- edges) {
        f(edge.at)
        f(edge.above)
      }
    }

    private def foreachInterval[U](f: ((Interval[K], V)) => U)(implicit o: Order[K], v: Eq[V]): Unit = {
      var prevBound: Bound[K] = Unbound[K]()
      var prevValue: V = belowAll
      for(c <- edges) {
        val below = prevValue
        val at = c.at
        val above = c.above
        prevBound = (!v.eqv(below, at), !v.eqv(at, above)) match {
          case (true, true) ⇒
            // change both below and above. We have to produce a point
            f((Interval.fromBounds(prevBound, Open(c.x)), below))
            f((Interval.point(c.x), at))
            Open(c.x)
          case (true, false) ⇒
            // change just below. The preceding interval must be open
            f((Interval.fromBounds(prevBound, Open(c.x)), below))
            Closed(c.x)
          case (false, true) ⇒
            // change just above. The preceding interval must be closed
            f((Interval.fromBounds(prevBound, Closed(c.x)), below))
            Open(c.x)
          case (false, false) ⇒
            // no change at all. we should not ever get here with a valid set
            prevBound
        }
        prevValue = above
      }
      f((Interval.fromBounds(prevBound, Unbound()), prevValue))
    }

    def mapValues[V2: Eq](f: V => V2) = {
      val edgeBuilder = Array.newBuilder[Edge[K, V2]]
      edgeBuilder.sizeHint(edges.length)
      val Eq = implicitly[Eq[V2]]
      val belowAll1 = f(belowAll)
      var prev1 = belowAll1
      for(Edge(x, at, above) <- edges) {
        val at1 = f(at)
        val above1 = f(above)
        if(Eq.neqv(prev1, at1) || Eq.neqv(at1, above1))
          edgeBuilder += Edge(x, at1, above1)
        prev1 = above1
      }
      new Impl(belowAll1, edgeBuilder.result())
    }
  }

  def constant[K, V](value: V): IntervalMap[K, V] =
    IntervalMap(value, Array.empty[Edge[K, V]])

  object CreateFromBool {
    implicit def fromBoolOps(x: IntervalMap.type): FromBool.type = FromBool
  }

  object CreateFromMonoid {
    implicit def fromBoolOps(x: IntervalMap.type): FromMonoid.type = FromMonoid
  }

  object FromMonoid {

    def empty[K, V](implicit vb: Monoid[V]): IntervalMap[K, V] = constant(vb.id)

    def point[K, V](x: K, value: V)(implicit vv: Monoid[V], ev: Eq[V]): IntervalMap[K, V] =
      step1(vv.id, x, value, vv.id)

    def hole[K, V](x: K, value: V)(implicit vv: Monoid[V], ev: Eq[V]): IntervalMap[K, V] =
      step1(value, x, vv.id, value)

    def atOrAbove[K, V](x: K, value: V)(implicit vv: Monoid[V], ev: Eq[V]): IntervalMap[K, V] =
      step1(vv.id, x, value, value)

    def above[K, V](x: K, value: V)(implicit vv: Monoid[V], ev: Eq[V]): IntervalMap[K, V] =
      step1(vv.id, x, vv.id, value)

    def atOrBelow[K, V](x: K, value: V)(implicit vv: Monoid[V], ev: Eq[V]): IntervalMap[K, V] =
      step1(value, x, value, vv.id)

    def below[K, V](x: K, value: V)(implicit vv: Monoid[V], ev: Eq[V]): IntervalMap[K, V] =
      step1(value, x, vv.id, vv.id)

    def apply[K: Order, V: Monoid: Eq](iv: (Interval[K], V)*): IntervalMap[K, V] = {
      val singles = iv.map { case (i, v) ⇒ apply(i, v) }
      val m = monoid[K, V]
      Reducer.reduce(singles)(m.op).getOrElse(empty)
    }

    def apply[K, V](interval: Interval[K], value: V)(implicit vv: Monoid[V], ve: Eq[V]): IntervalMap[K, V] = if (vv.isId(value)) empty
    else {
      interval.fold {
        case (Closed(a), Closed(b)) if a == b => point(a, value)
        case (Unbound(), Open(x)) => below(x, value)
        case (Unbound(), Closed(x)) => atOrBelow(x, value)
        case (Open(x), Unbound()) => above(x, value)
        case (Closed(x), Unbound()) => atOrAbove(x, value)
        case (Closed(a), Closed(b)) => step2(vv.id, a, value, value, b, value, vv.id)
        case (Closed(a), Open(b)) => step2(vv.id, a, value, value, b, vv.id, vv.id)
        case (Open(a), Closed(b)) => step2(vv.id, a, vv.id, value, b, value, vv.id)
        case (Open(a), Open(b)) => step2(vv.id, a, vv.id, value, b, vv.id, vv.id)
        case (Unbound(), Unbound()) => constant[K, V](value)
        case (EmptyBound(), EmptyBound()) => empty[K, V]
      }
    }
  }

  object FromBool {

    def zero[K, V](implicit vv: Value[V]): IntervalMap[K, V] =
      IntervalMap.constant(vv.zero)

    def one[K, V](implicit vb: Bool[V]): IntervalMap[K, V] =
      IntervalMap.constant(vb.one)

    def point[K, V](x: K, value: V)(implicit vv: Value[V]): IntervalMap[K, V] =
      if (vv.isZero(value)) zero
      else IntervalMap(vv.zero, Array(Edge(x, value, vv.zero)))

    def hole[K, V](x: K, value: V)(implicit vv: Value[V]): IntervalMap[K, V] =
      if (vv.isZero(value)) zero
      else IntervalMap(value, Array(Edge(x, vv.zero, value)))

    def atOrAbove[K, V](x: K, value: V)(implicit vv: Value[V]): IntervalMap[K, V] =
      if (vv.isZero(value)) zero
      else IntervalMap(vv.zero, Array(Edge(x, value, value)))

    def above[K, V](x: K, value: V)(implicit vv: Value[V]): IntervalMap[K, V] =
      if (vv.isZero(value)) zero
      else IntervalMap(vv.zero, Array(Edge(x, vv.zero, value)))

    def atOrBelow[K, V](x: K, value: V)(implicit vv: Value[V]): IntervalMap[K, V] =
      if (vv.isZero(value)) zero
      else IntervalMap(value, Array(Edge(x, value, vv.zero)))

    def below[K, V](x: K, value: V)(implicit vv: Value[V]): IntervalMap[K, V] =
      if (vv.isZero(value)) zero
      else IntervalMap(value, Array(Edge(x, vv.zero, vv.zero)))

    def apply[K: Order, V: Value: Eq](iv: (Interval[K], V)*): IntervalMap[K, V] = {
      val singles = iv.map { case (i, v) ⇒ apply(i, v) }
      Reducer.reduce(singles)(_ | _).getOrElse(zero)
    }

    def apply[K, V](interval: Interval[K], value: V)(implicit vv: Value[V], ve: Eq[V]): IntervalMap[K, V] = if (vv.isZero(value)) zero
    else {
      interval.fold {
        case (Closed(a), Closed(b)) if a == b => point(a, value)
        case (Unbound(), Open(x)) => below(x, value)
        case (Unbound(), Closed(x)) => atOrBelow(x, value)
        case (Open(x), Unbound()) => above(x, value)
        case (Closed(x), Unbound()) => atOrAbove(x, value)
        case (Closed(a), Closed(b)) => step2(vv.zero, a, value, value, b, value, vv.zero)
        case (Closed(a), Open(b)) => step2(vv.zero, a, value, value, b, vv.zero, vv.zero)
        case (Open(a), Closed(b)) => step2(vv.zero, a, vv.zero, value, b, value, vv.zero)
        case (Open(a), Open(b)) => step2(vv.zero, a, vv.zero, value, b, vv.zero, vv.zero)
        case (Unbound(), Unbound()) => constant[K, V](value)
        case (EmptyBound(), EmptyBound()) => zero[K, V]
      }
    }
  }

  private[interval] def step1[K, V](belowA: V, a: K, atA: V, aboveA: V)(implicit Eq: Eq[V]): IntervalMap[K, V] =
    if(Eq.eqv(belowA, atA) && Eq.eqv(atA, aboveA))
      constant[K, V](belowA)
    else
      IntervalMap[K, V](belowA, Array(Edge(a, atA, aboveA)))

  private[interval] def step2[K, V](belowA: V, a: K, atA: V, aboveA: V, b: K, atB: V, aboveB: V)(implicit Eq: Eq[V]): IntervalMap[K, V] = {
    if(Eq.eqv(belowA, atA) && Eq.eqv(atA, aboveA))
      step1(aboveA, b, atB, aboveB)
    else if(Eq.eqv(aboveA, atB) && Eq.eqv(atB, aboveB))
      step1(belowA, a, atA, aboveA)
    else
      IntervalMap(belowA, Array(Edge(a, atA, aboveA), Edge(b, atB, aboveB)))
  }

  private def negate[K, V](x: Impl[K, V])(implicit b: Bool[V]): IntervalMap[K, V] = {
    val belowAll1 = ~x.belowAll
    val edges1 = x.edges.map(e ⇒ Edge(e.x, ~e.at, ~e.above))
    IntervalMap(belowAll1, edges1)
  }

  private def apply[K, V](belowAll: V, edges: Array[Edge[K, V]]) =
    new Impl[K, V](belowAll, edges)

  private[interval] case class Edge[K, V](x: K, at: V, above: V)

  private[interval] object Edge {

    implicit def eqv[K, V]: spire.algebra.Eq[Edge[K, V]] = spire.optional.genericEq.generic[Edge[K, V]]
  }

  private abstract class MergeOperation[K, V] {

    def vEqv(a: V, b: V): Boolean

    def kOrder: Order[K]

    def lhs: Impl[K, V]

    def rhs: Impl[K, V]

    def r0: V

    protected[this] val as = lhs.edges

    protected[this] val bs = rhs.edges

    protected[this] val rs = Array.ofDim[Edge[K, V]](as.length + bs.length)

    protected[this] var ri = 0

    def collision(ai: Int, bi: Int): Unit

    def fromA(a0: Int, a1: Int, b: Int): Unit

    def fromB(a: Int, b0: Int, b1: Int): Unit

    def binarySearch(array: Array[Edge[K, V]], key: K, from: Int, until: Int): Int = {
      var low = from
      var high = until - 1
      while (low <= high) {
        val mid = (low + high) >>> 1
        val midVal = array(mid)
        val c = kOrder.compare(midVal.x, key)
        if (c < 0) {
          low = mid + 1
        } else if (c > 0) {
          high = mid - 1
        } else {
          // scalastyle:off return
          return mid
          // scalastyle:on return
        }
      }
      -(low + 1)
    }

    def merge0(a0: Int, a1: Int, b0: Int, b1: Int): Unit = {
      if (a0 == a1) {
        if (b0 != b1)
          fromB(a0, b0, b1)
      } else if (b0 == b1) {
        fromA(a0, a1, b0)
      } else {
        val am = (a0 + a1) / 2
        val res = binarySearch(bs, as(am).x, b0, b1)
        if (res >= 0) {
          // same elements
          val bm = res
          // merge everything below a(am) with everything below the found element
          merge0(a0, am, b0, bm)
          // add the elements a(am) and b(bm)
          collision(am, bm)
          // merge everything above a(am) with everything above the found element
          merge0(am + 1, a1, bm + 1, b1)
        } else {
          val bm = -res - 1
          // merge everything below a(am) with everything below the found insertion point
          merge0(a0, am, b0, bm)
          // add a(am)
          fromA(am, am + 1, bm)
          // everything above a(am) with everything above the found insertion point
          merge0(am + 1, a1, bm, b1)
        }
      }
    }

    def add(c: Edge[K, V]): Unit = {
      rs(ri) = c
      ri += 1
    }

    def result: IntervalMap[K, V] = {
      merge0(0, as.length, 0, bs.length)
      val result = IntervalMap(r0, rs.take(ri))
      //      val canonical = result.isCanonical(vValue)
      //      if(!canonical)
      //        require(result.isCanonical(vValue))
      result
    }
  }

  private abstract class BinaryOp[K, V] extends MergeOperation[K, V] {

    val r0 = op(lhs.belowAll, rhs.belowAll)
    var aCurr = lhs.belowAll
    var bCurr = rhs.belowAll
    def rCurr = if (ri == 0) r0 else rs(ri - 1).above

    def op(a: V, b: V): V

    def edge(x: K, below: V, at: V, above: V): Unit = {
      if (!vEqv(below, at) || !vEqv(at, above)) {
        add(Edge(x, at, above))
      }
    }

    def collision(ai: Int, bi: Int) = {
      val a = as(ai)
      val b = bs(bi)
      edge(a.x, rCurr, op(a.at, b.at), op(a.above, b.above))
      aCurr = a.above
      bCurr = b.above
    }

    def fromA(a0: Int, a1: Int, b: Int) = {
      var i = a0
      while (i < a1) {
        val a = as(i)
        edge(a.x, rCurr, op(a.at, bCurr), op(a.above, bCurr))
        i += 1
      }
      aCurr = as(a1 - 1).above
    }

    def fromB(a: Int, b0: Int, b1: Int) = {
      var i = b0
      while (i < b1) {
        val b = bs(i)
        edge(b.x, rCurr, op(aCurr, b.at), op(aCurr, b.above))
        i += 1
      }
      bCurr = bs(b1 - 1).above
    }

    def copyA(a0: Int, a1: Int): Unit = {
      System.arraycopy(as, a0, rs, ri, a1 - a0)
      ri += a1 - a0
      aCurr = as(a1 - 1).above
    }

    def copyB(b0: Int, b1: Int): Unit = {
      System.arraycopy(bs, b0, rs, ri, b1 - b0)
      ri += b1 - b0
      bCurr = bs(b1 - 1).above
    }

  }

  private abstract class BooleanMergeOperation[K, V] extends BinaryOp[K, V] {
    def isZero(x: V): Boolean = vValue.isZero(x)

    def isOne(x: V): Boolean = vValue.isOne(x)

    def and(a: V, b: V): V = vValue.and(a, b)

    def or(a: V, b: V): V = vValue.or(a, b)

    def xor(a: V, b: V): V = vValue.xor(a, b)

    def vEqv(a: V, b: V) = vValue.eqv(a, b)

    def vValue: Value[V]
  }

  private def and[K: Order, V: Value](lhs: IntervalMap[K, V], rhs: IntervalMap[K, V]): IntervalMap[K, V] =
    new And[K, V](lhs, rhs).result

  private def or[K: Order, V: Value](lhs: IntervalMap[K, V], rhs: IntervalMap[K, V]): IntervalMap[K, V] =
    new Or[K, V](lhs, rhs).result

  private def xor[K: Order, V: Value](lhs: IntervalMap[K, V], rhs: IntervalMap[K, V]): IntervalMap[K, V] =
    new Xor[K, V](lhs, rhs).result

  private final class And[K, V](val lhs: Impl[K, V], val rhs: Impl[K, V])(implicit val kOrder: Order[K], val vValue: Value[V]) extends BooleanMergeOperation[K, V] {
    def op(a: V, b: V) =
      and(a, b)

    override def fromA(a0: Int, a1: Int, b: Int) = {
      if (isOne(bCurr))
        super.copyA(a0, a1)
      else if (!isZero(bCurr))
        super.fromA(a0, a1, b)
      else
        aCurr = as(a1 - 1).above
    }

    override def fromB(a: Int, b0: Int, b1: Int) = {
      if (isOne(aCurr))
        super.copyB(b0, b1)
      else if (!isZero(aCurr))
        super.fromB(a, b0, b1)
      else
        bCurr = bs(b1 - 1).above
    }
  }

  private final class Or[K, V](val lhs: Impl[K, V], val rhs: Impl[K, V])(implicit val kOrder: Order[K], val vValue: Value[V]) extends BooleanMergeOperation[K, V] {
    def op(a: V, b: V) =
      or(a, b)

    override def fromA(a0: Int, a1: Int, b: Int) = {
      if (isZero(bCurr))
        super.copyA(a0, a1)
      else if (!isOne(bCurr))
        super.fromA(a0, a1, b)
      else
        aCurr = as(a1 - 1).above
    }

    override def fromB(a: Int, b0: Int, b1: Int) = {
      if (isZero(aCurr))
        super.copyB(b0, b1)
      else if (!isOne(aCurr))
        super.fromB(a, b0, b1)
      else
        bCurr = bs(b1 - 1).above
    }
  }

  private final class Xor[K, V](val lhs: Impl[K, V], val rhs: Impl[K, V])(implicit val kOrder: Order[K], val vValue: Value[V]) extends BooleanMergeOperation[K, V] {
    def op(a: V, b: V) =
      xor(a, b)

    override def fromA(a0: Int, a1: Int, b: Int) = {
      if (isZero(bCurr))
        super.copyA(a0, a1)
      else
        super.fromA(a0, a1, b)
    }

    override def fromB(a: Int, b0: Int, b1: Int) = {
      if (isZero(aCurr))
        super.copyB(b0, b1)
      else
        super.fromB(a, b0, b1)
    }
  }

  private[interval] def combine[K: Order, V: Monoid: Eq](a: IntervalMap[K, V], b: IntervalMap[K, V]): IntervalMap[K, V] =
    new MonoidCombine[K, V](a, b).result

  private final class MonoidCombine[K, V](val lhs: Impl[K, V], val rhs: Impl[K, V])(implicit val kOrder: Order[K], val vMonoid: Monoid[V], vEq: Eq[V]) extends BinaryOp[K, V] {
    def op(a: V, b: V) = vMonoid.op(a, b)

    def vEqv(a: V, b: V) = vEq.eqv(a, b)

    def isId(a: V) = vEq.eqv(a, vMonoid.id)

    override def fromA(a0: Int, a1: Int, b: Int) = {
      if (isId(bCurr))
        super.copyA(a0, a1)
      else
        super.fromA(a0, a1, b)
    }

    override def fromB(a: Int, b0: Int, b1: Int) = {
      if (isId(aCurr))
        super.copyB(b0, b1)
      else
        super.fromB(a, b0, b1)
    }
  }

  private[interval] def remove[K: Order, V: Group: Eq](a: IntervalMap[K, V], b: IntervalMap[K, V]): IntervalMap[K, V] =
    new GroupRemove[K, V](a, b).result

  private final class GroupRemove[K, V](val lhs: Impl[K, V], val rhs: Impl[K, V])(implicit val kOrder: Order[K], val vGroup: Group[V], vEq: Eq[V]) extends BinaryOp[K, V] {
    def op(a: V, b: V) = vGroup.opInverse(a, b)

    def vEqv(a: V, b: V) = vEq.eqv(a, b)

    def isId(a: V) = vEq.eqv(a, vGroup.id)

    override def fromA(a0: Int, a1: Int, b: Int) = {
      if (isId(bCurr))
        super.copyA(a0, a1)
      else
        super.fromA(a0, a1, b)
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy