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

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

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

import scala.annotation.tailrec

import org.opalj.collection.LongIterator
import org.opalj.collection.mutable.RefArrayStack
import java.lang.Long.{hashCode ⇒ lHashCode}

sealed abstract class LongTrieSet extends LongSet { intSet ⇒

    final type ThisSet = LongTrieSet

    override def equals(other: Any): Boolean
    override def hashCode: Int
}

object LongTrieSet {

    def empty: LongTrieSet = LongTrieSet0

    def apply(v1: Long): LongTrieSet = new LongTrieSet1(v1)

    def apply(v1: Long, v2: Long): LongTrieSetLeaf = {
        if (v1 == v2)
            new LongTrieSet1(v1)
        else if (v1 < v2)
            new LongTrieSet2(v1, v2)
        else
            new LongTrieSet2(v2, v1)
    }

    def apply(v1: Long, v2: Long, v3: Long): LongTrieSetLeaf = {
        if (v1 == v2)
            apply(v1, v3)
        else if (v2 == v3)
            apply(v1, v2)
        else if (v1 == v3)
            apply(v2, v3)
        else {
            // all three values are different...
            if (v1 < v2) {
                if (v2 < v3)
                    new LongTrieSet3(v1, v2, v3)
                else if (v1 < v3)
                    new LongTrieSet3(v1, v3, v2)
                else
                    new LongTrieSet3(v3, v1, v2)
            } else {
                // v2  i2) {
            i == i3
        } else {
            true
        }
    }

    override def apply(index: Int): Long = if (index == 0) i1 else if (index == 1) i2 else i3

    override def forall(p: Long ⇒ Boolean): Boolean = { p(i1) && p(i2) && p(i3) }
    override def foreach[U](f: Long ⇒ U): Unit = { f(i1); f(i2); f(i3) }
    override def iterator: LongIterator = LongIterator(i1, i2, i3)
    override def foldLeft[B](z: B)(op: (B, Long) ⇒ B): B = op(op(op(z, i1), i2), i3)

    override def +(i: Long): LongTrieSet = {
        if (i < i2) {
            if (i == i1)
                return this;
        } else if (i > i2) {
            if (i == i3)
                return this;
        } else {
            // i =!= i2
            return this;
        }

        new LongTrieSetN(4, this.grow(i, 0))
    }
    override private[immutable] def +(i: Long, level: Int): LongTrieSetNode = {
        if (i < i2) {
            if (i == i1)
                return this;
        } else if (i > i2) {
            if (i == i3)
                return this;
        } else {
            // i =!= i2
            return this;
        }

        this.grow(i, level)
    }
    private[this] def grow(i: Long, level: Int): LongTrieSetNode = {
        // we know that i1, i2, i3 and i are all different values
        // Now, let's try to create the final tree in a more direct manner:

        val i1_7L = ((i1 >> level) & 7L).toInt
        val i2_7L = ((i2 >> level) & 7L).toInt
        val i3_7L = ((i3 >> level) & 7L).toInt
        val i_7L = ((i >> level) & 7L).toInt
        if (i1_7L == i2_7L) {
            if (i1_7L == i3_7L) {
                if (i1_7L == i_7L) {
                    // they all have the same 3 bits used for branching purposes...
                    new LongTrieSetNode1(i1_7L.toInt, grow(i, level + 3))
                } else {
                    new LongTrieSetNode2(
                        1 << (i_7L * 4) | 2 << (i1_7L * 4) /*lookuptable*/ ,
                        new LongTrieSet1(i),
                        this
                    )
                }
            } else {
                // i1_7L != i3_7L
                if (i1_7L == i_7L) {
                    new LongTrieSetNode2(
                        1 << (i3_7L * 4) | 2 << (i1_7L * 4) /*lookuptable*/ ,
                        new LongTrieSet1(i3),
                        LongTrieSet(i1, i2, i)
                    )
                } else {
                    // i1_7L != i3_7L
                    // i1_7L != i_7L
                    if (i3_7L == i_7L) {
                        new LongTrieSetNode2(
                            1 << (i3_7L * 4) | 2 << (i1_7L * 4) /*lookuptable*/ ,
                            LongTrieSet(i3, i),
                            new LongTrieSet2(i1, i2)
                        )
                    } else {
                        new LongTrieSetNode3(
                            1 << (i3_7L * 4) | 2 << (i1_7L * 4) | 3 << (i_7L * 4),
                            new LongTrieSet1(i3),
                            new LongTrieSet2(i1, i2),
                            new LongTrieSet1(i)
                        )
                    }
                }
            }
        } else {
            // i1_7L != i2_7L
            if (i2_7L == i3_7L) {
                if (i2_7L == i_7L) {
                    new LongTrieSetNode2(
                        1 << (i1_7L * 4) | 2 << (i2_7L * 4) /*lookuptable*/ ,
                        new LongTrieSet1(i1),
                        LongTrieSet(i2, i3, i)
                    )
                } else {
                    // i1_7L != i2_7L
                    // i2_7L != i_7L
                    if (i1_7L == i_7L) {
                        new LongTrieSetNode2(
                            1 << (i1_7L * 4) | 2 << (i2_7L * 4) /*lookuptable*/ ,
                            LongTrieSet(i1, i),
                            new LongTrieSet2(i2, i3)
                        )
                    } else {
                        new LongTrieSetNode3(
                            1 << (i1_7L * 4) | 2 << (i2_7L * 4) | 3 << (i_7L * 4),
                            new LongTrieSet1(i1),
                            new LongTrieSet2(i2, i3),
                            new LongTrieSet1(i)
                        )
                    }
                }
            } else {
                // i1_7L != i2_7L
                // i2_7L != i3_7L
                if (i1_7L == i3_7L) {
                    if (i1_7L == i_7L) {
                        new LongTrieSetNode2(
                            1 << (i2_7L * 4) | 2 << (i1_7L * 4) /*lookuptable*/ ,
                            new LongTrieSet1(i2),
                            LongTrieSet(i1, i3, i)
                        )
                    } else {
                        // i1_7L != i2_7L
                        // i2_7L != i3_7L
                        // i1_7L != i_7L
                        if (i2_7L == i_7L) {
                            new LongTrieSetNode2(
                                1 << (i1_7L * 4) | 2 << (i2_7L * 4) /*lookuptable*/ ,
                                new LongTrieSet2(i1, i3),
                                LongTrieSet(i2, i)
                            )
                        } else {
                            // i1_7L != i2_7L
                            // i2_7L != i3_7L
                            // i1_7L != i_7L
                            // i2_7L != i_7L
                            new LongTrieSetNode3(
                                1 << (i2_7L * 4) | 2 << (i1_7L * 4) | 3 << (i_7L * 4),
                                new LongTrieSet1(i2),
                                new LongTrieSet2(i1, i3),
                                new LongTrieSet1(i)
                            )
                        }
                    }
                } else {
                    // i1_7L != i2_7L
                    // i2_7L != i3_7L
                    // i1_7L != i3_7L
                    if (i1_7L == i_7L) {
                        new LongTrieSetNode3(
                            1 << (i1_7L * 4) | 2 << (i2_7L * 4) | 3 << (i3_7L * 4),
                            LongTrieSet(i1, i),
                            new LongTrieSet1(i2),
                            new LongTrieSet1(i3)
                        )
                    } else if (i2_7L == i_7L) {
                        new LongTrieSetNode3(
                            1 << (i2_7L * 4) | 2 << (i1_7L * 4) | 3 << (i3_7L * 4),
                            LongTrieSet(i2, i),
                            new LongTrieSet1(i1),
                            new LongTrieSet1(i3)
                        )
                    } else if (i3_7L == i_7L) {
                        new LongTrieSetNode3(
                            1 << (i3_7L * 4) | 2 << (i2_7L * 4) | 3 << (i1_7L * 4),
                            LongTrieSet(i3, i),
                            new LongTrieSet1(i2),
                            new LongTrieSet1(i1)
                        )
                    } else {
                        new LongTrieSetNode4(
                            1 << (i_7L * 4) | 2 << (i3_7L * 4) | 3 << (i2_7L * 4) | 4 << (i1_7L * 4),
                            new LongTrieSet1(i),
                            new LongTrieSet1(i3),
                            new LongTrieSet1(i2),
                            new LongTrieSet1(i1)
                        )
                    }
                }
            }
        }

        /* OLD
        val l = new LongTrieSet1(i)
        var r: LongTrieSetNode = new LongTrieSetNode1(((i >> level) & 7L).toInt, l)
        r = r + (i1, level)
        r = r + (i2, level)
        r = r + (i3, level)
        r
         */
    }

    override def equals(other: Any): Boolean = {
        other match {
            case that: LongTrieSet3 ⇒
                (this eq that) || (i1 == that.i1 && i2 == that.i2 && i3 == that.i3)
            case _ ⇒
                false
        }
    }
    override def hashCode: Int = 31 * (31 * (31 + lHashCode(i1)) + lHashCode(i2)) + lHashCode(i3)
    override def toString: String = s"LongTrieSet($i1, $i2, $i3)"

}

private[immutable] final class LongTrieSetN(
        final val size: Int,
        final val root: LongTrieSetNode
) extends LongTrieSet {

    // assert(size >= 4)

    override def isEmpty: Boolean = false
    override def isSingletonSet: Boolean = false
    override def contains(value: Long): Boolean = root.contains(value, value)
    override def forall(p: Long ⇒ Boolean): Boolean = root.forall(p)
    override def foreach[U](f: Long ⇒ U): Unit = root.foreach(f)

    override def iterator: LongIterator = new LongIterator {
        private[this] var leafNode: LongTrieSetLeaf = null
        private[this] var index = 0
        private[this] val nodes = new RefArrayStack(root, Math.min(16, size / 2))
        @tailrec private[this] def moveToNextLeafNode(): Unit = {
            if (nodes.isEmpty) {
                leafNode = null
                return ;
            }
            (nodes.pop(): @unchecked) match {
                case n: LongTrieSetLeaf ⇒
                    leafNode = n
                    index = 0
                    return ;

                case n: LongTrieSetNode1 ⇒
                    nodes.push(n.n1)

                case n: LongTrieSetNode2 ⇒
                    nodes.push(n.n1)
                    nodes.push(n.n2)

                case n: LongTrieSetNode3 ⇒
                    nodes.push(n.n1)
                    nodes.push(n.n2)
                    nodes.push(n.n3)

                case n: LongTrieSetNode4 ⇒
                    nodes.push(n.n1)
                    nodes.push(n.n2)
                    nodes.push(n.n3)
                    nodes.push(n.n4)

                case n: LongTrieSetNode5 ⇒
                    nodes.push(n.n1)
                    nodes.push(n.n2)
                    nodes.push(n.n3)
                    nodes.push(n.n4)
                    nodes.push(n.n5)

                case n: LongTrieSetNode6 ⇒
                    nodes.push(n.n1)
                    nodes.push(n.n2)
                    nodes.push(n.n3)
                    nodes.push(n.n4)
                    nodes.push(n.n5)
                    nodes.push(n.n6)

                case n: LongTrieSetNode7 ⇒
                    nodes.push(n.n1)
                    nodes.push(n.n2)
                    nodes.push(n.n3)
                    nodes.push(n.n4)
                    nodes.push(n.n5)
                    nodes.push(n.n6)
                    nodes.push(n.n7)

                case n: LongTrieSetNode8 ⇒
                    nodes.push(n.n1)
                    nodes.push(n.n2)
                    nodes.push(n.n3)
                    nodes.push(n.n4)
                    nodes.push(n.n5)
                    nodes.push(n.n6)
                    nodes.push(n.n7)
                    nodes.push(n.n8)
            }
            moveToNextLeafNode()
        }
        moveToNextLeafNode()
        def hasNext: Boolean = leafNode ne null
        def next: Long = {
            var index = this.index
            val i = leafNode(index)
            index += 1
            if (index >= leafNode.size) {
                moveToNextLeafNode()
            } else {
                this.index = index
            }
            i
        }
    }

    override def foldLeft[B](z: B)(op: (B, Long) ⇒ B): B = root.foldLeft(z)(op)

    override def equals(other: Any): Boolean = {
        other match {
            case that: LongTrieSetN ⇒
                (that eq this) || (
                    that.size == this.size &&
                    // Recall that the iteration order of the values is dependent on the
                    // insertion order, but the shape of the tree – reflected by the size
                    // of nodes and also the captured bit patterns has to be equal. Hence,
                    // comparison can be done by traversing both trees in parallel which
                    // is more efficient than iterating over this (or that) tree and
                    // performing a contains check for each element (the naive approach).
                    this.root == that.root
                )
            case _ ⇒ false
        }
    }
    override def hashCode: Int = root.hashCode * 31 + size

    override def +(i: Long): LongTrieSet = {
        val root = this.root
        val newRoot = root + (i, 0)
        if (newRoot ne root) {
            new LongTrieSetN(size + 1, newRoot)
        } else {
            this
        }
    }

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

}

private[immutable] final class LongTrieSetNode1(
        final val n1Bits: Int,
        final val n1:     LongTrieSetNode
) extends LongTrieSetNode {

    override def foreach[U](f: Long ⇒ U): Unit = n1.foreach(f)
    override def forall(p: Long ⇒ Boolean): Boolean = n1.forall(p)
    override def foldLeft[B](z: B)(op: (B, Long) ⇒ B): B = n1.foldLeft(z)(op)

    override private[immutable] def contains(value: Long, key: Long): Boolean = {
        if (n1Bits == (key & 7L).toInt) {
            n1.contains(value, key >> 3)
        } else {
            false
        }
    }

    override private[immutable] def +(v: Long, level: Int): LongTrieSetNode = {
        val vBits = ((v >> level) & 7L).toInt
        if (vBits == n1Bits) {
            val newN1 = n1 + (v, level + 3)
            if (newN1 ne n1) {
                new LongTrieSetNode1(n1Bits, newN1)
            } else {
                this
            }
        } else {
            val lookupTable = 1 << (n1Bits * 4) | 2 << (vBits * 4)
            new LongTrieSetNode2(lookupTable, n1, new LongTrieSet1(v))
        }
    }

    override def equals(other: Any): Boolean = {
        other match {
            case that: LongTrieSetNode1 ⇒
                this.n1Bits == that.n1Bits && this.n1 == that.n1
            case _ ⇒ false
        }
    }
    override def hashCode: Int = n1.hashCode

    override def toString(indent: Int): String = {
        s"N(${bitsToString(n1Bits)}=>${n1.toString(indent + 1)})"
    }

}

private[immutable] sealed abstract class LongTrieSetNode2_7 extends LongTrieSetNode {

    /**
     * The mapping between the three (relevant) bits of the value to the slot where the value
     * is stored.
     */
    val lookupTable: Int

    /**
     * The index starts with "1"!
     */
    def node(index: Int): LongTrieSetNode

    final override private[immutable] def contains(v: Long, key: Long): Boolean = {
        val vBits = (key & 7L).toInt
        val vIndex = (lookupTable >> (vBits * 4)) & 15
        val n = node(vIndex)
        if (n ne null) {
            n.contains(v, key >> 3)
        } else {
            false
        }
    }

    final override def toString(level: Int): String = {
        val indent = " " * level * 3
        var s = s"N("
        var i = 0
        while (i < 8) {
            val index = ((lookupTable >> (i * 4)) & 15)
            val n = node(index)
            if (n ne null) {
                s += s"\n$indent${bitsToString(i)}=>${n.toString(level + 1)}"
            }
            i += 1
        }
        s+")"
    }

    final override def equals(other: Any): Boolean = {
        other match {
            case that: LongTrieSetNode2_7 ⇒
                val thisLookupTable = this.lookupTable
                val thatLookupTable = that.lookupTable
                var index = 0
                do {
                    val thisIndex = thisLookupTable >> (index * 4) & 15
                    val thatIndex = thatLookupTable >> (index * 4) & 15
                    if (thisIndex == 0) {
                        if (thatIndex == 0)
                            index += 1
                        else
                            return false;
                    } else {
                        if (thatIndex == 0)
                            return false;
                        else {
                            if (that.node(thatIndex) == this.node(thisIndex)) {
                                index += 1
                            } else {
                                return false;
                            }
                        }
                    }
                } while (index < 8)
                true
            case _ ⇒
                false
        }
    }
}

private[immutable] final class LongTrieSetNode2(
        final val lookupTable: Int,
        final val n1:          LongTrieSetNode,
        final val n2:          LongTrieSetNode
) extends LongTrieSetNode2_7 {

    override def node(index: Int): LongTrieSetNode = {
        index match {
            case 1 ⇒ n1
            case 2 ⇒ n2
            case _ ⇒ null
        }
    }

    override def foreach[U](f: Long ⇒ U): Unit = {
        n1.foreach(f)
        n2.foreach(f)
    }

    override def forall(p: Long ⇒ Boolean): Boolean = {
        n1.forall(p) && n2.forall(p)
    }

    override def foldLeft[B](z: B)(op: (B, Long) ⇒ B): B = {
        n2.foldLeft(n1.foldLeft(z)(op))(op)
    }

    override private[immutable] def +(v: Long, level: Int): LongTrieSetNode = {
        val vBits = ((v >> level) & 7L).toInt
        val vIndex = (lookupTable >> (vBits * 4)) & 15
        vIndex match {
            case 0 ⇒
                val newLookupTable = lookupTable | (3 << (vBits * 4))
                val newN3 = new LongTrieSet1(v)
                new LongTrieSetNode3(newLookupTable, n1, n2, newN3)
            case 1 ⇒
                val newN1 = n1 + (v, level + 3)
                if (newN1 ne n1) {
                    new LongTrieSetNode2(lookupTable, newN1, n2)
                } else {
                    this
                }
            case 2 ⇒
                val newN2 = n2 + (v, level + 3)
                if (newN2 ne n2) {
                    new LongTrieSetNode2(lookupTable, n1, newN2)
                } else {
                    this
                }
        }
    }

    override def hashCode: Int = n1.hashCode ^ n2.hashCode // to ensure order independence

}

private[immutable] final class LongTrieSetNode3(
        final val lookupTable: Int,
        final val n1:          LongTrieSetNode,
        final val n2:          LongTrieSetNode,
        final val n3:          LongTrieSetNode
) extends LongTrieSetNode2_7 {

    override def foreach[U](f: Long ⇒ U): Unit = {
        n1.foreach(f)
        n2.foreach(f)
        n3.foreach(f)
    }

    override def forall(p: Long ⇒ Boolean): Boolean = {
        n1.forall(p) && n2.forall(p) && n3.forall(p)
    }

    override def foldLeft[B](z: B)(op: (B, Long) ⇒ B): B = {
        n3.foldLeft(n2.foldLeft(n1.foldLeft(z)(op))(op))(op)
    }

    override def node(index: Int): LongTrieSetNode = {
        index match {
            case 1 ⇒ n1
            case 2 ⇒ n2
            case 3 ⇒ n3
            case _ ⇒ null
        }
    }

    override private[immutable] def +(v: Long, level: Int): LongTrieSetNode = {
        val vBits = ((v >> level) & 7L).toInt
        val vIndex = (lookupTable >> (vBits * 4)) & 15
        vIndex match {
            case 0 ⇒
                val newLookupTable = lookupTable | (4 << (vBits * 4))
                val newN4 = new LongTrieSet1(v)
                new LongTrieSetNode4(newLookupTable, n1, n2, n3, newN4)
            case 1 ⇒
                val newN1 = n1 + (v, level + 3)
                if (newN1 ne n1) {
                    new LongTrieSetNode3(lookupTable, newN1, n2, n3)
                } else {
                    this
                }
            case 2 ⇒
                val newN2 = n2 + (v, level + 3)
                if (newN2 ne n2) {
                    new LongTrieSetNode3(lookupTable, n1, newN2, n3)
                } else {
                    this
                }
            case 3 ⇒
                val newN3 = n3 + (v, level + 3)
                if (newN3 ne n3) {
                    new LongTrieSetNode3(lookupTable, n1, n2, newN3)
                } else {
                    this
                }
        }
    }

    override def hashCode: Int = n1.hashCode ^ n2.hashCode ^ n3.hashCode
}

private[immutable] final class LongTrieSetNode4(
        final val lookupTable: Int,
        final val n1:          LongTrieSetNode,
        final val n2:          LongTrieSetNode,
        final val n3:          LongTrieSetNode,
        final val n4:          LongTrieSetNode
) extends LongTrieSetNode2_7 {

    override def foreach[U](f: Long ⇒ U): Unit = {
        n1.foreach(f)
        n2.foreach(f)
        n3.foreach(f)
        n4.foreach(f)
    }

    override def forall(p: Long ⇒ Boolean): Boolean = {
        n1.forall(p) && n2.forall(p) && n3.forall(p) && n4.forall(p)
    }

    override def foldLeft[B](z: B)(op: (B, Long) ⇒ B): B = {
        n4.foldLeft(n3.foldLeft(n2.foldLeft(n1.foldLeft(z)(op))(op))(op))(op)
    }

    override def node(index: Int): LongTrieSetNode = {
        index match {
            case 1 ⇒ n1
            case 2 ⇒ n2
            case 3 ⇒ n3
            case 4 ⇒ n4
            case _ ⇒ null
        }
    }

    override private[immutable] def +(v: Long, level: Int): LongTrieSetNode = {
        val vBits = ((v >> level) & 7L).toInt
        val vIndex = (lookupTable >> (vBits * 4)) & 15
        vIndex match {
            case 0 ⇒
                val newLookupTable = lookupTable | (5 << (vBits * 4))
                val newN5 = new LongTrieSet1(v)
                new LongTrieSetNode5(newLookupTable, n1, n2, n3, n4, newN5)
            case 1 ⇒
                val newN1 = n1 + (v, level + 3)
                if (newN1 ne n1) {
                    new LongTrieSetNode4(lookupTable, newN1, n2, n3, n4)
                } else {
                    this
                }
            case 2 ⇒
                val newN2 = n2 + (v, level + 3)
                if (newN2 ne n2) {
                    new LongTrieSetNode4(lookupTable, n1, newN2, n3, n4)
                } else {
                    this
                }
            case 3 ⇒
                val newN3 = n3 + (v, level + 3)
                if (newN3 ne n3) {
                    new LongTrieSetNode4(lookupTable, n1, n2, newN3, n4)
                } else {
                    this
                }
            case 4 ⇒
                val newN4 = n4 + (v, level + 3)
                if (newN4 ne n4) {
                    new LongTrieSetNode4(lookupTable, n1, n2, n3, newN4)
                } else {
                    this
                }
        }
    }

    override def hashCode: Int = {
        n1.hashCode ^ n2.hashCode ^ n3.hashCode ^ n4.hashCode
    }
}

private[immutable] final class LongTrieSetNode5(
        final val lookupTable: Int,
        final val n1:          LongTrieSetNode,
        final val n2:          LongTrieSetNode,
        final val n3:          LongTrieSetNode,
        final val n4:          LongTrieSetNode,
        final val n5:          LongTrieSetNode
) extends LongTrieSetNode2_7 {

    override def foreach[U](f: Long ⇒ U): Unit = {
        n1.foreach(f)
        n2.foreach(f)
        n3.foreach(f)
        n4.foreach(f)
        n5.foreach(f)
    }

    override def forall(p: Long ⇒ Boolean): Boolean = {
        n1.forall(p) && n2.forall(p) && n3.forall(p) && n4.forall(p) && n5.forall(p)
    }

    override def foldLeft[B](z: B)(op: (B, Long) ⇒ B): B = {
        n5.foldLeft(n4.foldLeft(n3.foldLeft(n2.foldLeft(n1.foldLeft(z)(op))(op))(op))(op))(op)
    }

    override def node(index: Int): LongTrieSetNode = {
        index match {
            case 1 ⇒ n1
            case 2 ⇒ n2
            case 3 ⇒ n3
            case 4 ⇒ n4
            case 5 ⇒ n5
            case _ ⇒ null
        }
    }

    override private[immutable] def +(v: Long, level: Int): LongTrieSetNode = {
        val vBits = ((v >> level) & 7L).toInt
        val vIndex = (lookupTable >> (vBits * 4)) & 15
        vIndex match {
            case 0 ⇒
                val newLookupTable = lookupTable | (6 << (vBits * 4))
                val newN6 = new LongTrieSet1(v)
                new LongTrieSetNode6(newLookupTable, n1, n2, n3, n4, n5, newN6)
            case 1 ⇒
                val newN1 = n1 + (v, level + 3)
                if (newN1 ne n1) {
                    new LongTrieSetNode5(lookupTable, newN1, n2, n3, n4, n5)
                } else {
                    this
                }
            case 2 ⇒
                val newN2 = n2 + (v, level + 3)
                if (newN2 ne n2) {
                    new LongTrieSetNode5(lookupTable, n1, newN2, n3, n4, n5)
                } else {
                    this
                }
            case 3 ⇒
                val newN3 = n3 + (v, level + 3)
                if (newN3 ne n3) {
                    new LongTrieSetNode5(lookupTable, n1, n2, newN3, n4, n5)
                } else {
                    this
                }
            case 4 ⇒
                val newN4 = n4 + (v, level + 3)
                if (newN4 ne n4) {
                    new LongTrieSetNode5(lookupTable, n1, n2, n3, newN4, n5)
                } else {
                    this
                }
            case 5 ⇒
                val newN5 = n5 + (v, level + 3)
                if (newN5 ne n5) {
                    new LongTrieSetNode5(lookupTable, n1, n2, n3, n4, newN5)
                } else {
                    this
                }
        }
    }

    override def hashCode: Int = {
        n1.hashCode ^ n2.hashCode ^ n3.hashCode ^ n4.hashCode ^ n5.hashCode
    }
}

private[immutable] final class LongTrieSetNode6(
        final val lookupTable: Int,
        final val n1:          LongTrieSetNode,
        final val n2:          LongTrieSetNode,
        final val n3:          LongTrieSetNode,
        final val n4:          LongTrieSetNode,
        final val n5:          LongTrieSetNode,
        final val n6:          LongTrieSetNode
) extends LongTrieSetNode2_7 {

    override def foreach[U](f: Long ⇒ U): Unit = {
        n1.foreach(f)
        n2.foreach(f)
        n3.foreach(f)
        n4.foreach(f)
        n5.foreach(f)
        n6.foreach(f)
    }

    override def forall(p: Long ⇒ Boolean): Boolean = {
        n1.forall(p) &&
            n2.forall(p) &&
            n3.forall(p) &&
            n4.forall(p) &&
            n5.forall(p) &&
            n6.forall(p)
    }

    override def foldLeft[B](z: B)(op: (B, Long) ⇒ B): B = {
        val f4 = n4.foldLeft(n3.foldLeft(n2.foldLeft(n1.foldLeft(z)(op))(op))(op))(op)
        n6.foldLeft(n5.foldLeft(f4)(op))(op)
    }

    override def node(index: Int): LongTrieSetNode = {
        index match {
            case 1 ⇒ n1
            case 2 ⇒ n2
            case 3 ⇒ n3
            case 4 ⇒ n4
            case 5 ⇒ n5
            case 6 ⇒ n6
            case _ ⇒ null
        }
    }

    override private[immutable] def +(v: Long, level: Int): LongTrieSetNode = {
        val vBits = ((v >> level) & 7L).toInt
        val vIndex = (lookupTable >> (vBits * 4)) & 15
        vIndex match {
            case 0 ⇒
                val newLookupTable = lookupTable | (7 << (vBits * 4))
                val newN7 = new LongTrieSet1(v)
                new LongTrieSetNode7(newLookupTable, n1, n2, n3, n4, n5, n6, newN7)
            case 1 ⇒
                val newN1 = n1 + (v, level + 3)
                if (newN1 ne n1) {
                    new LongTrieSetNode6(lookupTable, newN1, n2, n3, n4, n5, n6)
                } else {
                    this
                }
            case 2 ⇒
                val newN2 = n2 + (v, level + 3)
                if (newN2 ne n2) {
                    new LongTrieSetNode6(lookupTable, n1, newN2, n3, n4, n5, n6)
                } else {
                    this
                }
            case 3 ⇒
                val newN3 = n3 + (v, level + 3)
                if (newN3 ne n3) {
                    new LongTrieSetNode6(lookupTable, n1, n2, newN3, n4, n5, n6)
                } else {
                    this
                }
            case 4 ⇒
                val newN4 = n4 + (v, level + 3)
                if (newN4 ne n4) {
                    new LongTrieSetNode6(lookupTable, n1, n2, n3, newN4, n5, n6)
                } else {
                    this
                }
            case 5 ⇒
                val newN5 = n5 + (v, level + 3)
                if (newN5 ne n5) {
                    new LongTrieSetNode6(lookupTable, n1, n2, n3, n4, newN5, n6)
                } else {
                    this
                }
            case 6 ⇒
                val newN6 = n6 + (v, level + 3)
                if (newN6 ne n6) {
                    new LongTrieSetNode6(lookupTable, n1, n2, n3, n4, n5, newN6)
                } else {
                    this
                }
        }
    }

    override def hashCode: Int = {
        n1.hashCode ^ n2.hashCode ^ n3.hashCode ^ n4.hashCode ^ n5.hashCode ^ n6.hashCode
    }
}

private[immutable] final class LongTrieSetNode7(
        final val lookupTable: Int,
        final val n1:          LongTrieSetNode,
        final val n2:          LongTrieSetNode,
        final val n3:          LongTrieSetNode,
        final val n4:          LongTrieSetNode,
        final val n5:          LongTrieSetNode,
        final val n6:          LongTrieSetNode,
        final val n7:          LongTrieSetNode
) extends LongTrieSetNode2_7 {

    override def foreach[U](f: Long ⇒ U): Unit = {
        n1.foreach(f)
        n2.foreach(f)
        n3.foreach(f)
        n4.foreach(f)
        n5.foreach(f)
        n6.foreach(f)
        n7.foreach(f)
    }

    override def forall(p: Long ⇒ Boolean): Boolean = {
        n1.forall(p) &&
            n2.forall(p) &&
            n3.forall(p) &&
            n4.forall(p) &&
            n5.forall(p) &&
            n6.forall(p) &&
            n7.forall(p)
    }

    override def foldLeft[B](z: B)(op: (B, Long) ⇒ B): B = {
        val f4 = n4.foldLeft(n3.foldLeft(n2.foldLeft(n1.foldLeft(z)(op))(op))(op))(op)
        n7.foldLeft(n6.foldLeft(n5.foldLeft(f4)(op))(op))(op)
    }

    override def node(index: Int): LongTrieSetNode = {
        index match {
            case 1 ⇒ n1
            case 2 ⇒ n2
            case 3 ⇒ n3
            case 4 ⇒ n4
            case 5 ⇒ n5
            case 6 ⇒ n6
            case 7 ⇒ n7
            case _ ⇒ null
        }
    }

    override private[immutable] def +(v: Long, level: Int): LongTrieSetNode = {
        val vBits = ((v >> level) & 7L).toInt
        val vIndex = (lookupTable >> (vBits * 4)) & 15
        vIndex match {
            case 0 ⇒
                // We resolve the lookup table because we don't need it any longe
                val newV = new LongTrieSet1(v)
                val newN1 = if (vBits == 0) newV else node(lookupTable & 15)
                val newN2 = if (vBits == 1) newV else node(lookupTable >> 4 & 15)
                val newN3 = if (vBits == 2) newV else node(lookupTable >> 8 & 15)
                val newN4 = if (vBits == 3) newV else node(lookupTable >> 12 & 15)
                val newN5 = if (vBits == 4) newV else node(lookupTable >> 16 & 15)
                val newN6 = if (vBits == 5) newV else node(lookupTable >> 20 & 15)
                val newN7 = if (vBits == 6) newV else node(lookupTable >> 24 & 15)
                val newN8 = if (vBits == 7) newV else node(lookupTable >> 28 & 15)
                new LongTrieSetNode8(newN1, newN2, newN3, newN4, newN5, newN6, newN7, newN8)
            case 1 ⇒
                val newN1 = n1 + (v, level + 3)
                if (newN1 ne n1) {
                    new LongTrieSetNode7(lookupTable, newN1, n2, n3, n4, n5, n6, n7)
                } else {
                    this
                }
            case 2 ⇒
                val newN2 = n2 + (v, level + 3)
                if (newN2 ne n2) {
                    new LongTrieSetNode7(lookupTable, n1, newN2, n3, n4, n5, n6, n7)
                } else {
                    this
                }
            case 3 ⇒
                val newN3 = n3 + (v, level + 3)
                if (newN3 ne n3) {
                    new LongTrieSetNode7(lookupTable, n1, n2, newN3, n4, n5, n6, n7)
                } else {
                    this
                }
            case 4 ⇒
                val newN4 = n4 + (v, level + 3)
                if (newN4 ne n4) {
                    new LongTrieSetNode7(lookupTable, n1, n2, n3, newN4, n5, n6, n7)
                } else {
                    this
                }
            case 5 ⇒
                val newN5 = n5 + (v, level + 3)
                if (newN5 ne n5) {
                    new LongTrieSetNode7(lookupTable, n1, n2, n3, n4, newN5, n6, n7)
                } else {
                    this
                }
            case 6 ⇒
                val newN6 = n6 + (v, level + 3)
                if (newN6 ne n6) {
                    new LongTrieSetNode7(lookupTable, n1, n2, n3, n4, n5, newN6, n7)
                } else {
                    this
                }
            case 7 ⇒
                val newN7 = n7 + (v, level + 3)
                if (newN7 ne n7) {
                    new LongTrieSetNode7(lookupTable, n1, n2, n3, n4, n5, n6, newN7)
                } else {
                    this
                }

        }
    }

    override def hashCode: Int = {
        val h6 = n1.hashCode ^ n2.hashCode ^ n3.hashCode ^ n4.hashCode ^ n5.hashCode ^ n6.hashCode
        h6 ^ n7.hashCode
    }
}

private[immutable] final class LongTrieSetNode8(
        final val n1: LongTrieSetNode,
        final val n2: LongTrieSetNode,
        final val n3: LongTrieSetNode,
        final val n4: LongTrieSetNode,
        final val n5: LongTrieSetNode,
        final val n6: LongTrieSetNode,
        final val n7: LongTrieSetNode,
        final val n8: LongTrieSetNode
) extends LongTrieSetNode {

    override def foreach[U](f: Long ⇒ U): Unit = {
        n1.foreach(f)
        n2.foreach(f)
        n3.foreach(f)
        n4.foreach(f)
        n5.foreach(f)
        n6.foreach(f)
        n7.foreach(f)
        n8.foreach(f)
    }

    override def forall(p: Long ⇒ Boolean): Boolean = {
        n1.forall(p) &&
            n2.forall(p) &&
            n3.forall(p) &&
            n4.forall(p) &&
            n5.forall(p) &&
            n6.forall(p) &&
            n7.forall(p) &&
            n8.forall(p)
    }

    override def foldLeft[B](z: B)(op: (B, Long) ⇒ B): B = {
        val f4 = n4.foldLeft(n3.foldLeft(n2.foldLeft(n1.foldLeft(z)(op))(op))(op))(op)
        n8.foldLeft(n7.foldLeft(n6.foldLeft(n5.foldLeft(f4)(op))(op))(op))(op)
    }

    override private[immutable] def contains(value: Long, key: Long): Boolean = {
        ((key & 7L).toInt match {
            case 0 ⇒ n1
            case 1 ⇒ n2
            case 2 ⇒ n3
            case 3 ⇒ n4
            case 4 ⇒ n5
            case 5 ⇒ n6
            case 6 ⇒ n7
            case 7 ⇒ n8
        }).contains(value, key >> 3)
    }

    override private[immutable] def +(v: Long, level: Int): LongTrieSetNode = {
        ((v >> level) & 7L).toInt match {
            case 0 ⇒
                val newN1 = n1 + (v, level + 3)
                if (newN1 ne n1) {
                    new LongTrieSetNode8(newN1, n2, n3, n4, n5, n6, n7, n8)
                } else {
                    this
                }
            case 1 ⇒
                val newN2 = n2 + (v, level + 3)
                if (newN2 ne n2) {
                    new LongTrieSetNode8(n1, newN2, n3, n4, n5, n6, n7, n8)
                } else {
                    this
                }
            case 2 ⇒
                val newN3 = n3 + (v, level + 3)
                if (newN3 ne n3) {
                    new LongTrieSetNode8(n1, n2, newN3, n4, n5, n6, n7, n8)
                } else {
                    this
                }
            case 3 ⇒
                val newN4 = n4 + (v, level + 3)
                if (newN4 ne n4) {
                    new LongTrieSetNode8(n1, n2, n3, newN4, n5, n6, n7, n8)
                } else {
                    this
                }
            case 4 ⇒
                val newN5 = n5 + (v, level + 3)
                if (newN5 ne n5) {
                    new LongTrieSetNode8(n1, n2, n3, n4, newN5, n6, n7, n8)
                } else {
                    this
                }
            case 5 ⇒
                val newN6 = n6 + (v, level + 3)
                if (newN6 ne n6) {
                    new LongTrieSetNode8(n1, n2, n3, n4, n5, newN6, n7, n8)
                } else {
                    this
                }
            case 6 ⇒
                val newN7 = n7 + (v, level + 3)
                if (newN7 ne n7) {
                    new LongTrieSetNode8(n1, n2, n3, n4, n5, n6, newN7, n8)
                } else {
                    this
                }
            case 7 ⇒
                val newN8 = n8 + (v, level + 3)
                if (newN8 ne n8) {
                    new LongTrieSetNode8(n1, n2, n3, n4, n5, n6, n7, newN8)
                } else {
                    this
                }

        }
    }

    final override def toString(level: Int): String = {
        val indent = " " * level * 3
        var s = s"N("
        var i = 0
        while (i < 8) {
            val n = i match {
                case 0 ⇒ n1
                case 1 ⇒ n2
                case 2 ⇒ n3
                case 3 ⇒ n4
                case 4 ⇒ n5
                case 5 ⇒ n6
                case 6 ⇒ n7
                case 7 ⇒ n8
            }
            s += s"\n$indent${bitsToString(i)}=>${n.toString(level + 1)}"
            i += 1
        }
        s+")"
    }

    override def equals(other: Any): Boolean = {
        other match {
            case that: LongTrieSetNode8 ⇒
                this.n1 == that.n1 &&
                    this.n2 == that.n2 &&
                    this.n3 == that.n3 &&
                    this.n4 == that.n4 &&
                    this.n5 == that.n5 &&
                    this.n6 == that.n6 &&
                    this.n7 == that.n7 &&
                    this.n8 == that.n8
            case _ ⇒ false
        }
    }
    override def hashCode: Int = {
        val h6 = n1.hashCode ^ n2.hashCode ^ n3.hashCode ^ n4.hashCode ^ n5.hashCode ^ n6.hashCode
        h6 ^ n7.hashCode ^ n8.hashCode
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy