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

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

The newest version!
/* BSD 2-Clause License - see OPAL/LICENSE for details. */

package org.opalj.collection
package immutable

import org.opalj.collection.mutable.RefArrayStack

/**
 * A set of objects of type UID. This set is defined over the ids of the objects and
 * NOT over the objects themselves. I.e., at any given time no two different objects
 * which have the same id, will be found in the set (provided that the ids are not changed
 * after adding the object to this set, which is a pre-requisite.)
 *
 * @note Though `equals` and `hashCode` are implemented, comparing UID trie sets
 *       is still not efficient (n * log n) because the structure of the trie
 *       depends on the insertion order.
 */
sealed abstract class UIDTrieSet[T <: UID] { set ⇒

    def isEmpty: Boolean
    def nonEmpty: Boolean
    def isSingletonSet: Boolean
    def size: Int
    /**
     * Tests if this set contains a value with the same id as the given value.
     * I.e., no comparison of the values is done, but only the underlying ids
     * are compared.
     */
    final def contains(value: T): Boolean = containsId(value.id)
    def containsId(id: Int): Boolean
    def foreach[U](f: T ⇒ U): Unit
    def forall(p: T ⇒ Boolean): Boolean
    def exists(p: T ⇒ Boolean): Boolean
    def foldLeft[B](z: B)(op: (B, T) ⇒ B): B
    final def foreachIterator: ForeachRefIterator[T] = new ForeachRefIterator[T] {
        override def foreach[U](f: T ⇒ U): Unit = set.foreach(f)
    }
    def iterator: RefIterator[T]
    def +(value: T): UIDTrieSet[T]
    def head: T

    // TODO: optimize implementation
    def ++(other: UIDTrieSet[T]): UIDTrieSet[T] = other.foldLeft(this)((r, e) ⇒ r + e)

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

    def equals(other: UIDTrieSet[_]): Boolean
}

/**
 * Factory methods for creating UIDTrieSets.
 */
object UIDTrieSet {

    def empty[T <: UID]: UIDTrieSet[T] = {
        UIDTrieSet0.asInstanceOf[UIDTrieSet[T]]
    }

    def apply[T <: UID](value: T): UIDTrieSet[T] = {
        new UIDTrieSet1(value)
    }

    def apply[T <: UID](value1: T, value2: T): UIDTrieSet[T] = {
        if (value1.id == value2.id)
            new UIDTrieSet1(value1)
        else
            new UIDTrieSet2(value1, value2)
    }
}

/**
 * The common superclass of the nodes of the trie.
 */
private[immutable] sealed trait UIDTrieSetNode[T <: UID] {

    def foreach[U](f: T ⇒ U): Unit
    def foldLeft[B](z: B)(op: (B, T) ⇒ B): B
    def forall(p: T ⇒ Boolean): Boolean
    def exists(p: T ⇒ Boolean): Boolean
    def head: T

    //
    // IMPLEMENTATION "INTERNAL" METHODS
    //
    // Adds the value with the id to the trie at the specified level where `key is id >> level`.
    private[immutable] def +(value: T, id: Int, key: Int, level: Int): UIDTrieSetNode[T]
    private[immutable] def containsId(id: Int, key: Int): Boolean
    private[immutable] def toString(indent: Int): String
}

/**
 * The common superclass of the leafs of the trie.
 */
private[immutable] sealed abstract class UIDTrieSetLeaf[T <: UID]
    extends UIDTrieSet[T]
    with UIDTrieSetNode[T] {

    final override private[immutable] def containsId(id: Int, key: Int): Boolean = {
        this.containsId(id)
    }

    final override private[immutable] def toString(indent: Int): String = {
        (" " * indent) + toString()
    }

}

case object UIDTrieSet0 extends UIDTrieSetLeaf[UID] {
    override def isSingletonSet: Boolean = false
    override def isEmpty: Boolean = true
    override def nonEmpty: Boolean = false
    override def size: Int = 0
    override def foreach[U](f: UID ⇒ U): Unit = {}
    override def forall(p: UID ⇒ Boolean): Boolean = true
    override def exists(p: UID ⇒ Boolean): Boolean = false
    override def foldLeft[B](z: B)(op: (B, UID) ⇒ B): B = z
    override def +(i: UID): UIDTrieSet1[UID] = new UIDTrieSet1(i)
    override def iterator: RefIterator[UID] = RefIterator.empty
    override def containsId(id: Int): Boolean = false
    override def head: UID = throw new NoSuchElementException

    override def equals(other: UIDTrieSet[_]): Boolean = other eq this
    override def hashCode: Int = 0
    override def toString: String = "UIDTrieSet()"

    override private[immutable] def +(
        value: UID,
        id:    Int,
        key:   Int,
        level: Int
    ): UIDTrieSetNode[UID] = {
        this + value
    }
}

final class UIDTrieSet1[T <: UID](val i: T) extends UIDTrieSetLeaf[T] {
    override def isEmpty: Boolean = false
    override def nonEmpty: Boolean = true
    override def isSingletonSet: Boolean = true
    override def size: Int = 1
    override def foreach[U](f: T ⇒ U): Unit = { f(i) }
    override def forall(p: T ⇒ Boolean): Boolean = p(i)
    override def exists(p: T ⇒ Boolean): Boolean = p(i)
    override def foldLeft[B](z: B)(op: (B, T) ⇒ B): B = op(z, i)
    override def +(value: T): UIDTrieSetLeaf[T] = {
        val v = this.i
        if (v.id == value.id) this else new UIDTrieSet2(v, value)
    }
    override def iterator: RefIterator[T] = RefIterator(i)
    override def containsId(id: Int): Boolean = id == i.id
    override def head: T = i

    override def equals(other: UIDTrieSet[_]): Boolean = {
        (other eq this) || (other match {
            case that: UIDTrieSet1[_] ⇒ this.i.id == that.i.id
            case that                 ⇒ false
        })
    }

    override def hashCode: Int = i.id

    override def toString: String = s"UIDTrieSet($i)"

    override private[immutable] def +(
        value: T,
        id:    Int,
        key:   Int,
        level: Int
    ): UIDTrieSetNode[T] = {
        this + value
    }
}

/**
 * Represents an ordered set of two values where i1 has to be smaller than i2.
 */
private[immutable] final class UIDTrieSet2[T <: UID] private[immutable] (
        val i1: T, val i2: T
) extends UIDTrieSetLeaf[T] {

    override def isEmpty: Boolean = false
    override def nonEmpty: Boolean = true
    override def isSingletonSet: Boolean = false
    override def size: Int = 2
    override def iterator: RefIterator[T] = RefIterator(i1, i2)
    override def foreach[U](f: T ⇒ U): Unit = { f(i1); f(i2) }
    override def forall(p: T ⇒ Boolean): Boolean = { p(i1) && p(i2) }
    override def exists(p: T ⇒ Boolean): Boolean = { p(i1) || p(i2) }
    override def foldLeft[B](z: B)(op: (B, T) ⇒ B): B = op(op(z, i1), i2)
    override def containsId(id: Int): Boolean = id == i1.id || id == i2.id
    override def head: T = i1
    override def +(value: T): UIDTrieSetLeaf[T] = {
        val id = value.id

        val i1 = this.i1
        if (i1.id == id) {
            return this;
        }

        val i2 = this.i2
        if (i2.id == id) {
            this
        } else {
            new UIDTrieSet3(i1, i2, value)
        }
    }

    override def equals(other: UIDTrieSet[_]): Boolean = {
        (other eq this) || (
            other match {
                case that: UIDTrieSet2[_] ⇒
                    (this.i1.id == that.i1.id && this.i2.id == that.i2.id) ||
                        (this.i1.id == that.i2.id && this.i2.id == that.i1.id)
                case that ⇒
                    false
            }
        )
    }

    override def hashCode: Int = i1.id ^ i2.id // ordering independent

    override def toString: String = s"UIDTrieSet($i1, $i2)"

    override private[immutable] def +(
        value: T,
        id:    Int,
        key:   Int,
        level: Int
    ): UIDTrieSetNode[T] = {
        this + value
    }

}

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

    override def size: Int = 3
    override def isEmpty: Boolean = false
    override def nonEmpty: Boolean = true
    override def isSingletonSet: Boolean = false
    override def containsId(id: Int): Boolean = id == i1.id || id == i2.id || id == i3.id
    override def head: T = i1
    override def iterator: RefIterator[T] = RefIterator(i1, i2, i3)
    override def foreach[U](f: T ⇒ U): Unit = { f(i1); f(i2); f(i3) }
    override def forall(p: T ⇒ Boolean): Boolean = { p(i1) && p(i2) && p(i3) }
    override def exists(p: T ⇒ Boolean): Boolean = { p(i1) || p(i2) || p(i3) }
    override def foldLeft[B](z: B)(op: (B, T) ⇒ B): B = op(op(op(z, i1), i2), i3)

    override def +(value: T): UIDTrieSet[T] = {
        val id = value.id
        val newSet = this + (value, id, id, 0)
        if (newSet ne this)
            new UIDTrieSetN(4, newSet)
        else
            this
    }

    override def equals(other: UIDTrieSet[_]): Boolean = {
        (other eq this) || (
            other match {
                case that: UIDTrieSet3[_] ⇒
                    that.containsId(this.i1.id) &&
                        that.containsId(this.i2.id) &&
                        that.containsId(this.i3.id)
                case that ⇒
                    false
            }
        )
    }

    override def hashCode: Int = i1.id ^ i2.id ^ i3.id // ordering independent

    override def toString: String = s"UIDTrieSet($i1, $i2, $i3)"

    override private[immutable] def +(
        value: T,
        id:    Int,
        key:   Int,
        level: Int
    ): UIDTrieSetNode[T] = {
        val i1 = this.i1
        val i1Id = i1.id
        if (id == i1Id)
            return this;

        val i2 = this.i2
        val i2Id = i2.id
        if (id == i2Id)
            return this;

        val i3 = this.i3
        val i3Id = i3.id
        if (id == i3Id)
            return this;

        if ((key & 1) == 0) {
            if ((i1Id >> level & 1) == 0) {
                if ((i2Id >> level & 1) == 0) {
                    if ((i3Id >> level & 1) == 0) {
                        new UIDTrieSetNode_0(value, this)
                    } else {
                        new UIDTrieSetNode_0(
                            i3,
                            new UIDTrieSet3(value, i1, i2)
                        )
                    }
                } else {
                    if ((i3Id >> level & 1) == 0) {
                        new UIDTrieSetNode_0(
                            i2,
                            new UIDTrieSet3(value, i1, i3)
                        )
                    } else {
                        new UIDTrieSetNode_0_1(
                            value,
                            new UIDTrieSet1(i1),
                            new UIDTrieSet2(i2, i3)
                        )
                    }
                }
            } else {
                // value >  _0, i1 =>  _1, ...
                if ((i2Id >> level & 1) == 0) {
                    if ((i3Id >> level & 1) == 0) {
                        new UIDTrieSetNode_0(
                            i1,
                            new UIDTrieSet3(value, i2, i3)
                        )
                    } else {
                        // value >  _0, i1 =>  _1, i2 => _ 0, i3 => _1
                        new UIDTrieSetNode_0_1(
                            value,
                            new UIDTrieSet1(i2),
                            new UIDTrieSet2(i1, i3)
                        )
                    }
                } else {
                    // value >  _0, i1 =>  _1, i2 => _ 1, ...
                    if ((i3Id >> level & 1) == 0) {
                        new UIDTrieSetNode_0_1(
                            value,
                            new UIDTrieSet1(i3),
                            new UIDTrieSet2(i1, i2)
                        )
                    } else {
                        new UIDTrieSetNode_1(value, this)
                    }
                }
            }
        } else {
            // value =>  _1,  ...
            if ((i1Id >> level & 1) == 0) {
                if ((i2Id >> level & 1) == 0) {
                    if ((i3Id >> level & 1) == 0) {
                        new UIDTrieSetNode_0(value, this)
                    } else {
                        new UIDTrieSetNode_0_1(
                            value,
                            new UIDTrieSet2(i1, i2),
                            new UIDTrieSet1(i3)
                        )
                    }
                } else {
                    // value =>  _1, i1 => 0,  i2 => _1
                    if ((i3Id >> level & 1) == 0) {
                        new UIDTrieSetNode_0_1(
                            value,
                            new UIDTrieSet2(i1, i3),
                            new UIDTrieSet1(i2)
                        )
                    } else {
                        new UIDTrieSetNode_1(
                            i1,
                            new UIDTrieSet3(value, i2, i3)
                        )
                    }
                }
            } else {
                // value =>  _1, i1 =>  _1, ...
                if ((i2Id >> level & 1) == 0) {
                    if ((i3Id >> level & 1) == 0) {
                        new UIDTrieSetNode_0_1(
                            value,
                            new UIDTrieSet2(i2, i3),
                            new UIDTrieSet1(i1)
                        )
                    } else {
                        // value =>  _1, i1 =>  _1, i2 => _ 0, i3 => _1
                        new UIDTrieSetNode_1(
                            i2,
                            new UIDTrieSet3(value, i1, i3)
                        )
                    }
                } else {
                    // value =>  _1, i1 =>  _1, i2 => _ 1, ...
                    if ((i3Id >> level & 1) == 0) {
                        new UIDTrieSetNode_1(
                            i3,
                            new UIDTrieSet3(value, i1, i2)
                        )
                    } else {
                        new UIDTrieSetNode_1(value, this)
                    }
                }
            }
        }
    }
}

/**
 * A UIDTrieSet with four or more values.
 */
private[immutable] final class UIDTrieSetN[T <: UID](
        val size: Int,
        root:     UIDTrieSetNode[T]
) extends UIDTrieSet[T] {

    // assert(size >= 4)

    override def isEmpty: Boolean = false
    override def nonEmpty: Boolean = true
    override def isSingletonSet: Boolean = false
    override def containsId(id: Int): Boolean = root.containsId(id, id)
    override def head: T = root.head
    override def foreach[U](f: T ⇒ U): Unit = root.foreach(f)
    override def forall(p: T ⇒ Boolean): Boolean = root.forall(p)
    override def exists(p: T ⇒ Boolean): Boolean = root.exists(p)
    override def foldLeft[B](z: B)(op: (B, T) ⇒ B): B = root.foldLeft(z)(op)

    override def iterator: RefIterator[T] = new RefIterator[T] {
        private[this] var currentNode = root
        private[this] var index = 0
        private[this] val furtherNodes = RefArrayStack.empty[UIDTrieSetNode[T]]
        def hasNext: Boolean = currentNode ne null
        def next: T = {
            (this.currentNode: @unchecked) match {
                case n: UIDTrieSet1[T] ⇒
                    this.currentNode = if (furtherNodes.nonEmpty) furtherNodes.pop() else null
                    n.i
                case n: UIDTrieSet2[T] ⇒
                    if (index == 0) {
                        index = 1
                        n.i1
                    } else {
                        this.currentNode = if (furtherNodes.nonEmpty) furtherNodes.pop() else null
                        index = 0
                        n.i2
                    }
                case n: UIDTrieSet3[T] ⇒
                    if (index == 0) {
                        index = 1
                        n.i1
                    } else if (index == 1) {
                        index = 2
                        n.i2
                    } else {
                        this.currentNode = if (furtherNodes.nonEmpty) furtherNodes.pop() else null
                        index = 0
                        n.i3
                    }
                case n: UIDTrieSetNode_0[T] ⇒
                    currentNode = n._0
                    n.v
                case n: UIDTrieSetNode_1[T] ⇒
                    currentNode = n._1
                    n.v
                case n: UIDTrieSetNode_0_1[T] ⇒
                    currentNode = n._0
                    furtherNodes.push(n._1)
                    n.v
            }
        }
    }

    override def equals(that: UIDTrieSet[_]): Boolean = {
        (that eq this) ||
            // recall that the shape of the trie depends on the insertion order
            // (but doesn't reflect the order)
            (that.size == this.size && this.forall(uid ⇒ that.containsId(uid.id)))
    }

    override def hashCode: Int = root.hashCode * size

    override def +(value: T): UIDTrieSet[T] = {
        val id = value.id
        val root = this.root
        val newRoot = root + (value, id, id, 0)
        if (newRoot ne root) {
            new UIDTrieSetN(size + 1, newRoot)
        } else {
            this
        }
    }

    override def toString: String = s"UIDTrieSet(#$size, ${root.toString(1)})"

}

private[immutable] final class UIDTrieSetNode_0_1[T <: UID](
        val v:  T, // value with the current prefix...
        val _0: UIDTrieSetNode[T],
        val _1: UIDTrieSetNode[T]
) extends UIDTrieSetNode[T] {

    override def foreach[U](f: T ⇒ U): Unit = { f(v); _0.foreach(f); _1.foreach(f) }
    override def foldLeft[B](z: B)(op: (B, T) ⇒ B): B = _1.foldLeft(_0.foldLeft(op(z, v))(op))(op)
    override def forall(p: T ⇒ Boolean): Boolean = { p(v) && _0.forall(p) && _1.forall(p) }
    override def exists(p: T ⇒ Boolean): Boolean = { p(v) || _0.forall(p) || _1.forall(p) }
    override def head: T = v

    override def hashCode: Int = v.id ^ _0.hashCode ^ _1.hashCode

    override private[immutable] def +(
        value: T,
        id:    Int,
        key:   Int,
        level: Int
    ): UIDTrieSetNode[T] = {
        val v = this.v
        if (v.id != id) {
            if ((key & 1) == 0) {
                val new_0 = _0.+(value, id, key >> 1, level + 1)
                if (new_0 ne _0) {
                    new UIDTrieSetNode_0_1(v, new_0, _1)
                } else {
                    this
                }
            } else {
                val new_1 = _1.+(value, id, key >> 1, level + 1)
                if (new_1 ne _1) {
                    new UIDTrieSetNode_0_1(v, _0, new_1)
                } else {
                    this
                }
            }
        } else {
            this
        }
    }

    override private[immutable] def containsId(id: Int, key: Int): Boolean = {
        this.v.id == id || {
            val newKey = key >> 1
            if ((key & 1) == 0) _0.containsId(id, newKey) else _1.containsId(id, newKey)
        }
    }

    override private[immutable] def toString(indent: Int): String = {
        val spaces = " " * indent
        s"N($v,\n${spaces}0=>${_0.toString(indent + 1)},\n${spaces}1=>${_1.toString(indent + 1)})"
    }

}

private[immutable] final class UIDTrieSetNode_0[T <: UID](
        val v:  T,
        val _0: UIDTrieSetNode[T]
) extends UIDTrieSetNode[T] {

    override def hashCode: Int = v.id ^ _0.hashCode

    override def foreach[U](f: T ⇒ U): Unit = { f(v); _0.foreach(f) }
    override def foldLeft[B](z: B)(op: (B, T) ⇒ B): B = _0.foldLeft(op(z, v))(op)
    override def forall(p: T ⇒ Boolean): Boolean = { p(v) && _0.forall(p) }
    override def exists(p: T ⇒ Boolean): Boolean = { p(v) || _0.forall(p) }
    override def head: T = v

    override private[immutable] def +(
        value: T,
        id:    Int,
        key:   Int,
        level: Int
    ): UIDTrieSetNode[T] = {
        val v = this.v
        val vId = v.id
        if (vId != id) {
            if ((key & 1) == 0) {
                // let's check if we can improve the balancing of the tree by putting
                // the new value in this node and moving this node further down the tree...
                if (((vId >> level) & 1) == 1) {
                    if (!_0.containsId(id, key >> 1)) {
                        new UIDTrieSetNode_0_1(value, _0, new UIDTrieSet1(v))
                    } else {
                        this
                    }
                } else {
                    val new_0 = _0.+(value, id, key >> 1, level + 1)
                    if (new_0 ne _0) {
                        new UIDTrieSetNode_0(v, new_0)
                    } else {
                        this
                    }
                }
            } else {
                val new_1 = new UIDTrieSet1(value)
                new UIDTrieSetNode_0_1(v, _0, new_1)
            }
        } else {
            this
        }
    }

    private[immutable] def containsId(id: Int, key: Int): Boolean = {
        this.v.id == id || ((key & 1) == 0 && _0.containsId(id, key >> 1))
    }

    private[immutable] def toString(indent: Int): String = {
        val spaces = " " * indent
        s"N($v,\n${spaces}0=>${_0.toString(indent + 1)})"
    }
}

private[immutable] final class UIDTrieSetNode_1[T <: UID](
        val v:  T,
        val _1: UIDTrieSetNode[T]
) extends UIDTrieSetNode[T] {

    override def hashCode: Int = v.id ^ _1.hashCode

    override def foreach[U](f: T ⇒ U): Unit = { f(v); _1.foreach(f) }
    override def foldLeft[B](z: B)(op: (B, T) ⇒ B): B = _1.foldLeft(op(z, v))(op)
    override def forall(p: T ⇒ Boolean): Boolean = { p(v) && _1.forall(p) }
    override def exists(p: T ⇒ Boolean): Boolean = { p(v) || _1.forall(p) }
    override def head: T = v

    override private[immutable] def +(
        value: T,
        id:    Int,
        key:   Int,
        level: Int
    ): UIDTrieSetNode[T] = {
        val v = this.v
        val vId = v.id
        if (vId != id) {
            if ((key & 1) == 0) {
                val new_0 = new UIDTrieSet1(value)
                new UIDTrieSetNode_0_1(v, new_0, _1)
            } else {
                // let's check if we can improve the balancing of the tree by putting
                // the new value in this node and moving this node further down the tree...
                if (((vId >> level) & 1) == 0) {
                    if (!_1.containsId(id, key >> 1)) {
                        new UIDTrieSetNode_0_1(value, new UIDTrieSet1(v), _1)
                    } else {
                        this
                    }
                } else {
                    val new_1 = _1.+(value, id, key >> 1, level + 1)
                    if (new_1 ne _1) {
                        new UIDTrieSetNode_1(v, new_1)
                    } else {
                        this
                    }
                }
            }
        } else {
            this
        }
    }

    override private[immutable] def containsId(id: Int, key: Int): Boolean = {
        this.v.id == id || ((key & 1) == 1 && _1.containsId(id, key >> 1))
    }

    override private[immutable] def toString(indent: Int): String = {
        val spaces = " " * indent
        s"N($v,\n${spaces}1=>${_1.toString(indent + 1)})"
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy