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

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

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

/**
 * An unordered set of integer values backed by a trie set. The branching is done using
 * the least significant bit and values are only stored in leaf nodes. This ensure that
 * we have a stable iteration order.
 *
 * @author Michael Eichberg
 */
sealed abstract class IntTrieSet
    extends IntSet[IntTrieSet]
    with IntCollectionWithStableOrdering[IntTrieSet]
    with IntWorkSet[IntTrieSet] { intSet ⇒

    /**
     * Returns each pairing of two values. I.e., if the set contains 1, 4, 8, the pairings
     * ((1,4) XOR (4,1)),((1,8) XOR (8,1)) and ((4,8) XOR (8,4)) will be returned; hence,
     * the order between the two values is not defined.
     */
    def foreachPair[U](f: (Int, Int) ⇒ U): Unit
    def intersect(other: IntTrieSet): IntTrieSet = {
        if (other.size <= 2)
            // we have specialized handling for small sets
            return other.intersect(this);

        val (smallerSet, largerSet) = if (other.size > this.size) (this, other) else (other, this)
        var r = smallerSet
        val it = smallerSet.iterator
        while (it.hasNext) {
            val n = it.next()
            if (!largerSet.contains(n)) {
                r -= n
            }
        }
        r
    }

    /** Returns some value and removes it from this set. */
    def headAndTail: IntRefPair[IntTrieSet]

    def filter(p: Int ⇒ Boolean): IntTrieSet
    override def withFilter(p: Int ⇒ Boolean): IntTrieSet

    final override def subsetOf(other: IntTrieSet): Boolean = subsetOf(other, 0)

    final override def toString: String = mkString("IntTrieSet(", ",", ")")

    /**
     * Tries to add the given method to this trie set by ''mutating the set if possible''.
     * Due to the internal organization, mutating the set is not always possible. In this case, a
     * new set containing the new value is returned. Hence, the return value ''does not have to'' be
     * ignored!
     */
    def +!(value: Int): IntTrieSet

    /**
     * @see `+!(Int)` for details!
     */
    final def ++!(that: IntTrieSet): IntTrieSet = {
        that.foldLeft(this)(_ +! _) // We have to expand `this`!
    }

    /**
     * Merges the values of this and the given set into the set that is larger. If both sets
     * have equal sizes, then the given one is merged into this one.
     *
     * @see `+!(Int)` for details!
     */
    final def !++!(that: IntTrieSet): IntTrieSet = {
        if (this.size < that.size)
            that.++!(this)
        else
            this.++!(that)
    }

    final override def equals(other: Any): Boolean = {
        other match {
            case that: IntTrieSet ⇒ this.equals(that)
            case _                ⇒ false
        }
    }

    def equals(other: IntTrieSet): Boolean

    //
    // IMPLEMENTATION "INTERNAL" METHODS
    //

    private[immutable] def +(i: Int, level: Int): IntTrieSet
    private[immutable] def +!(i: Int, level: Int): IntTrieSet
    private[immutable] def -(i: Int, key: Int): IntTrieSet
    private[immutable] def contains(value: Int, key: Int): Boolean
    private[immutable] def subsetOf(other: IntTrieSet, level: Int): Boolean

    /** Ensures that this set is represented using its canonical representation. */
    private[immutable] def constringe(): IntTrieSet
}

// TODO Reduce to FilterMonadic
final class FilteredIntTrieSet(
        private val s: IntTrieSet,
        private val p: Int ⇒ Boolean
) extends IntTrieSet {

    override def iterator: IntIterator = s.iterator.withFilter(p)

    override def foreach[U](f: Int ⇒ U): Unit = s.foreach { i ⇒ if (p(i)) f(i) }
    override def map(f: Int ⇒ Int): IntTrieSet = {
        s.foldLeft(EmptyIntTrieSet: IntTrieSet) { (c, i) ⇒ if (p(i)) c +! f(i) else c }
    }
    override def map(map: Array[Int]): IntTrieSet = {
        s.foldLeft(EmptyIntTrieSet: IntTrieSet) { (c, i) ⇒ if (p(i)) c +! map(i) else c }
    }
    override def flatMap(f: Int ⇒ IntTrieSet): IntTrieSet = {
        s.flatMap(i ⇒ if (p(i)) f(i) else EmptyIntTrieSet)
    }
    override def withFilter(p: Int ⇒ Boolean): IntTrieSet = {
        new FilteredIntTrieSet(s, i ⇒ p(i) && this.p(i))
    }

    override def exists(p: Int ⇒ Boolean): Boolean = s.exists(i ⇒ this.p(i) && p(i))
    override def forall(f: Int ⇒ Boolean): Boolean = s.forall(i ⇒ !this.p(i) || f(i))
    override def contains(value: Int): Boolean = p(value) && s.contains(value)
    override def toChain: Chain[Int] = iterator.toChain

    private[this] lazy val filtered: IntTrieSet = s.filter(p)

    override def intersect(other: IntTrieSet): IntTrieSet = filtered.intersect(other)
    override def foreachPair[U](f: (Int, Int) ⇒ U): Unit = filtered.foreachPair(f)
    override def filter(p: Int ⇒ Boolean): IntTrieSet = filtered.filter(p)
    override def isSingletonSet: Boolean = filtered.isSingletonSet
    override def hasMultipleElements: Boolean = filtered.hasMultipleElements
    override def isEmpty: Boolean = filtered.isEmpty
    override def size: Int = filtered.size
    override def head: Int = filtered.head
    override def headAndTail: IntRefPair[IntTrieSet] = filtered.headAndTail
    override def -(i: Int): IntTrieSet = filtered - i
    override def +(i: Int): IntTrieSet = filtered + i
    override def +!(value: Int): IntTrieSet = filtered +! value
    override def foldLeft[B](z: B)(f: (B, Int) ⇒ B): B = filtered.foldLeft(z)(f)
    override def equals(other: IntTrieSet): Boolean = filtered.equals(other)
    override def hashCode: Int = filtered.hashCode()

    // Actually the following methods should never be called... in a sense they are dead.
    private[immutable] override def constringe(): IntTrieSet = filtered.constringe()
    private[immutable] override def -(i: Int, key: Int): IntTrieSet = filtered - (i, key)
    private[immutable] override def +(i: Int, level: Int): IntTrieSet = filtered + (i, level)
    private[immutable] override def +!(i: Int, level: Int): IntTrieSet = filtered +! (i, level)
    private[immutable] override def contains(value: Int, key: Int): Boolean = {
        filtered.contains(value, key)
    }
    private[immutable] override def subsetOf(other: IntTrieSet, level: Int): Boolean = {
        filtered.subsetOf(other, level)
    }
}

/** The (potential) leaves of an IntTrie. */
private[immutable] sealed abstract class IntTrieSetL extends IntTrieSet {

    final override private[immutable] def -(i: Int, key: Int): IntTrieSet = this.-(i)
    final override private[immutable] def constringe(): IntTrieSet = this
    final override private[immutable] def contains(value: Int, key: Int): Boolean = {
        this.contains(value)
    }
}

case object EmptyIntTrieSet extends IntTrieSetL {
    override def isSingletonSet: Boolean = false
    override def hasMultipleElements: Boolean = false
    override def isEmpty: Boolean = true
    override def size: Int = 0
    override def head: Int = throw new UnsupportedOperationException("empty")
    override def headAndTail: IntRefPair[IntTrieSet] = {
        throw new UnsupportedOperationException("headAndTail")
    }
    override def foreach[U](f: Int ⇒ U): Unit = {}
    override def foreachPair[U](f: (Int, Int) ⇒ U): Unit = {}
    override def filter(p: Int ⇒ Boolean): IntTrieSet = this
    override def withFilter(p: Int ⇒ Boolean): IntTrieSet = this
    override def map(f: Int ⇒ Int): IntTrieSet = this
    override def map(map: Array[Int]): IntTrieSet = this
    override def -(i: Int): this.type = this
    override def +(i: Int): IntTrieSet1 = IntTrieSet1(i)
    override def +!(i: Int): IntTrieSet1 = IntTrieSet1(i)
    override def intersect(other: IntTrieSet): IntTrieSet = this
    override def iterator: IntIterator = IntIterator.empty
    override def contains(value: Int): Boolean = false
    override def exists(p: Int ⇒ Boolean): Boolean = false
    override def foldLeft[B](z: B)(f: (B, Int) ⇒ B): B = z
    override def forall(f: Int ⇒ Boolean): Boolean = true
    override def flatMap(f: Int ⇒ IntTrieSet): IntTrieSet = this
    override def toChain: Chain[Int] = Naught

    override def equals(other: IntTrieSet): Boolean = other eq this
    override def hashCode: Int = 0 // compatible to Arrays.hashCode

    private[immutable] override def +(i: Int, level: Int): IntTrieSet = this.+(i)
    private[immutable] override def +!(i: Int, level: Int /* irrelevant */ ): IntTrieSet = this.+!(i)
    private[immutable] override def subsetOf(other: IntTrieSet, level: Int): Boolean = true
}

final case class IntTrieSet1 private (i: Int) extends IntTrieSetL {
    override def isEmpty: Boolean = false
    override def isSingletonSet: Boolean = true
    override def hasMultipleElements: Boolean = false
    override def size: Int = 1
    override def foreach[U](f: Int ⇒ U): Unit = { f(i) }
    override def foreachPair[U](f: (Int, Int) ⇒ U): Unit = {}
    override def headAndTail: IntRefPair[IntTrieSet] = IntRefPair(i, IntTrieSet.empty)
    override def filter(p: Int ⇒ Boolean): IntTrieSet = if (p(i)) this else EmptyIntTrieSet
    override def withFilter(p: Int ⇒ Boolean): IntTrieSet = new FilteredIntTrieSet(this, p)
    override def map(f: Int ⇒ Int): IntTrieSet = {
        val newI = f(i)
        if (newI != i)
            IntTrieSet1(newI)
        else
            this
    }
    override def map(map: Array[Int]): IntTrieSet = {
        val newI = map(i)
        if (newI != i)
            IntTrieSet1(newI)
        else
            this
    }
    override def flatMap(f: Int ⇒ IntTrieSet): IntTrieSet = f(i)
    override def head: Int = i
    override def -(i: Int): IntTrieSet = if (this.i != i) this else EmptyIntTrieSet
    override def +(i: Int): IntTrieSet = if (this.i == i) this else IntTrieSet.from(this.i, i)
    override def +!(i: Int): IntTrieSet = this + i
    override def iterator: IntIterator = IntIterator(i)
    override def intersect(other: IntTrieSet): IntTrieSet = {
        if (other.contains(this.i)) this else EmptyIntTrieSet
    }
    override def contains(value: Int): Boolean = value == i
    override def exists(p: Int ⇒ Boolean): Boolean = p(i)
    override def foldLeft[B](z: B)(f: (B, Int) ⇒ B): B = f(z, i)
    override def forall(f: Int ⇒ Boolean): Boolean = f(i)
    override def toChain: Chain[Int] = new :&:[Int](i)

    override def equals(other: IntTrieSet): Boolean = {
        (other eq this) || (other match {
            case that: IntTrieSet1 ⇒ this.i == that.i
            case that              ⇒ that.isSingletonSet && this.i == that.head
        })
    }

    override def hashCode: Int = 31 + i // compatible to Arrays.hashCode

    override private[immutable] def +(i: Int, level: Int): IntTrieSet = this.+(i)
    override private[immutable] def +!(i: Int, level: Int /* irrelevant */ ): IntTrieSet = this.+!(i)
    override private[immutable] def subsetOf(other: IntTrieSet, level: Int): Boolean = {
        other.contains(i, i >>> level)
    }
}

object IntTrieSet1 {

    // The preallocation of the IntTrieSet1 data structures costs ~2Mb memory;
    // however, we use it as the backbone Infrastructure for storing CFGs and
    // def-use information; in both cases, we generally require HUGE numbers
    // of such sets in the preconfigured ranges and therefore we avoid allocating
    // several hundred million instances (in case of a thorough analysis of the
    // JDK) and corresponding memory.
    val Cache1LowerBound = -100000 - (48 * 1024) // inclusive
    val Cache1UpperBound = -99999 // exclusive
    val Cache2LowerBound = -2048 // inclusive
    val Cache2UpperBound = 48 * 1024 // exclusive

    private[this] val cache1: Array[IntTrieSet1] = {
        val a = new Array[IntTrieSet1](Cache1UpperBound + (-Cache1LowerBound))
        var v = Cache1LowerBound
        var index = 0
        while (v < Cache1UpperBound) {
            a(index) = new IntTrieSet1(v)
            index += 1
            v += 1
        }
        a
    }

    private[this] val cache2: Array[IntTrieSet1] = {
        val a = new Array[IntTrieSet1](Cache2UpperBound + (-Cache2LowerBound))
        var v = Cache2LowerBound
        var index = 0
        while (v < Cache2UpperBound) {
            a(index) = new IntTrieSet1(v)
            index += 1
            v += 1
        }
        a
    }

    def apply(v: Int): IntTrieSet1 = {
        if (v >= Cache1LowerBound && v < Cache1UpperBound) {
            cache1(v + (-Cache1LowerBound))
        } else if (v >= Cache2LowerBound && v < Cache2UpperBound) {
            cache2(v + (-Cache2LowerBound))
        } else {
            new IntTrieSet1(v)
        }
    }
}

/**
 * Represents an ordered set of two values where i1 has to be smaller than i2.
 */
private[immutable] final class IntTrieSet2 private[immutable] (
        val i1: Int, val i2: Int
) extends IntTrieSetL {

    override def isEmpty: Boolean = false
    override def isSingletonSet: Boolean = false
    override def hasMultipleElements: Boolean = true
    override def size: Int = 2
    override def head: Int = i2
    override def headAndTail: IntRefPair[IntTrieSet] = IntRefPair(i2, IntTrieSet1(i1))
    override def iterator: IntIterator = IntIterator(i1, i2)
    override def foreach[U](f: Int ⇒ U): Unit = { f(i1); f(i2) }
    override def foreachPair[U](f: (Int, Int) ⇒ U): Unit = { f(i1, i2) }
    override def filter(p: Int ⇒ Boolean): IntTrieSet = {
        if (p(i1)) {
            if (p(i2))
                this
            else
                IntTrieSet1(i1)
        } else {
            if (p(i2))
                IntTrieSet1(i2)
            else
                EmptyIntTrieSet
        }
    }
    override def withFilter(p: Int ⇒ Boolean): IntTrieSet = new FilteredIntTrieSet(this, p)
    override def map(f: Int ⇒ Int): IntTrieSet = {
        val i1 = this.i1
        val newI1 = f(i1)
        val i2 = this.i2
        val newI2 = f(i2)
        if (newI1 == newI2)
            IntTrieSet1(newI1)
        else if ((newI1 == i1 && newI2 == i2) || (newI1 == i2 && newI2 == i1))
            this
        else
            IntTrieSet.from(newI1, newI2)
    }
    override def map(map: Array[Int]): IntTrieSet = {
        val newI1 = map(this.i1)
        val newI2 = map(this.i2)
        if (newI1 == newI2)
            IntTrieSet1(newI1)
        else if ((newI1 == i1 && newI2 == i2) || (newI1 == i2 && newI2 == i1))
            this
        else
            IntTrieSet.from(newI1, newI2)
    }
    override def flatMap(f: Int ⇒ IntTrieSet): IntTrieSet = f(i1) ++ f(i2)

    override def -(i: Int): IntTrieSet = {
        if (i == i1) IntTrieSet1(i2)
        else if (i == i2) IntTrieSet1(i1)
        else this
    }
    override def +(i: Int): IntTrieSet = if (i1 == i | i2 == i) this else IntTrieSet.from(i1, i2, i)
    override def +!(i: Int): IntTrieSet = this + i
    override def intersect(other: IntTrieSet): IntTrieSet = {
        other.size match {
            case 0 ⇒ other
            case 1 ⇒ if (other.head == i1 || other.head == i2) other else EmptyIntTrieSet
            case _ ⇒
                if (other.contains(this.i1)) {
                    if (other.contains(this.i2)) {
                        this
                    } else {
                        IntTrieSet1(this.i1)
                    }
                } else if (other.contains(this.i2)) {
                    IntTrieSet1(this.i2)
                } else {
                    EmptyIntTrieSet
                }
        }
    }
    override def contains(value: Int): Boolean = value == i1 || value == i2
    override def exists(p: Int ⇒ Boolean): Boolean = p(i1) || p(i2)
    override def foldLeft[B](z: B)(f: (B, Int) ⇒ B): B = f(f(z, i1), i2)
    override def forall(f: Int ⇒ Boolean): Boolean = f(i1) && f(i2)

    override def toChain: Chain[Int] = i1 :&: i2 :&: Naught

    override private[immutable] def subsetOf(other: IntTrieSet, level: Int): Boolean = {
        other.size match {
            case 0 | 1 ⇒
                false
            case 2 ⇒
                other match {
                    case that: IntTrieSet2 ⇒
                        that.i1 == this.i1 && that.i2 == this.i2
                    case _ ⇒
                        // ... this case should never occur...
                        other.contains(i1, i1 >>> level) && other.contains(i2, i2 >>> level)
                }
            case _ ⇒
                other.contains(i1, i1 >>> level) && other.contains(i2, i2 >>> level)
        }
    }

    override def equals(other: IntTrieSet): Boolean = {
        (other eq this) || (
            other match {
                case that: IntTrieSet2 ⇒ this.i1 == that.i1 && this.i2 == that.i2
                case that              ⇒ that.size == 2 && that.contains(i1) && that.contains(i2)
            }
        )
    }

    override def hashCode: Int = 31 * (31 + i1) + i2 // compatible to Arrays.hashCode

    override private[immutable] def +(i: Int, level: Int): IntTrieSet = this.+(i)
    override private[immutable] def +!(i: Int, level: Int /* irrelevant */ ): IntTrieSet = this.+!(i)
}

/**
 * Represents an ordered set of three int values: i1 < i2 < i3.
 */
private[immutable] final class IntTrieSet3 private[immutable] (
        val i1: Int, val i2: Int, val i3: Int
) extends IntTrieSetL {

    override def isEmpty: Boolean = false
    override def isSingletonSet: Boolean = false
    override def hasMultipleElements: Boolean = true
    override def size: Int = 3
    override def headAndTail: IntRefPair[IntTrieSet] = {
        IntRefPair(i3, new IntTrieSet2(i1, i2))
    }
    override def head: Int = i3
    override def flatMap(f: Int ⇒ IntTrieSet): IntTrieSet = f(i1) ++ f(i2) ++ f(i3)
    override def iterator: IntIterator = IntIterator(i1, i2, i3)
    override def foreach[U](f: Int ⇒ U): Unit = { f(i1); f(i2); f(i3) }
    override def foreachPair[U](f: (Int, Int) ⇒ U): Unit = { f(i1, i2); f(i1, i3); f(i2, i3) }

    override def filter(p: Int ⇒ Boolean): IntTrieSet = {
        if (p(i1)) {
            if (p(i2)) {
                if (p(i3))
                    this
                else
                    new IntTrieSet2(i1, i2)
            } else {
                if (p(i3))
                    new IntTrieSet2(i1, i3)
                else
                    IntTrieSet1(i1)
            }
        } else {
            if (p(i2)) {
                if (p(i3))
                    new IntTrieSet2(i2, i3)
                else
                    IntTrieSet1(i2)
            } else {
                if (p(i3))
                    IntTrieSet1(i3)
                else
                    EmptyIntTrieSet
            }
        }
    }
    override def withFilter(p: Int ⇒ Boolean): IntTrieSet = new FilteredIntTrieSet(this, p)
    override def map(f: Int ⇒ Int): IntTrieSet = {
        val i1 = this.i1
        val newI1 = f(i1)
        val i2 = this.i2
        val newI2 = f(i2)
        val i3 = this.i3
        val newI3 = f(i3)
        if (newI1 != i1 || newI2 != i2 || newI3 != i3)
            IntTrieSet(newI1, newI2, newI3) // ensures invariant
        else
            this
    }
    override def map(map: Array[Int]): IntTrieSet = {
        val newI1 = map(i1)
        val newI2 = map(i2)
        val newI3 = map(i3)
        IntTrieSet(newI1, newI2, newI3)
    }
    override def -(i: Int): IntTrieSet = {
        if (i1 == i) new IntTrieSet2(i2, i3)
        else if (i2 == i) new IntTrieSet2(i1, i3)
        else if (i3 == i) new IntTrieSet2(i1, i2)
        else this
    }
    override def +(i: Int): IntTrieSet = this.+(i, 0)
    override def +!(i: Int): IntTrieSet = this.+(i, 0)
    override def contains(value: Int): Boolean = value == i1 || value == i2 || value == i3
    override def exists(p: Int ⇒ Boolean): Boolean = p(i1) || p(i2) || p(i3)
    override def foldLeft[B](z: B)(f: (B, Int) ⇒ B): B = f(f(f(z, i1), i2), i3)
    override def forall(f: Int ⇒ Boolean): Boolean = f(i1) && f(i2) && f(i3)
    override def toChain: Chain[Int] = i1 :&: i2 :&: i3 :&: Naught

    override private[immutable] def subsetOf(other: IntTrieSet, level: Int): Boolean = {
        other.size match {
            case 0 | 1 | 2 ⇒
                false
            case 3 ⇒
                other match {
                    case that: IntTrieSet3 ⇒
                        that.i1 == this.i1 && that.i2 == this.i2 && that.i3 == this.i3
                    case _ ⇒
                        // ... this case should never occur...
                        other.contains(i1, i1 >>> level) &&
                            other.contains(i2, i2 >>> level) &&
                            other.contains(i3, i3 >>> level)
                }
            case _ ⇒
                other.contains(i1, i1 >>> level) &&
                    other.contains(i2, i2 >>> level) &&
                    other.contains(i3, i3 >>> level)
        }
    }

    override def equals(other: IntTrieSet): Boolean = {
        (other eq this) || (
            other match {
                case that: IntTrieSet3 ⇒
                    this.i1 == that.i1 && this.i2 == that.i2 && this.i3 == that.i3
                case that ⇒
                    that.size == 3 && that.contains(i1) && that.contains(i2) && that.contains(i3)
            }
        )
    }

    override def hashCode: Int = 31 * (31 * (31 + i1) + i2) + i3 // compatible to Arrays.hashCode

    override private[immutable] def +(i: Int, level: Int): IntTrieSet = {
        if (i == i1 || i == i2 || i == i3)
            this
        else
            IntTrieSet.from(i, i1, i2, i3, level)
    }
    override private[immutable] def +!(i: Int, level: Int): IntTrieSet = this.+(i, level)
}

private[immutable] abstract class IntTrieSetNN extends IntTrieSet {

    final override def isSingletonSet: Boolean = size == 1
    final override def isEmpty: Boolean = false

    final override def map(f: Int ⇒ Int): IntTrieSet = {
        foldLeft(EmptyIntTrieSet: IntTrieSet)(_ +! f(_))
    }
    final override def map(map: Array[Int]): IntTrieSet = {
        foldLeft(EmptyIntTrieSet: IntTrieSet)(_ +! map(_))
    }

    final override def flatMap(f: Int ⇒ IntTrieSet): IntTrieSet = {
        foldLeft(EmptyIntTrieSet: IntTrieSet)(_ ++! f(_))
    }

    final override def withFilter(p: Int ⇒ Boolean): IntTrieSet = new FilteredIntTrieSet(this, p)

    final override def toChain: Chain[Int] = {
        val cb = new Chain.ChainBuilder[Int]()
        foreach((i: Int) ⇒ cb += i)
        cb.result()
    }

    final override def equals(that: IntTrieSet): Boolean = {
        (that eq this) || (that.size == this.size && {
            // IMPROVE Implement a comparison directly over the trie
            // we have stable orderings!
            val thisIt = this.iterator
            val otherIt = that.iterator
            var allEqual = true
            while (thisIt.hasNext && allEqual) {
                allEqual = thisIt.next() == otherIt.next()
            }
            allEqual
        })
    }

    final override def hashCode: Int = foldLeft(1)(31 * _ + _)
}

private[immutable] final class IntTrieSetN private[immutable] (
        private[immutable] var left:  IntTrieSet, // can be empty, but never null!
        private[immutable] var right: IntTrieSet, // can be empty, but never null!
        var size:                     Int
) extends IntTrieSetNN { intSet ⇒

    assert(left.size + right.size == size)
    assert(size > 0) // <= can be "one" at construction time

    override def hasMultipleElements: Boolean = size > 1
    override def exists(p: Int ⇒ Boolean): Boolean = left.exists(p) || right.exists(p)
    override def forall(p: Int ⇒ Boolean): Boolean = left.forall(p) && right.forall(p)

    override private[immutable] def subsetOf(other: IntTrieSet, level: Int): Boolean = {
        if (this.size > other.size)
            return false;

        other match {
            case that: IntTrieSetN ⇒
                this.right.size <= that.right.size && // check if we have a chance...
                    this.left.subsetOf(that.left, level + 1) &&
                    this.right.subsetOf(that.right, level + 1)
            case that: IntTrieSetNJustLeft ⇒
                this.right.isEmpty && this.left.subsetOf(that.left, level + 1)
            case that: IntTrieSetNJustRight ⇒
                this.left.isEmpty && this.right.subsetOf(that.right, level + 1)
            case that ⇒
                // Here, the level is actually not relevant...
                this.left.subsetOf(that, level + 1) && this.right.subsetOf(that, level + 1)
        }
    }

    override def foreach[U](f: Int ⇒ U): Unit = {
        left.foreach(f)
        right.foreach(f)
    }
    override def foreachPair[U](f: (Int, Int) ⇒ U): Unit = {
        val outerIt = iterator
        while (outerIt.hasNext) {
            val i = outerIt.next()
            val innerIt = iterator
            while (innerIt.hasNext) {
                val j = innerIt.next()
                if (i != j) f(i, j)
            }
        }
    }

    override def foldLeft[B](z: B)(f: (B, Int) ⇒ B): B = {
        right.foldLeft(left.foldLeft(z)(f))(f)
    }

    override private[immutable] def +(i: Int, level: Int): IntTrieSet = {
        if (((i >>> level) & 1) == 0) {
            val left = this.left
            val newLeft = left + (i, level + 1)
            if (newLeft eq left)
                this
            else
                IntTrieSetN(newLeft, right, size + 1)
        } else {
            val right = this.right
            val newRight = right + (i, level + 1)
            if (newRight eq right)
                this
            else
                IntTrieSetN(left, newRight, size + 1)
        }
    }

    override def +(i: Int): IntTrieSet = this.+(i, 0)

    override private[immutable] def +!(i: Int, level: Int): IntTrieSet = {
        if (((i >>> level) & 1) == 0) {
            val oldLeft = this.left
            val oldLeftSize = oldLeft.size
            val newLeft = oldLeft +! (i, level + 1)
            if (newLeft.size != oldLeftSize) {
                this.left = newLeft
                this.size += 1
            }
        } else {
            val oldRight = this.right
            val oldRightSize = oldRight.size
            val newRight = oldRight +! (i, level + 1)
            if (newRight.size != oldRightSize) {
                this.right = newRight
                this.size += 1
            }
        }
        this
    }

    override def +!(i: Int): IntTrieSet = this.+!(i, 0)

    override private[immutable] def contains(value: Int, key: Int): Boolean = {
        if ((key & 1) == 0)
            left.contains(value, key >>> 1)
        else
            right.contains(value, key >>> 1)
    }

    override def contains(value: Int): Boolean = this.contains(value, value)

    /**
     * Ensures that subtrees which contain less than 3 elements are represented using
     * a cannonical representation.
     */
    override private[immutable] def constringe(): IntTrieSet = {
        assert(size <= 2)
        if (left.isEmpty)
            right.constringe()
        else if (right.isEmpty)
            left.constringe()
        else
            new IntTrieSet2(left.head, right.head)
    }

    private[immutable] def -(i: Int, key: Int): IntTrieSet = {
        if ((key & 1) == 0) {
            val left = this.left
            val newLeft = left.-(i, key >>> 1)
            if (newLeft eq left)
                this
            else {
                (size - 1) match {
                    case 0 ⇒
                        EmptyIntTrieSet
                    case 1 ⇒
                        if (newLeft.isEmpty)
                            right.constringe()
                        else
                            newLeft.constringe()
                    case newSize ⇒
                        IntTrieSetN(newLeft, right, newSize)
                }
            }
        } else {
            val right = this.right
            val newRight = right.-(i, key >>> 1)
            if (newRight eq right)
                this
            else {
                val newSize = size - 1
                if (newSize == 0)
                    EmptyIntTrieSet
                else if (newSize == 1) {
                    if (newRight.isEmpty)
                        left.constringe()
                    else
                        newRight.constringe()
                } else {
                    IntTrieSetN(left, newRight, newSize)
                }
            }
        }
    }

    def -(i: Int): IntTrieSet = this.-(i, i)

    override def iterator: IntIterator = new IntIterator {
        private[this] var it: IntIterator = left.iterator
        private[this] var isRightIterator: Boolean = false
        private[this] def advanceIterator(): Unit = {
            if (!it.hasNext && !isRightIterator) {
                isRightIterator = true
                it = right.iterator
            }
        }
        advanceIterator()
        def hasNext: Boolean = it.hasNext
        def next(): Int = { val v = it.next(); advanceIterator(); v }
    }

    override def head: Int = {
        val left = this.left
        val right = this.right
        val leftSize = left.size
        val rightSize = right.size
        if (leftSize > rightSize)
            left.head
        else
            right.head
    }

    override def headAndTail: IntRefPair[IntTrieSet] = {
        // try to reduce the tree size by removing an element from the
        // bigger subtree
        val left = this.left
        val right = this.right
        val leftSize = left.size
        val rightSize = right.size
        if (leftSize > rightSize) {
            // => left has at least one element
            if (leftSize == 1) { // => right is empty!
                IntRefPair(left.head, EmptyIntTrieSet)
            } else {
                val IntRefPair(v, newLeft) = left.headAndTail
                val theNewLeft = if (leftSize == 2) newLeft.constringe() else newLeft
                IntRefPair(v, IntTrieSetN(theNewLeft, right, leftSize - 1 + rightSize))
            }
        } else {
            // ...leftSize <= right.size
            assert(right.nonEmpty)
            if (right.isSingletonSet) {
                // left.size \in {0,1}
                IntRefPair(right.head, left.constringe())
            } else {
                val IntRefPair(v, newRight) = right.headAndTail
                val theNewRight = if (rightSize == 2) newRight.constringe() else newRight
                IntRefPair(v, IntTrieSetN(left, theNewRight, size - 1))
            }
        }
    }

    override def filter(p: Int ⇒ Boolean): IntTrieSet = {
        val left = this.left
        val right = this.right
        var newLeft = left.filter(p)
        var newRight = right.filter(p)
        if ((newLeft eq left) && (newRight eq right))
            return this;

        val newLeftSize = newLeft.size
        val newRightSize = newRight.size

        if (newLeftSize + newRightSize <= 2) {
            val newSet =
                if (newLeft.isEmpty) newRight
                else if (newRight.isEmpty) newLeft
                else newLeft + newRight.head
            return newSet;
        }

        if (newLeftSize <= 2) {
            newLeft = newLeft.constringe()
        }
        if (newRightSize <= 2) {
            newRight = newRight.constringe()
        }
        IntTrieSetN(newLeft, newRight, newLeftSize + newRightSize)
    }

}

private[immutable] object IntTrieSetN {

    def apply(
        left:  IntTrieSet, // can be empty, but never null!
        right: IntTrieSet, // can be empty, but never null!
        size:  Int
    ): IntTrieSet = {
        if (right.isEmpty)
            new IntTrieSetNJustLeft(left)
        else if (left.isEmpty)
            new IntTrieSetNJustRight(right)
        else
            new IntTrieSetN(left, right, size)
    }
}

private[immutable] final class IntTrieSetNJustRight private[immutable] (
        private[immutable] var right: IntTrieSet // can't be empty, left is already empty
) extends IntTrieSetNN { intSet ⇒

    assert(size > 0) // <= can be "one" at construction time

    override def hasMultipleElements: Boolean = right.hasMultipleElements
    override def size: Int = right.size
    override def head: Int = right.head
    override def exists(p: Int ⇒ Boolean): Boolean = right.exists(p)
    override def forall(p: Int ⇒ Boolean): Boolean = right.forall(p)
    override def foreach[U](f: Int ⇒ U): Unit = right.foreach(f)
    override def foreachPair[U](f: (Int, Int) ⇒ U): Unit = right.foreachPair(f)
    override def foldLeft[B](z: B)(f: (B, Int) ⇒ B): B = right.foldLeft(z)(f)

    override private[immutable] def +(i: Int, level: Int): IntTrieSet = {
        if (((i >>> level) & 1) == 0) {
            IntTrieSetN(IntTrieSet1(i), right, size + 1)
        } else {
            val right = this.right
            val newRight = right + (i, level + 1)
            if (newRight eq right)
                this
            else
                new IntTrieSetNJustRight(newRight)
        }
    }

    override private[immutable] def +!(i: Int, level: Int): IntTrieSet = {
        if (((i >>> level) & 1) == 0) {
            IntTrieSetN(IntTrieSet1(i), right, size + 1)
        } else {
            this.right = this.right +! (i, level + 1)
            this
        }
    }

    override def +(i: Int): IntTrieSet = this.+(i, 0)
    override def +!(i: Int): IntTrieSet = this.+!(i, 0)

    override private[immutable] def subsetOf(other: IntTrieSet, level: Int): Boolean = {
        if (this.size > other.size)
            return false;

        other match {
            case that: IntTrieSetN          ⇒ this.right.subsetOf(that.right, level + 1)
            case that: IntTrieSetNJustLeft  ⇒ false
            case that: IntTrieSetNJustRight ⇒ this.right.subsetOf(that.right, level + 1)
            case that                       ⇒ this.right.subsetOf(that, level + 1)
        }
    }

    override private[immutable] def contains(value: Int, key: Int): Boolean = {
        if ((key & 1) == 0)
            false
        else
            right.contains(value, key >>> 1)
    }

    override def contains(value: Int): Boolean = this.contains(value, value)

    /**
     * Ensures that subtrees which contain less than 3 elements are represented using
     * a cannonical representation.
     */
    override private[immutable] def constringe(): IntTrieSet = {
        assert(size <= 2)
        right.constringe()
    }

    private[immutable] def -(i: Int, key: Int): IntTrieSet = {
        if ((key & 1) == 0) {
            this
        } else {
            val right = this.right
            val newRight = right.-(i, key >>> 1)
            if (newRight eq right)
                this
            else {
                val newSize = size - 1
                if (newSize == 0)
                    EmptyIntTrieSet
                else if (newSize == 1) {
                    newRight.constringe()
                } else {
                    new IntTrieSetNJustRight(newRight)
                }
            }
        }
    }

    def -(i: Int): IntTrieSet = this.-(i, i)

    def iterator: IntIterator = right.iterator

    override def headAndTail: IntRefPair[IntTrieSet] = {
        // try to reduce the tree size by removing an element from the
        // bigger subtree
        val right = this.right
        val rightSize = right.size
        if (right.isSingletonSet) {
            IntRefPair(right.head, EmptyIntTrieSet)
        } else {
            val IntRefPair(v, newRight) = right.headAndTail
            val theNewRight = if (rightSize == 2) newRight.constringe() else newRight
            IntRefPair(v, new IntTrieSetNJustRight(theNewRight))
        }

    }

    override def filter(p: Int ⇒ Boolean): IntTrieSet = {
        val right = this.right
        val newRight = right.filter(p)
        if (newRight eq right)
            return this;

        val newRightSize = newRight.size
        if (newRightSize <= 2) {
            newRight.constringe()
        } else {
            new IntTrieSetNJustRight(newRight)
        }
    }

}

private[immutable] final class IntTrieSetNJustLeft private[immutable] (
        private[immutable] var left: IntTrieSet // cannot be empty; right is empty
) extends IntTrieSetNN { intSet ⇒

    assert(size > 0) // <= can be "one" at construction time

    override def size: Int = left.size
    override def hasMultipleElements: Boolean = left.hasMultipleElements
    override def head: Int = left.head
    override def exists(p: Int ⇒ Boolean): Boolean = left.exists(p)
    override def forall(p: Int ⇒ Boolean): Boolean = left.forall(p)
    override def foreach[U](f: Int ⇒ U): Unit = left.foreach(f)
    override def foreachPair[U](f: (Int, Int) ⇒ U): Unit = left.foreachPair(f)
    override def foldLeft[B](z: B)(f: (B, Int) ⇒ B): B = left.foldLeft(z)(f)

    override private[immutable] def +(i: Int, level: Int): IntTrieSet = {
        if (((i >>> level) & 1) == 0) {
            val left = this.left
            val newLeft = left + (i, level + 1)
            if (newLeft eq left)
                this
            else
                new IntTrieSetNJustLeft(newLeft)
        } else {
            new IntTrieSetN(left, IntTrieSet1(i), size + 1)
        }
    }

    override private[immutable] def +!(i: Int, level: Int): IntTrieSet = {
        if (((i >>> level) & 1) == 0) {
            this.left = this.left +! (i, level + 1)
            this
        } else {
            new IntTrieSetN(left, IntTrieSet1(i), size + 1)
        }
    }

    override def +(i: Int): IntTrieSet = this.+(i, 0)
    override def +!(i: Int): IntTrieSet = this.+!(i, 0)

    override def subsetOf(other: IntTrieSet, level: Int): Boolean = {
        if (this.size > other.size)
            return false;

        other match {
            case that: IntTrieSetN          ⇒ this.left.subsetOf(that.left, level + 1)
            case that: IntTrieSetNJustLeft  ⇒ this.left.subsetOf(that.left, level + 1)
            case that: IntTrieSetNJustRight ⇒ false
            case that                       ⇒ this.left.subsetOf(that, level + 1)
        }
    }

    override private[immutable] def contains(value: Int, key: Int): Boolean = {
        if ((key & 1) == 0)
            left.contains(value, key >>> 1)
        else
            false
    }

    override def contains(value: Int): Boolean = this.contains(value, value)

    /**
     * Ensures that subtrees which contain less than 3 elements are represented using
     * a cannonical representation.
     */
    override private[immutable] def constringe(): IntTrieSet = {
        assert(size <= 2)
        left.constringe()
    }

    private[immutable] def -(i: Int, key: Int): IntTrieSet = {
        if ((key & 1) == 0) {
            val left = this.left
            val newLeft = left.-(i, key >>> 1)
            if (newLeft eq left)
                this
            else {
                val newSize = size - 1
                newSize match {
                    case 0 ⇒
                        EmptyIntTrieSet
                    case 1 ⇒
                        newLeft.constringe()
                    case _ ⇒
                        new IntTrieSetNJustLeft(newLeft)
                }
            }
        } else {
            this
        }
    }

    def -(i: Int): IntTrieSet = this.-(i, i)

    def iterator: IntIterator = left.iterator

    override def headAndTail: IntRefPair[IntTrieSet] = {
        // try to reduce the tree size by removing an element from the
        // bigger subtree
        val left = this.left
        val leftSize = left.size
        if (leftSize == 1) { // => right is empty!
            IntRefPair(left.head, EmptyIntTrieSet)
        } else {
            val IntRefPair(v, newLeft) = left.headAndTail
            val theNewLeft = if (leftSize == 2) newLeft.constringe() else newLeft
            IntRefPair(v, new IntTrieSetNJustLeft(theNewLeft))
        }

    }

    override def filter(p: Int ⇒ Boolean): IntTrieSet = {
        val left = this.left
        val newLeft = left.filter(p)
        if (newLeft eq left)
            return this;

        val newLeftSize = newLeft.size
        if (newLeftSize <= 2) {
            newLeft.constringe()
        } else {
            new IntTrieSetNJustLeft(newLeft)
        }
    }

}

class IntTrieSetBuilder extends scala.collection.mutable.Builder[Int, IntTrieSet] {
    private[this] var s: IntTrieSet = EmptyIntTrieSet
    def +=(i: Int): this.type = { s +!= i; this }
    def clear(): Unit = s = EmptyIntTrieSet
    def result(): IntTrieSet = s
}

/**
 * Factory to create IntTrieSets.
 */
object IntTrieSet {

    def empty: IntTrieSet = EmptyIntTrieSet

    def apply(i1: Int): IntTrieSet = IntTrieSet1(i1)

    def apply(i1: Int, i2: Int): IntTrieSet = {
        if (i1 == i2)
            IntTrieSet1(i1)
        else {
            from(i1, i2)
        }
    }

    /** Constructs a new IntTrie from the two distinct(!) values. */
    def from(i1: Int, i2: Int): IntTrieSet = {
        assert(i1 != i2)
        // we have to ensure the same ordering as used when the values are
        // stored in the trie
        if ((Integer.lowestOneBit(i1 ^ i2) & i1) == 0) {
            // ... i2 is the value with a 0 at the bit position where both values differ
            new IntTrieSet2(i1, i2)
        } else {
            new IntTrieSet2(i2, i1)
        }
    }

    def apply(i1: Int, i2: Int, i3: Int): IntTrieSet = {
        if (i1 == i2)
            IntTrieSet(i1, i3) // this also handles the case i1 == i3
        else if (i1 == i3 || i2 == i3) { // we have i1 =!= i2
            IntTrieSet.from(i1, i2)
        } else { // i1 =!= i2 && i2 =!= i3 && i1 =!= i3
            IntTrieSet.from(i1, i2, i3)
        }
    }

    /** Constructs a new IntTrie from the three distinct(!) values! */
    def from(i1: Int, i2: Int, i3: Int): IntTrieSet = {
        // We have to ensure the same ordering as used when the values are stored in the trie...
        var v1, v2, v3 = 0
        if ((Integer.lowestOneBit(i1 ^ i2) & i1) == 0) {
            // ... i1 is the value with a 0 at the lowest one bit position...
            v1 = i1
            v2 = i2
        } else {
            v1 = i2
            v2 = i1
        }

        if ((Integer.lowestOneBit(v2 ^ i3) & v2) == 0) {
            // v2 is the value with the 0 and the distinguishing position...
            v3 = i3
        } else {
            v3 = v2
            if ((Integer.lowestOneBit(v1 ^ i3) & v1) == 0) {
                v2 = i3
            } else {
                v2 = v1
                v1 = i3
            }
        }

        new IntTrieSet3(v1, v2, v3)
    }

    def apply(i1: Int, i2: Int, i3: Int, i4: Int): IntTrieSet = {
        if (i1 == i2) {
            IntTrieSet(i2, i3, i4)
        } else if (i1 == i3 || i2 == i3 || i3 == i4) { // we have i1 =!= i2
            IntTrieSet(i1, i2, i4)
        } else if (i1 == i4 || i2 == i4) {
            IntTrieSet(i1, i2, i3)
        } else {
            IntTrieSet.from(i1, i2, i3, i4, 0)
        }
    }

    def from(i1: Int, i2: Int, i3: Int, i4: Int): IntTrieSet = {
        if ((i1 & 1) == 0) {
            if ((i2 & 1) == 0) {
                if ((i3 & 1) == 0) {
                    if ((i4 & 1) == 0) { // first bit of all "0"
                        new IntTrieSetNJustLeft(from(i1, i2, i3, i4, 1))
                    } else { // first bit of i4 is "1"
                        new IntTrieSetN(IntTrieSet.from(i1, i2, i3), IntTrieSet1(i4), 4)
                    }
                } else {
                    if ((i4 & 1) == 0) { // first bit of i3 is "1"
                        new IntTrieSetN(IntTrieSet.from(i1, i2, i4), IntTrieSet1(i3), 4)
                    } else { // first bit of i3, i4 is "1"
                        new IntTrieSetN(IntTrieSet.from(i1, i2), IntTrieSet.from(i3, i4), 4)
                    }
                }
            } else {
                if ((i3 & 1) == 0) {
                    if ((i4 & 1) == 0) { // first bit of i2 is "1"
                        new IntTrieSetN(IntTrieSet.from(i1, i3, i4), IntTrieSet1(i2), 4)
                    } else { // first bit of i2 and i4 is "1"
                        new IntTrieSetN(IntTrieSet.from(i1, i3), IntTrieSet.from(i2, i4), 4)
                    }
                } else {
                    if ((i4 & 1) == 0) { // first bit of i2, i3 is "1"
                        new IntTrieSetN(IntTrieSet.from(i1, i4), IntTrieSet.from(i2, i3), 4)
                    } else { // first bit of i2, i3, i4 is "1"
                        new IntTrieSetN(IntTrieSet1(i1), IntTrieSet.from(i2, i3, i4), 4)
                    }
                }
            }
        } else {
            if ((i2 & 1) == 0) {
                if ((i3 & 1) == 0) {
                    if ((i4 & 1) == 0) { // first bit of i1 is "1"
                        new IntTrieSetN(IntTrieSet.from(i2, i3, i4), IntTrieSet1(i1), 4)
                    } else { // first bit of i1, i4 is "1"
                        new IntTrieSetN(IntTrieSet.from(i2, i3), IntTrieSet.from(i1, i4), 4)
                    }
                } else {
                    if ((i4 & 1) == 0) { // first bit of i1, i3 is "1"
                        new IntTrieSetN(IntTrieSet.from(i2, i4), IntTrieSet.from(i1, i3), 4)
                    } else { // first bit of i1, i3, i4 is "1"
                        new IntTrieSetN(IntTrieSet1(i2), IntTrieSet.from(i1, i3, i4), 4)
                    }
                }
            } else {
                if ((i3 & 1) == 0) {
                    if ((i4 & 1) == 0) { // first bit of i1, i2 is "1"
                        new IntTrieSetN(IntTrieSet.from(i3, i4), IntTrieSet.from(i1, i2), 4)
                    } else { // first bit of i1, i2 and i4 is "1"
                        new IntTrieSetN(IntTrieSet1(i3), IntTrieSet.from(i1, i2, i4), 4)
                    }
                } else {
                    if ((i4 & 1) == 0) { // first bit of i1, i2, i3 is "1"
                        new IntTrieSetN(IntTrieSet1(i4), IntTrieSet.from(i1, i2, i3), 4)
                    } else { // first bit of i1, i2, i3, i4 is "1"
                        new IntTrieSetNJustRight(from(i1, i2, i3, i4, 1))
                    }
                }
            }
        }
    }

    /**
     * Constructs a new `IntTrieSet` from the given distinct values.
     *
     * If level is > 0 then all values have to have the same least significant bits up until level!
     */
    private[immutable] def from(i1: Int, i2: Int, i3: Int, i4: Int, level: Int): IntTrieSet = {
        val root =
            if (((i1 >>> level) & 1) == 0)
                new IntTrieSetNJustLeft(IntTrieSet1(i1))
            else
                new IntTrieSetNJustRight(IntTrieSet1(i1))

        root +! (i2, level) +! (i3, level) +! (i4, level)
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy