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

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

The newest version!
package com.rklaehn.interval

private[interval] object Tree {

  import java.lang.Long.numberOfLeadingZeros

  @inline final def toPrefix(key: Long): Long = key - Long.MinValue

  @inline final def fromPrefix(key: Long): Long = key + Long.MinValue

  @inline final def unsigned_<(i: Long, j: Long) = (i < j) ^ (i < 0L) ^ (j < 0L)

  @inline final def levelAbove(a: Long, b: Long): Byte =
    (63 - numberOfLeadingZeros(a ^ b)).toByte

  @inline final def maskAbove(prefix: Long, bit: Byte) = {
    // this is not the same as (-1L << (bit + 1)) due to the somewhat strange behavior of the java shift operator
    // -1L << 64 gives -1L, whereas (-1L << 63) << 1 gives 0L like we need
    prefix & ((-1L << bit) << 1)
  }

  @inline final def zeroAt(value: Long, bit: Byte) =
    (value & (1L << bit)) == 0L

  @inline final def hasMatchAt(key: Long, prefix: Long, level: Byte) =
    maskAbove(key, level) == prefix

  def concat(t1: Leaf, t2: Leaf): Tree = {
    if (!unsigned_<(t1.prefix, t2.prefix))
      throw new IllegalArgumentException("Arguments of concat must be ordered")
    val p1 = t1.prefix
    val p2 = t2.prefix
    val l = levelAbove(p1, p2)
    val p = maskAbove(p1, l)
    Branch(p, l, t1, t2)
  }

  //  def join(p1 : Long, t1 : IntervalTrie, p2 : Long, t2 : IntervalTrie) : IntervalTrie = {
  //    val l = levelAbove(p1, p2)
  //    val p = maskAbove(p1, l)
  //    if (zeroAt(p1, l))
  //      Branch(p, l, t1, t2)
  //    else
  //      Branch(p, l, t2, t1)
  //  }

  /**
   * Creates a branch from two possibly null children. In case one of the children is null, the other child will
   * be returned. So if both children are null, this operation can return null.
   * @param p the prefix to be used for a new branch
   * @param level the level to be used for a new branch
   * @param l the left child
   * @param r the right child
   * @return the result, can be null
   */
  @inline private final def branch(p: Long, level: Byte, l: Tree, r: Tree): Tree =
    if (l eq null)
      r
    else if (r eq null)
      l
    else
      Branch(p, level, l, r)

  // $COVERAGE-OFF$
  private[interval] def unreachable: Nothing = throw new NotImplementedError("You should never get here")
  // $COVERAGE-ON$

  sealed abstract class BooleanBinaryOperator {

    @inline private final def disjoint(a0: Boolean, a: Tree, b0: Boolean, b: Tree): Boolean = {
      val a_p = a.prefix
      val b_p = b.prefix
      val level = levelAbove(a_p, b_p)
      if (zeroAt(a_p, level)) {
        // a is before b, so it is overlapped by b0
        // b is behind a, so it is overlapped by a0 ^ a.sign
        overlapA(a0, a, b0) && overlapB(a0 ^ a.sign, b0, b)
      } else {
        // b is before a, so it is overlapped by a0
        // a is behind b, so it is overlapped by b0 ^ b.sign
        overlapB(a0, b0, b) && overlapA(a0, a, b0 ^ b.sign)
      }
    }

    protected def op(a: Boolean, b: Boolean): Boolean

    /**
     * This is called if two leaves collide (have the same prefix)
     * @param a0 the value before a
     * @param a a leaf from the lhs
     * @param b0 the value before b
     * @param b a leaf from the rhs
     * @return the result. Can be a leaf or null
     */
    protected def collision(a0: Boolean, a: Leaf, b0: Boolean, b: Leaf): Boolean

    /**
     * This will be called when a is completely covered by a contiguous interval of b
     * @param a0
     * @param a a non-null tree (leaf or branch)
     * @param b0 the constant value of b in the complete interval of a
     * @return the result, can be null
     */
    protected def overlapA(a0: Boolean, a: Tree, b0: Boolean): Boolean

    /**
     * This will be called when b is completely covered by a contiguous interval of a
     * @param a0 the constant value of a in the complete interval of b
     * @param b0
     * @param b a non-null tree (leaf or branch)
     * @return the result, can be null
     */
    protected def overlapB(a0: Boolean, b0: Boolean, b: Tree): Boolean

    /**
     * Performs the binary operation for two arbitrary trees
     * @param a0 the value before a
     * @param a a node (leaf or branch) from the lhs
     * @param b0 the value before b
     * @param b a node (leaf or branch) from the rhs
     * @return the result, can be null
     */
    private final def op(a0: Boolean, a: Tree, b0: Boolean, b: Tree): Boolean = {
      val a_l = a.level
      val a_p = a.prefix
      val b_l = b.level
      val b_p = b.prefix

      if (a_l > b_l) {
        // a is larger => a must be a branch
        if (!hasMatchAt(b_p, a_p, a_l)) {
          // the prefix of a and b is different. We don't care if a is a branch or a leaf
          disjoint(a0, a, b0, b)
        } else a match {
          case a: Branch =>
            val am = a0 ^ a.left.sign
            if (zeroAt(b_p, a_l)) {
              // b fits into the left child of a
              op(a0, a.left, b0, b) && overlapA(am, a.right, b0 ^ b.sign)
            } else {
              // b fits into the right child of a
              overlapA(a0, a.left, b0) && op(am, a.right, b0, b)
            }
          // $COVERAGE-OFF$
          case _ => unreachable
          // $COVERAGE-ON$
        }
      } else if (b_l > a_l) {
        // b is larger => b must be a branch
        if (!hasMatchAt(a_p, b_p, b_l)) {
          // the prefix of a and b is different. We don't care if b is a branch or a leaf
          disjoint(a0, a, b0, b)
        } else b match {
          case b: Branch =>
            val bm = b0 ^ b.left.sign
            if (zeroAt(a_p, b_l)) {
              // a fits into the left child of b
              op(a0, a, b0, b.left) && overlapB(a0 ^ a.sign, bm, b.right)
            } else {
              // a fits into the right child of b
              overlapB(a0, b0, b.left) && op(a0, a, bm, b.right)
            }
          // $COVERAGE-OFF$
          case _ => unreachable
          // $COVERAGE-ON$
        }
      } else {
        // a_l == b_l, trees are the same size
        if (a_p == b_p) {
          (a, b) match {
            case (a: Branch, b: Branch) =>
              val am = a0 ^ a.left.sign
              val bm = b0 ^ b.left.sign
              // same prefix. leaves have to be merged
              // todo: check if we can return b unchanged
              op(a0, a.left, b0, b.left) && op(am, a.right, bm, b.right)
            case (a: Leaf, b: Leaf) =>
              collision(a0, a, b0, b)
            // $COVERAGE-OFF$
            case _ => unreachable
            // $COVERAGE-ON$
          }
        } else {
          // same mask, different prefix
          disjoint(a0, a, b0, b)
        }
      }
    }

    final def apply(a0: Boolean, a: Tree, b0: Boolean, b: Tree): Boolean = op(a0, b0) && {
      if ((a eq null) && (b eq null))
        true
      else if (a eq null)
        overlapB(a0, b0, b)
      else if (b eq null)
        overlapA(a0, a, b0)
      else
        op(a0, a, b0, b)
    }
  }

  /**
   * A binary calculator that preserves the order of operands. This is the most generic case. It is used even for
   * symmetric operations. There might be some performance benefit in doing an operator for symmetric operations, but
   * I doubt that it is worth it. And in any case I am too lazy right now.
   */
  sealed abstract class OrderedBinaryOperator {

    /**
     * Joins two non-overlapping leaves
     * @param a0 the value before a
     * @param a a node (leaf or branch) from the lhs
     * @param b0 the value before b
     * @param b a node (leaf or branch) from the rhs
     * @return the result, can be null
     */
    @inline private final def join(a0: Boolean, a: Tree, b0: Boolean, b: Tree): Tree = {
      val a_p = a.prefix
      val b_p = b.prefix
      val level = levelAbove(a_p, b_p)
      val p = maskAbove(a_p, level)
      if (zeroAt(a_p, level)) {
        // a is before b, so it is overlapped by b0
        val a1 = overlapA(a0, a, b0)
        // b is behind a, so it is overlapped by a0 ^ a.sign
        val b1 = overlapB(a0 ^ a.sign, b0, b)
        // make the branch (results can be empty)
        branch(p, level, a1, b1)
      } else {
        // b is before a, so it is overlapped by a0
        val b1 = overlapB(a0, b0, b)
        // a is behind b, so it is overlapped by b0 ^ b.sign
        val a1 = overlapA(a0, a, b0 ^ b.sign)
        // make the branch (results can be empty)
        branch(p, level, b1, a1)
      }
    }

    /**
     * This is called if two leaves collide (have the same prefix)
     * @param a0 the value before a
     * @param a a leaf from the lhs
     * @param b0 the value before b
     * @param b a leaf from the rhs
     * @return the result. Can be a leaf or null
     */
    protected def collision(a0: Boolean, a: Leaf, b0: Boolean, b: Leaf): Tree

    /**
     * This will be called when a is completely covered by a contiguous interval of b
     * @param a0
     * @param a a non-null tree (leaf or branch)
     * @param b0 the constant value of b in the complete interval of a
     * @return the result, can be null
     */
    protected def overlapA(a0: Boolean, a: Tree, b0: Boolean): Tree

    /**
     * This will be called when b is completely covered by a contiguous interval of a
     * @param a0 the constant value of a in the complete interval of b
     * @param b0
     * @param b a non-null tree (leaf or branch)
     * @return the result, can be null
     */
    protected def overlapB(a0: Boolean, b0: Boolean, b: Tree): Tree

    /**
     * Performs the binary operation for two arbitrary trees
     * @param a0 the value before a
     * @param a a node (leaf or branch) from the lhs
     * @param b0 the value before b
     * @param b a node (leaf or branch) from the rhs
     * @return the result, can be null
     */
    private final def op(a0: Boolean, a: Tree, b0: Boolean, b: Tree): Tree = {
      val a_l = a.level
      val a_p = a.prefix
      val b_l = b.level
      val b_p = b.prefix

      if (a_l > b_l) {
        // a is larger => a must be a branch
        if (!hasMatchAt(b_p, a_p, a_l)) {
          // the prefix of a and b is different. We don't care if a is a branch or a leaf
          join(a0, a, b0, b)
        } else a match {
          case a: Branch =>
            val am = a0 ^ a.left.sign
            if (zeroAt(b_p, a_l)) {
              // b fits into the left child of a
              a.lr(op(a0, a.left, b0, b), overlapA(am, a.right, b0 ^ b.sign))
            } else {
              // b fits into the right child of a
              a.lr(overlapA(a0, a.left, b0), op(am, a.right, b0, b))
            }
          // $COVERAGE-OFF$
          case _ => unreachable
          // $COVERAGE-ON$
        }
      } else if (b_l > a_l) {
        // b is larger => b must be a branch
        if (!hasMatchAt(a_p, b_p, b_l)) {
          // the prefix of a and b is different. We don't care if b is a branch or a leaf
          join(a0, a, b0, b)
        } else b match {
          case b: Branch =>
            val bm = b0 ^ b.left.sign
            if (zeroAt(a_p, b_l)) {
              // a fits into the left child of b
              b.lr(op(a0, a, b0, b.left), overlapB(a0 ^ a.sign, bm, b.right))
            } else {
              // a fits into the right child of b
              b.lr(overlapB(a0, b0, b.left), op(a0, a, bm, b.right))
            }
          // $COVERAGE-OFF$
          case _ => unreachable
          // $COVERAGE-ON$
        }
      } else {
        // a_l == b_l, trees are the same size
        if (a_p == b_p) {
          (a, b) match {
            case (a: Branch, b: Branch) =>
              val am = a0 ^ a.left.sign
              val bm = b0 ^ b.left.sign
              // same prefix. leaves have to be merged
              // todo: check if we can return b unchanged
              a.lr(op(a0, a.left, b0, b.left), op(am, a.right, bm, b.right))
            case (a: Leaf, b: Leaf) =>
              collision(a0, a, b0, b)
            // $COVERAGE-OFF$
            case _ => unreachable
            // $COVERAGE-ON$
          }
        } else {
          // same mask, different prefix
          join(a0, a, b0, b)
        }
      }
    }

    final def apply(a0: Boolean, a: Tree, b0: Boolean, b: Tree) = {
      if ((a eq null) && (b eq null))
        null
      else if (a eq null)
        overlapB(a0, b0, b)
      else if (b eq null)
        overlapA(a0, a, b0)
      else
        op(a0, a, b0, b)
    }
  }

  object DisjointCalculator extends BooleanBinaryOperator {

    override protected def op(a: Boolean, b: Boolean): Boolean = !(a & b)

    override protected def overlapB(a0: Boolean, b0: Boolean, b: Tree): Boolean = !a0

    override protected def overlapA(a0: Boolean, a: Tree, b0: Boolean): Boolean = !b0

    override protected def collision(a0: Boolean, a: Leaf, b0: Boolean, b: Leaf): Boolean = {
      val at1 = !((a.at ^ a0) & (b.at ^ b0))
      val above1 = !((a.above ^ a0) & (b.above ^ b0))
      at1 && above1
    }
  }

  object SupersetOfCalculator extends BooleanBinaryOperator {

    override protected def op(a: Boolean, b: Boolean): Boolean = a | !b

    override protected def overlapB(a0: Boolean, b0: Boolean, b: Tree): Boolean = a0

    override protected def overlapA(a0: Boolean, a: Tree, b0: Boolean): Boolean = !b0

    override protected def collision(a0: Boolean, a: Leaf, b0: Boolean, b: Leaf): Boolean = {
      val at1 = (a.at ^ a0) | !(b.at ^ b0)
      val above1 = (a.above ^ a0) | !(b.above ^ b0)
      at1 && above1
    }
  }

  object OrCalculator extends OrderedBinaryOperator {

    protected def collision(a0: Boolean, a: Leaf, b0: Boolean, b: Leaf) = {
      val below1 = a0 | b0
      val at1 = (a.at ^ a0) | (b.at ^ b0)
      val above1 = (a.above ^ a0) | (b.above ^ b0)
      leaf(below1 != at1, at1 != above1, a, b)
    }

    protected def overlapA(a0: Boolean, a: Tree, b0: Boolean) =
      if (b0)
        null
      else
        a

    protected def overlapB(a0: Boolean, b0: Boolean, b: Tree) =
      if (a0)
        null
      else
        b
  }

  object XorCalculator extends OrderedBinaryOperator {

    protected def collision(a0: Boolean, a: Leaf, b0: Boolean, b: Leaf) = {
      val below1 = a0 ^ b0
      val at1 = (a.at ^ a0) ^ (b.at ^ b0)
      val above1 = (a.above ^ a0) ^ (b.above ^ b0)
      leaf(below1 != at1, at1 != above1, a, b)
    }

    protected def overlapA(a0: Boolean, a: Tree, b0: Boolean) = a

    protected def overlapB(a0: Boolean, b0: Boolean, b: Tree) = b
  }

  object AndCalculator extends OrderedBinaryOperator {

    protected def collision(a0: Boolean, a: Leaf, b0: Boolean, b: Leaf) = {
      val below1 = a0 & b0
      val at1 = (a.at ^ a0) & (b.at ^ b0)
      val above1 = (a.above ^ a0) & (b.above ^ b0)
      leaf(below1 != at1, at1 != above1, a, b)
    }

    protected def overlapA(a0: Boolean, a: Tree, b0: Boolean) =
      if (b0)
        a
      else
        null

    protected def overlapB(a0: Boolean, b0: Boolean, b: Tree) =
      if (a0)
        b
      else
        null
  }

  /**
   * An operation that calculates the value before, at or behind a position
   */
  sealed abstract class Sampler {

    def apply(a0: Boolean, a: Tree, value: Long) = op(a0, a, value)

    /**
     * Method that is invoked when a leaf is found. This allows to customize whether we want at, before or after
     * @param a0 the value before the leaf
     * @param a the leaf
     */
    protected def onLeaf(a0: Boolean, a: Leaf): Boolean

    private final def op(a0: Boolean, a: Tree, value: Long): Boolean = a match {
      case a: Branch =>
        val prefix = a.prefix
        val level = a.level
        if (!hasMatchAt(value, prefix, level)) {
          // key is either before or after a
          val branchLevel = levelAbove(prefix, value)
          if (zeroAt(prefix, branchLevel))
            a0 ^ a.sign // after
          else
            a0 // before
        } else {
          // key is within a
          if (zeroAt(value, level))
            op(a0, a.left, value)
          else
            op(a0 ^ a.left.sign, a.right, value)
        }
      case a: Leaf =>
        if (a.prefix == value)
          onLeaf(a0, a)
        else if (unsigned_<(a.prefix, value))
          a0 ^ a.sign
        else
          a0
      case _ =>
        a0
    }
  }

  object SampleBelow extends Sampler {

    protected def onLeaf(a0: Boolean, a: Leaf): Boolean = a0
  }

  object SampleAt extends Sampler {

    protected def onLeaf(a0: Boolean, a: Leaf): Boolean = a0 ^ a.at
  }

  object SampleAbove extends Sampler {

    protected def onLeaf(a0: Boolean, a: Leaf): Boolean = a0 ^ a.above
  }

  def leaf(changeBelow: Boolean, changeAbove: Boolean, a: Leaf, b: Leaf) = {
    val at = changeBelow
    val sign = changeBelow ^ changeAbove
    if (!changeBelow && !changeAbove)
      null
    else if (at == a.at && sign == a.sign)
      a
    else if (at == b.at && sign == b.sign)
      b
    else
      Leaf(a.prefix, at, sign)
  }

  /**
   * A leaf.
   * @param prefix the prefix, which in case of a leaf is identical to the key
   */
  final case class Leaf(prefix: Long, at: Boolean, sign: Boolean) extends Tree {

    /**
     * For a leaf, the prefix is the key
     */
    def key = fromPrefix(prefix)

    /**
     * This is -1 for leaves, so that the smallest possible branch (level=0) has a bigger level than a leaf
     */
    def level = -1.toByte

    @inline def above = sign
  }

  /**
   * A branch
   * @param prefix the common prefix of both children
   * @param level the level of the node. 0..63 for branches. Higher means bigger
   * @param left the left child
   * @param right the right child
   */
  final case class Branch(prefix: Long, level: Byte, left: Tree, right: Tree) extends Tree {

    val sign = left.sign ^ right.sign

    def lr(left: Tree, right: Tree): Tree = {
      if (left eq null)
        right
      else if (right eq null)
        left
      else if ((left eq this.left) && (right eq this.right))
        this
      else
        copy(left = left, right = right)
    }
  }
}

private[interval] sealed abstract class Tree {

  def prefix: Long

  def level: Byte

  def sign: Boolean
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy