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

org.opalj.collection.immutable.UIDSet.scala Maven / Gradle / Ivy

The newest version!
/* BSD 2-Clause License - see OPAL/LICENSE for details. */
package org.opalj
package collection
package immutable

import scala.collection.generic.CanBuildFrom
import scala.collection.mutable.Builder
import scala.collection.mutable.ArrayStack

/**
 * An '''unordered''' trie-set based on the unique ids of the stored [[UID]] objects. I.e.,
 * equality of two sets is defined in terms of the unique ids and not in terms of structural or
 * reference equality of the stored elements.
 *
 * ==Implementation==
 * This trie set uses the least significant bit to decide whether the search is continued in the
 * right or left branch.
 *
 * Small sets are represented using a UIDSet0...3.
 *
 * Compared to Scala's `Set` implementations in particular the tail and filter methods are much
 * faster.
 */
sealed abstract class UIDSet[T <: UID]
    extends scala.collection.immutable.Set[T]
    with scala.collection.SetLike[T, UIDSet[T]] { set ⇒

    final override def empty: UIDSet[T] = UIDSet0.asInstanceOf[UIDSet[T]]
    final override def contains(e: T): Boolean = containsId(e.id)

    override def exists(p: T ⇒ Boolean): Boolean
    override def forall(p: T ⇒ Boolean): Boolean
    override def head: T
    /**
     * Returns the current last value, which is never head if the underlying set contains
     * at least two values. The last value can be different for two sets containing
     * the same values if both sets were created in different ways.
     */
    override def last: T
    override def tail: UIDSet[T] = throw new UnknownError()
    override def +(e: T): UIDSet[T]
    override def -(e: T): UIDSet[T]
    override def foldLeft[B](z: B)(op: (B, T) ⇒ B): B

    //
    // METHODS DEFINED BY UIDSet
    //

    /** Iterator over all ids. */
    def idIterator: IntIterator

    def foreachIterator: ForeachRefIterator[T] = new ForeachRefIterator[T] {
        def foreach[U](f: T ⇒ U): Unit = set.foreach(f)
    }

    override def iterator: RefIterator[T]
    // Note that, "super.toIterator" guarantees to call "iterator"

    def idSet: IntTrieSet

    def containsId(id: Int): Boolean

    def isSingletonSet: Boolean

    def ++(es: UIDSet[T]): UIDSet[T]
    def findById(id: Int): Option[T]

    /**
     * Adds the given element to this set by mutating it!
     */
    private[opalj] def +!(e: T): UIDSet[T] = this + e

    // The following method(s) is(are) unsafe if "+!" is used!
    final def toUIDSet[X >: T <: UID]: UIDSet[X] = this.asInstanceOf[UIDSet[X]]
    final def includes[X >: T <: UID](e: X): Boolean = containsId(e.id)
    final def add[X >: T <: UID](e: X): UIDSet[X] = {
        (this + (e.asInstanceOf[T] /*pure fiction*/ )).asInstanceOf[UIDSet[X] /*pure fiction*/ ]
    }

    /**
     * Performs a qualified comparison of this set with the given set.
     */
    def compare(that: UIDSet[T]): SetRelation = {
        val thisSize = this.size
        val thatSize = that.size

        if (thisSize < thatSize) {
            if (this.forall(e ⇒ that.containsId(e.id))) StrictSubset else UncomparableSets
        } else if (thisSize == thatSize) {
            if (this == that) EqualSets else UncomparableSets
        } else if (that.forall(e ⇒ this.containsId(e.id))) {
            StrictSuperset
        } else
            UncomparableSets
    }

    def toRefArray: RefArray[T] = new RefArray(toArray[AnyRef])

}

/**
 * Represents the empty UIDSet.
 */
object UIDSet0 extends UIDSet[UID] {

    override def isEmpty: Boolean = true
    override def nonEmpty: Boolean = false
    override def size: Int = 0

    override def find(p: UID ⇒ Boolean): Option[UID] = None
    override def exists(p: UID ⇒ Boolean): Boolean = false
    override def forall(p: UID ⇒ Boolean): Boolean = true
    override def foreach[U](f: UID ⇒ U): Unit = {}
    override def iterator: RefIterator[Nothing] = RefIterator.empty
    override def head: UID = throw new NoSuchElementException
    override def last: UID = throw new NoSuchElementException
    override def headOption: Option[UID] = None
    override def tail: UIDSet[UID] = throw new NoSuchElementException
    override def filter(p: UID ⇒ Boolean): UIDSet[UID] = this
    override def filterNot(p: UID ⇒ Boolean): UIDSet[UID] = this
    override def +(e: UID): UIDSet[UID] = new UIDSet1(e)
    override def -(e: UID): UIDSet[UID] = this
    override def foldLeft[B](z: B)(op: (B, UID) ⇒ B): B = z
    override def drop(n: Int): UIDSet[UID] = this
    // default equals/hashCode are a perfect fit

    //
    // METHODS DEFINED BY UIDSet
    //
    override def findById(id: Int): Option[UID] = None
    override def idIterator: IntIterator = IntIterator.empty
    override def foreachIterator: ForeachRefIterator[Nothing] = ForeachRefIterator.empty
    override def idSet: IntTrieSet = IntTrieSet.empty
    override def containsId(id: Int): Boolean = false
    override def isSingletonSet: Boolean = false
    override def ++(es: UIDSet[UID]): UIDSet[UID] = es
    override def compare(that: UIDSet[UID]): SetRelation = {
        if (that.isEmpty) EqualSets else /* this is a */ StrictSubset
    }

}

sealed abstract class NonEmptyUIDSet[T <: UID] extends UIDSet[T] {

    final override def isEmpty: Boolean = false
    final override def nonEmpty: Boolean = true
    final override def headOption: Option[T] = Some(head)
}

final case class UIDSet1[T <: UID](value: T) extends NonEmptyUIDSet[T] {

    override def size: Int = 1
    override def find(p: T ⇒ Boolean): Option[T] = if (p(value)) Some(value) else None
    override def exists(p: T ⇒ Boolean): Boolean = p(value)
    override def forall(p: T ⇒ Boolean): Boolean = p(value)
    override def foreach[U](f: T ⇒ U): Unit = f(value)
    override def head: T = value
    override def last: T = value
    override def tail: UIDSet[T] = empty
    override def iterator: RefIterator[T] = RefIterator(value)
    override def filter(p: T ⇒ Boolean): UIDSet[T] = if (p(value)) this else empty
    override def filterNot(p: T ⇒ Boolean): UIDSet[T] = if (p(value)) empty else this

    override def +(e: T): UIDSet[T] = if (value.id == e.id) this else new UIDSet2(value, e)
    override def -(e: T): UIDSet[T] = if (value.id == e.id) empty else this
    override def foldLeft[B](z: B)(op: (B, T) ⇒ B): B = op(z, value)
    override def drop(n: Int): UIDSet[T] = if (n == 0) this else empty

    override def hashCode(): Int = value.id
    override def equals(other: Any): Boolean = {
        other match {
            case that: UIDSet[_] ⇒ that.size == 1 && that.head.id == value.id
            case _               ⇒ false
        }
    }

    //
    // METHODS DEFINED BY UIDSet
    //

    override def findById(id: Int): Option[T] = if (value.id == id) Some(value) else None
    override def idIterator: IntIterator = IntIterator(value.id)
    override def idSet: IntTrieSet = IntTrieSet1(value.id)
    override def isSingletonSet: Boolean = true
    override def containsId(id: Int): Boolean = value.id == id

    override def ++(es: UIDSet[T]): UIDSet[T] = {
        if (es eq this)
            return this;

        es.size match {
            case 0 ⇒ this
            case 1 ⇒ this + es.head
            case _ ⇒ es + value
        }
    }

    override def compare(that: UIDSet[T]): SetRelation = {
        if (that.isEmpty) {
            StrictSuperset
        } else if (that.isSingletonSet) {
            if (this.value.id == that.head.id) EqualSets else UncomparableSets
        } else if (that.contains(this.value))
            StrictSubset
        else
            UncomparableSets
    }
}

final class UIDSet2[T <: UID](value1: T, value2: T) extends NonEmptyUIDSet[T] {

    override def size: Int = 2
    override def exists(p: T ⇒ Boolean): Boolean = p(value1) || p(value2)
    override def forall(p: T ⇒ Boolean): Boolean = p(value1) && p(value2)
    override def foreach[U](f: T ⇒ U): Unit = { f(value1); f(value2) }
    override def iterator: RefIterator[T] = RefIterator(value1, value2)
    override def head: T = value1
    override def last: T = value2
    override def tail: UIDSet[T] = new UIDSet1(value2)
    override def foldLeft[B](z: B)(op: (B, T) ⇒ B): B = op(op(z, value1), value2)

    override def find(p: T ⇒ Boolean): Option[T] = {
        if (p(value1)) Some(value1) else if (p(value2)) Some(value2) else None

    }

    override def filter(p: T ⇒ Boolean): UIDSet[T] = {
        if (p(value1)) {
            if (p(value2))
                this
            else
                new UIDSet1(value1)
        } else if (p(value2)) {
            new UIDSet1(value2)
        } else {
            empty
        }
    }

    override def filterNot(p: T ⇒ Boolean): UIDSet[T] = {
        if (p(value1)) {
            if (p(value2))
                empty
            else
                new UIDSet1(value2)
        } else if (p(value2)) {
            new UIDSet1(value1)
        } else {
            this
        }
    }

    override def drop(n: Int): UIDSet[T] = {
        if (n == 0) this else if (n == 1) new UIDSet1(value2) else empty
    }

    override def +(e: T): UIDSet[T] = {
        val eId = e.id
        val value1 = this.value1
        if (eId == value1.id)
            return this;
        val value2 = this.value2
        if (eId == value2.id)
            return this;

        new UIDSet3(value1, value2, e)
    }

    override def -(e: T): UIDSet[T] = {
        val eId = e.id
        if (value1.id == eId)
            new UIDSet1(value2)
        else if (value2.id == eId)
            new UIDSet1(value1)
        else
            this
    }

    override def hashCode: Int = value1.id ^ value2.id // ordering independent
    override def equals(other: Any): Boolean = {
        other match {
            case that: UIDSet[_] ⇒
                that.size == 2 && {
                    if (that.head.id == value1.id)
                        that.last.id == value2.id
                    else
                        that.head.id == value2.id && that.last.id == value1.id
                }
            case _ ⇒ false
        }
    }

    //
    // METHODS DEFINED BY UIDSet
    //

    override def findById(id: Int): Option[T] = {
        if (value1.id == id) Some(value1) else if (value2.id == id) Some(value2) else None
    }

    override def idIterator: IntIterator = IntIterator(value1.id, value2.id)
    override def idSet: IntTrieSet = IntTrieSet.from(value1.id, value2.id)
    override def isSingletonSet: Boolean = false
    override def containsId(id: Int): Boolean = value1.id == id || value2.id == id

    def ++(es: UIDSet[T]): UIDSet[T] = {
        if (es eq this)
            return this;

        es.size match {
            case 0 ⇒ this
            case 1 ⇒ this + es.head
            case 2 ⇒ this + es.head + es.last
            case _ ⇒ this.foldLeft(es)(_ + _) // es is larger... which should be less work
        }
    }
}
final object UIDSet2 {
    def apply[T <: UID](value1: T, value2: T): UIDSet2[T] = new UIDSet2[T](value1, value2)
}

final class UIDSet3[T <: UID](value1: T, value2: T, value3: T) extends NonEmptyUIDSet[T] {

    override def size: Int = 3
    override def find(p: T ⇒ Boolean): Option[T] = {
        if (p(value1)) Some(value1)
        else if (p(value2)) Some(value2)
        else if (p(value3)) Some(value3)
        else None
    }
    override def exists(p: T ⇒ Boolean): Boolean = p(value1) || p(value2) || p(value3)
    override def forall(p: T ⇒ Boolean): Boolean = p(value1) && p(value2) && p(value3)
    override def foreach[U](f: T ⇒ U): Unit = { f(value1); f(value2); f(value3) }
    override def iterator: RefIterator[T] = RefIterator(value1, value2, value3)
    override def head: T = value1
    override def last: T = value3
    override def tail: UIDSet[T] = new UIDSet2(value2, value3)
    override def filter(p: T ⇒ Boolean): UIDSet[T] = {
        if (p(value1)) {
            if (p(value2)) {
                if (p(value3))
                    this
                else
                    new UIDSet2[T](value1, value2)
            } else {
                if (p(value3))
                    new UIDSet2[T](value1, value3)
                else
                    new UIDSet1[T](value1)
            }
        } else {
            if (p(value2)) {
                if (p(value3))
                    new UIDSet2[T](value2, value3)
                else
                    new UIDSet1[T](value2)
            } else {
                if (p(value3))
                    new UIDSet1[T](value3)
                else
                    empty
            }
        }

    }
    override def filterNot(p: T ⇒ Boolean): UIDSet[T] = filter(e ⇒ !p(e))
    override def foldLeft[B](z: B)(op: (B, T) ⇒ B): B = op(op(op(z, value1), value2), value3)
    override def drop(n: Int): UIDSet[T] = {
        n match {
            case 0 ⇒ this
            case 1 ⇒ new UIDSet2(value2, value3)
            case 2 ⇒ new UIDSet1(value3)
            case _ ⇒ empty
        }
    }

    override def +(e: T): UIDSet[T] = {
        val eId = e.id
        val value1 = this.value1
        if (eId == value1.id)
            return this;
        val value2 = this.value2
        if (eId == value2.id)
            return this;
        val value3 = this.value3
        if (eId == value3.id)
            return this;

        // we only use the trie for sets with more than three elements
        new UIDSetInnerNode(1, value1, null, null) +! value2 +! value3 +! e
    }

    override def -(e: T): UIDSet[T] = {
        val eId = e.id
        if (value1.id == eId)
            new UIDSet2(value2, value3)
        else if (value2.id == eId)
            new UIDSet2(value1, value3)
        else if (value3.id == eId)
            new UIDSet2(value1, value2)
        else
            this
    }

    override def hashCode: Int = value1.id ^ value2.id ^ value3.id // ordering independent
    override def equals(other: Any): Boolean = {
        other match {
            case that: UIDSet[_] ⇒
                (that eq this) || {
                    that.size == 3 &&
                        that.containsId(value1.id) &&
                        that.containsId(value2.id) &&
                        that.containsId(value3.id)
                }
            case _ ⇒ false
        }
    }

    //
    // METHODS DEFINED BY UIDSet
    //

    override def findById(id: Int): Option[T] = {
        if (value1.id == id)
            Some(value1)
        else if (value2.id == id)
            Some(value2)
        else if (value3.id == id)
            Some(value3)
        else None
    }

    override def idIterator: IntIterator = IntIterator(value1.id, value2.id, value3.id)
    override def idSet: IntTrieSet = IntTrieSet.from(value1.id, value2.id, value3.id)
    override def isSingletonSet: Boolean = false
    override def containsId(id: Int): Boolean = {
        value1.id == id || value2.id == id || value3.id == id
    }
    override def ++(es: UIDSet[T]): UIDSet[T] = {
        if (es eq this)
            return this;

        es.size match {
            case 0 ⇒ this
            case 1 ⇒ this + es.head
            case 2 ⇒ this + es.head + es.last
            case _ ⇒ this.foldLeft(es)(_ + _) // es is at least as large as this set
        }
    }
}

// ------------------------------------------------------------------------------------------------
//
//
// If we have more than three values we always create a trie.
//
//
// ------------------------------------------------------------------------------------------------

sealed private[immutable] abstract class UIDSetNodeLike[T <: UID] extends NonEmptyUIDSet[T] {
    self ⇒

    protected def value: T

    // the following two methods return either a UIDSetNode, a UIDSetLeaf or null:
    protected def left: UIDSetNodeLike[T]
    protected def right: UIDSetNodeLike[T]

    override def find(p: T ⇒ Boolean): Option[T] = {
        if (p(value))
            return Some(value);

        if (left ne null) {
            val result = left.find(p);
            if (result.isDefined)
                return result;
        }
        if (right ne null) {
            val result = right.find(p)
            if (result.isDefined)
                return result;
        }
        None
    }

    override def exists(p: T ⇒ Boolean): Boolean = {
        p(value) || (left != null && left.exists(p)) || (right != null && right.exists(p))
    }

    override def forall(p: T ⇒ Boolean): Boolean = {
        p(value) && {
            val left = this.left
            left == null || left.forall(p)
        } && {
            val right = this.right
            right == null || right.forall(p)
        }
    }

    override def foreach[U](f: T ⇒ U): Unit = {
        f(value)
        val left = this.left; if (left ne null) left.foreach(f)
        val right = this.right; if (right ne null) right.foreach(f)
        /*
        val nodes = new Array[UIDSetNodeLike[T]](32 /*IMPROVE... we have to know the depth...*/ )
        nodes(0) = this
        var lastElementOnStack = 0
        while (lastElementOnStack >= 0) {
            val node = nodes(lastElementOnStack)

                    f(node.value)
                    lastElementOnStack -= 1
                    val left = node.left
                    if (left ne null) {
                        lastElementOnStack += 1
                        nodes(lastElementOnStack) = left
                    }
                    val right = node.right
                    if (right ne null) {
                        lastElementOnStack += 1
                        nodes(lastElementOnStack) = right
                    }
        }
*/
    }

    def iterator: RefIterator[T] = new RefIterator[T] {
        private[this] val nextNodes = ArrayStack[UIDSetNodeLike[T]](self)
        def hasNext: Boolean = nextNodes.nonEmpty
        def next: T = {
            val currentNode = nextNodes.pop
            val nextRight = currentNode.right
            val nextLeft = currentNode.left
            if (nextRight ne null) nextNodes.push(nextRight)
            if (nextLeft ne null) nextNodes.push(nextLeft)
            currentNode.value
        }
    }

    override def head: T = value

    override def tail: UIDSet[T] = {
        /*current...*/ size match {
            case 1 ⇒ empty
            case 2 ⇒
                val left = this.left
                new UIDSet1(if (left ne null) left.value else right.value)
            case 3 ⇒
                val left = this.left
                val right = this.right
                if (left eq null)
                    new UIDSet2(right.head, right.last)
                else if (right eq null)
                    new UIDSet2(left.head, left.last)
                else
                    new UIDSet2(left.head, right.head)
            case _ ⇒
                dropHead
        }
    }

    override def foldLeft[B](z: B)(op: (B, T) ⇒ B): B = {
        val left = this.left
        val right = this.right
        var result = op(z, value)
        if (left ne null) result = left.foldLeft(result)(op)
        if (right ne null) result = right.foldLeft(result)(op)
        result
    }

    final def +(e: T): UIDSet[T] = { val eId = e.id; this + (e, eId, eId, 0) }

    final def -(e: T): UIDSet[T] = {
        size match {
            case 1 ⇒ throw new UnknownError
            case 2 ⇒
                val value = this.value
                val eId = e.id
                if (value.id == eId)
                    new UIDSet1(if (left ne null) left.head else right.head)
                else {
                    val value1 = value
                    val value2Candidate = if (left ne null) left.head else right.head
                    if (value2Candidate.id == eId)
                        new UIDSet1(value)
                    else
                        new UIDSet2(value1, value2Candidate)
                }
            case 3 ⇒
                val value = this.value
                val eId = e.id
                if (value.id == eId) {
                    // let's remove this value
                    if (left ne null) {
                        if (right ne null)
                            new UIDSet2(left.head, right.head)
                        else
                            new UIDSet2(left.head, left.last)
                    } else {
                        new UIDSet2(right.head, right.last)
                    }
                } else {
                    // we have to keep this value...
                    var value2Candidate: T = null.asInstanceOf[T]
                    var value3Candidate: T = null.asInstanceOf[T]
                    if (left ne null) {
                        if (right ne null) {
                            value2Candidate = left.head
                            value3Candidate = right.head
                        } else {
                            value2Candidate = left.head
                            value3Candidate = left.last
                        }
                    } else {
                        value2Candidate = right.head
                        value3Candidate = right.last
                    }
                    if (value2Candidate.id == eId)
                        new UIDSet2(value, value3Candidate)
                    else if (value3Candidate.id == eId)
                        new UIDSet2(value, value2Candidate)
                    else
                        this
                }
            case _ ⇒
                val eId = e.id
                this.-(eId, eId)
        }
    }

    override def filter(p: T ⇒ Boolean): UIDSet[T] = {
        val result = filter0(p)
        if (result == null)
            return empty;

        result.size match {
            case 1 ⇒ new UIDSet1(result.head)
            case 2 ⇒ new UIDSet2(result.head, result.last)
            case _ ⇒ result
        }
    }

    private def filter0(p: T ⇒ Boolean): UIDSetNodeLike[T] = {
        val left = this.left
        val right = this.right
        val newLeft = if (left != null) left.filter0(p) else null
        val newRight = if (right != null) right.filter0(p) else null
        if (p(value)) {
            if ((newLeft ne left) || (newRight ne right)) {
                var newSize = 1
                if (newLeft ne null) newSize += newLeft.size
                if (newRight ne null) newSize += newRight.size
                if (newSize == 1)
                    new UIDSetLeaf(value)
                else
                    new UIDSetInnerNode(newSize, value, newLeft, newRight)
            } else {
                this
            }
        } else {
            selectHead(newLeft, newRight)
        }
    }

    override def filterNot(p: T ⇒ Boolean): UIDSet[T] = filter((u: T) ⇒ !p(u))

    //
    // METHODS DEFINED BY UIDSet
    //

    override def idIterator: IntIterator = {
        new IntIterator {

            private[this] val nextNodes = ArrayStack[UIDSetNodeLike[T]](self)

            override def hasNext: Boolean = nextNodes.nonEmpty

            override def next(): Int = {
                val currentNode = nextNodes.pop
                val nextRight = currentNode.right
                val nextLeft = currentNode.left
                if (nextRight ne null) nextNodes.push(nextRight)
                if (nextLeft ne null) nextNodes.push(nextLeft)
                currentNode.value.id
            }
        }
    }

    override def idSet: IntTrieSet = growIdSet(IntTrieSet.empty)

    protected[immutable] def growIdSet(set: IntTrieSet): IntTrieSet

    override def isSingletonSet: Boolean = false

    override def findById(id: Int): Option[T] = {
        var currentNode: UIDSetNodeLike[T] = this
        var currentShiftedEId = id
        do {
            if (currentNode.value.id == id)
                return Some(currentNode.value);

            if ((currentShiftedEId & 1) == 1)
                currentNode = currentNode.right
            else
                currentNode = currentNode.left

            currentShiftedEId = currentShiftedEId >>> 1

        } while (currentNode ne null)
        None
    }

    override def ++(es: UIDSet[T]): UIDSet[T] = {
        if (es eq this)
            return this;

        es.size match {
            case 0 ⇒ this
            case 1 ⇒ this + es.head
            case 2 ⇒ this + es.head + es.last
            case esSize ⇒
                if (this.size > esSize)
                    es.foldLeft(this: UIDSet[T])(_ + _)
                else
                    this.foldLeft(es: UIDSet[T])(_ + _)
        }
    }

    private def selectHead(
        left:  UIDSetNodeLike[T],
        right: UIDSetNodeLike[T]
    ): UIDSetNodeLike[T] = {
        val rightSize = if (right ne null) right.size else 0
        var newSize = rightSize
        if (left ne null) {
            val leftSize = left.size
            newSize += leftSize
            val leftValue = left.head
            if (leftSize == 1) {
                if (right eq null)
                    new UIDSetLeaf(leftValue)
                else
                    new UIDSetInnerNode(newSize, leftValue, null, right)
            } else {
                new UIDSetInnerNode(newSize, leftValue, left.dropHead, right)
            }
        } else if (right ne null) {
            val rightValue = right.head
            if (rightSize == 1) {
                if (left eq null)
                    new UIDSetLeaf(rightValue)
                else
                    new UIDSetInnerNode(newSize, rightValue, left, null)
            } else {
                new UIDSetInnerNode(newSize, rightValue, left, right.dropHead)
            }
        } else {
            null
        }
    }

    private def dropHead: UIDSetNodeLike[T] = {
        if (left ne null) {
            val leftValue = left.head
            if (left.size == 1) {
                if (right eq null)
                    new UIDSetLeaf(leftValue)
                else
                    new UIDSetInnerNode(size - 1, leftValue, null, right)
            } else { //left.size >= 2... but maybe we can pull the right value...
                if ((right ne null) && right.size == 1)
                    new UIDSetInnerNode(size - 1, right.head, left, null)
                else
                    new UIDSetInnerNode(size - 1, leftValue, left.dropHead, right)
            }
        } else if (right ne null) {
            val rightValue = right.head
            if (right.size == 1) {
                if (left eq null)
                    new UIDSetLeaf(rightValue)
                else
                    new UIDSetInnerNode(size - 1, rightValue, left, null)
            } else { //right.size >= 2... but maybe we can pull the left value...
                if ((left ne null) && left.size == 1)
                    new UIDSetInnerNode(size - 1, left.head, null, right)
                else
                    new UIDSetInnerNode(size - 1, rightValue, left, right.dropHead)
            }
        } else {
            null
        }
    }

    override def containsId(id: Int): Boolean = containsId(id, id)

    private[immutable] def containsId(id: Int, shiftedId: Int): Boolean = {
        /* The recursive version is roughly 5% slower...
        this.value.id == eId || {
            if ((shiftedEId & 1) == 1)
                right != null && right.contains(eId, shiftedEId >>> 1)
            else
                left != null && left.contains(eId, shiftedEId >>> 1)
        }
        */

        var currentNode: UIDSetNodeLike[T] = this
        var currentShiftedId = shiftedId
        do {
            if (currentNode.value.id == id)
                return true;

            if ((currentShiftedId & 1) == 1)
                currentNode = currentNode.right
            else
                currentNode = currentNode.left

            currentShiftedId = currentShiftedId >>> 1

        } while (currentNode ne null)
        false
    }

    private[immutable] def +!(e: T, eId: Int, shiftedEId: Int, level: Int): UIDSetNodeLike[T]

    private def +(e: T, eId: Int, shiftedEId: Int, level: Int): UIDSetNodeLike[T] = {
        val valueId = this.value.id
        // In the following, we try to minimize the high of the tree.
        if (valueId == eId)
            return this;

        val right = this.right
        val left = this.left
        var newRight = right
        var newLeft = left
        if ((shiftedEId & 1) == 1) {
            // we have to add the value "here" or on the right branch
            if (newRight eq null)
                newRight = new UIDSetLeaf(e)
            else {
                val newShiftedEId = shiftedEId >>> 1
                if ((newLeft eq null) &&
                    (valueId >>> level & 1) == 0 &&
                    !newRight.containsId(eId, newShiftedEId)) {
                    // we can move the current value to the empty left branch...
                    return new UIDSetInnerNode(size + 1, e, new UIDSetLeaf(value), newRight);
                } else {
                    newRight += (e, eId, newShiftedEId, level + 1)
                    if (newRight eq right)
                        return this;
                }
            }
        } else {
            if (newLeft eq null)
                newLeft = new UIDSetLeaf(e)
            else {
                val newShiftedEId = shiftedEId >>> 1
                if ((newRight eq null) &&
                    (valueId >>> level & 1) == 1 &&
                    !newLeft.containsId(eId, newShiftedEId)) {
                    // we can move the current value to the empty right branch...
                    return new UIDSetInnerNode(size + 1, e, newLeft, new UIDSetLeaf(value));
                } else {
                    newLeft += (e, eId, newShiftedEId, level + 1)
                    if (newLeft eq left)
                        return this;
                }
            }
        }
        new UIDSetInnerNode(size + 1, value, newLeft, newRight)
    }

    private def -(eId: Int, shiftedEId: Int): UIDSetNodeLike[T] = {
        // assert( size > 3) // i.e., after removal we still have a tree
        val value = this.value
        if (value.id == eId) {
            dropHead
        } else { // we don't delete this value ...
            val left = this.left
            val right = this.right
            var newLeft = left
            var newRight = right
            if ((shiftedEId & 1) == 1) {
                if (right eq null)
                    return this;
                // we have to search for the value in the right tree
                newRight = right - (eId, shiftedEId >>> 1)
                if (newRight eq right)
                    return this;
            } else {
                if (left eq null)
                    return this;
                newLeft = left - (eId, shiftedEId >>> 1)
                if (newLeft eq left)
                    return this;
            }
            new UIDSetInnerNode(size - 1, value, newLeft, newRight)
        }
    }

    def showTree(level: Int = 0): String = {
        val indent = "  " * level
        indent + value.id.toBinaryString + s" #$size("+
            (if (left ne null) s"\n$indent left ="+left.showTree(level + 1)+"\n" else "") +
            (if (right ne null) s"\n$indent right="+right.showTree(level + 1)+"\n)" else ")")
    }
}

private[immutable] object UIDSetNode {

    def apply[T <: UID](
        size:  Int,
        value: T,
        left:  UIDSetNodeLike[T],
        right: UIDSetNodeLike[T]
    ): UIDSetNodeLike[T] = {
        if (size == 1)
            new UIDSetLeaf(value)
        else
            new UIDSetInnerNode(size, value, left, right)
    }

}

final class UIDSetLeaf[T <: UID] private[immutable] (
        val value: T
) extends UIDSetNodeLike[T] {
    override def size: Int = 1
    override def left: UIDSetNodeLike[T] = null
    override def right: UIDSetNodeLike[T] = null
    override def head: T = value
    override def tail: UIDSet[T] = empty
    override def last: T = value
    override def filter(p: T ⇒ Boolean): UIDSet[T] = if (p(value)) this else null
    override def foldLeft[B](z: B)(op: (B, T) ⇒ B): B = op(z, value)
    override def exists(p: T ⇒ Boolean): Boolean = p(value)
    override def forall(p: T ⇒ Boolean): Boolean = p(value)
    override def foreach[U](f: T ⇒ U): Unit = f(value)
    override def iterator: RefIterator[T] = RefIterator(value)
    override def find(p: T ⇒ Boolean): Option[T] = if (p(value)) Some(value) else None
    override def findById(id: Int): Option[T] = if (value.id == id) Some(value) else None

    override def hashCode: Int = value.id.hashCode()

    override def equals(that: Any): Boolean = {
        that match {
            case that: UIDSet[_] ⇒ that.size == 1 && that.head.id == this.value.id
            case _               ⇒ false
        }
    }

    override private[opalj] def +!(e: T): UIDSet[T] = throw new UnknownError

    private[immutable] def +!(e: T, eId: Int, shiftedEId: Int, level: Int): UIDSetNodeLike[T] = {
        if (value.id == eId)
            return this;

        if ((shiftedEId & 1) == 1)
            new UIDSetInnerNode(2, value, null, new UIDSetLeaf(e))
        else
            new UIDSetInnerNode(2, value, new UIDSetLeaf(e), null)
    }

    override def containsId(id: Int): Boolean = id == value.id
    protected[immutable] def growIdSet(set: IntTrieSet): IntTrieSet = set + value.id

}

// we wan't to be able to adapt the case class...
final class UIDSetInnerNode[T <: UID] private[immutable] (
        protected var theSize:          Int,
        protected[immutable] var value: T,
        protected[immutable] var left:  UIDSetNodeLike[T],
        protected[immutable] var right: UIDSetNodeLike[T]
) extends UIDSetNodeLike[T] {

    override def size: Int = theSize

    override def last: T = {
        if (right ne null)
            right.last
        else if (left ne null)
            left.last
        else
            value
    }

    override def hashCode: Int = {
        // ordering independent
        var hash = value.id
        if (left ne null) hash ^= left.hashCode()
        if (right ne null) hash ^= right.hashCode()
        hash
    }

    override def equals(other: Any): Boolean = {
        other match {
            case that: UIDSet[_] ⇒
                (that eq this) ||
                    (that.size == theSize && this.forall(e ⇒ that.containsId(e.id)))
            case _ ⇒ false
        }
    }

    override private[opalj] def +!(e: T): UIDSet[T] = {
        val eId = e.id
        this +! (e, eId, eId, 0)
        this
    }

    private[immutable] def +!(
        e:          T,
        eId:        Int,
        shiftedEId: Int,
        level:      Int
    ): UIDSetNodeLike[T] = {
        val value = this.value
        val valueId = value.id
        if (eId == valueId)
            return this;

        val left = this.left
        val right = this.right
        if ((shiftedEId & 1) == 1) {
            // we have to add the new value here or to the right branch
            if (right eq null) {
                this.right = new UIDSetLeaf(e)
                this.theSize += 1
            } else if ((left eq null) &&
                (valueId >>> level & 1) == 0 &&
                !right.containsId(eId, shiftedEId >>> 1)) {
                this.left = new UIDSetLeaf(value)
                this.value = e
                this.theSize += 1
            } else {
                val newRight = right +! (e, eId, shiftedEId >>> 1, level + 1)
                this.right = newRight
                this.theSize = (if (left ne null) left.size else 0) + newRight.size + 1
            }
        } else {
            // we have to add the new value here or to the left branch
            if (left eq null) {
                this.left = new UIDSetLeaf(e)
                this.theSize += 1
            } else if ((right eq null) &&
                (valueId >>> level & 1) == 1 &&
                !left.containsId(eId, shiftedEId >>> 1)) {
                this.right = new UIDSetLeaf(value)
                this.value = e
                this.theSize += 1
            } else {
                val newLeft = left +! (e, eId, shiftedEId >>> 1, level + 1)
                this.left = newLeft
                this.theSize = newLeft.size + (if (right ne null) right.size else 0) + 1
            }
        }
        this
    }

    protected[immutable] def growIdSet(set: IntTrieSet): IntTrieSet = {
        var newSet = set + value.id
        val nextLeft = this.left
        if (nextLeft ne null) {
            newSet = nextLeft.growIdSet(newSet)
        }
        val nextRight = this.right
        if (nextRight ne null) {
            newSet = nextRight.growIdSet(newSet)
        }
        newSet
    }

}

object UIDSet {

    class UIDSetBuilder[T <: UID] extends Builder[T, UIDSet[T]] {
        private var s: UIDSet[T] = empty[T]
        def +=(elem: T): this.type = {
            s +!= elem
            this
        }
        def clear(): Unit = s = empty
        def result(): UIDSet[T] = s
    }

    implicit def canBuildFrom[T <: UID]: CanBuildFrom[UIDSet[_], T, UIDSet[T]] = {
        new CanBuildFrom[UIDSet[_], T, UIDSet[T]] {
            override def apply(from: UIDSet[_]): UIDSetBuilder[T] = newBuilder[T]
            override def apply(): UIDSetBuilder[T] = newBuilder[T]
        }
    }

    def canBuildUIDSet[T <: UID]: CanBuildFrom[Any, T, UIDSet[T]] = {
        new CanBuildFrom[Any, T, UIDSet[T]] {
            override def apply(from: Any): UIDSetBuilder[T] = newBuilder[T]
            override def apply(): UIDSetBuilder[T] = newBuilder[T]
        }
    }

    def newBuilder[T <: UID]: UIDSetBuilder[T] = new UIDSetBuilder[T]

    def empty[T <: UID]: UIDSet[T] = UIDSet0.asInstanceOf[UIDSet[T]]

    def apply[T <: UID](vs: T*): UIDSet[T] = {
        if (vs.isEmpty)
            empty[T]
        else {
            vs.foldLeft(empty[T]: UIDSet[T])(_ +! _)
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy