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

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

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

import java.lang.Integer.toUnsignedLong

/**
 * An immutable bit set for storing positive int values.
 *
 * An array is used to store the underlying values.
 * The empty bit set and sets where the maximum value is 64 use optimized representations.
 *
 * @author Michael Eichberg
 */
sealed abstract class BitArraySet extends BitSet { thisSet ⇒

    def isEmpty: Boolean

    def +(i: Int): BitArraySet

    def ++(that: BitArraySet): BitArraySet

    def -(i: Int): BitArraySet

    final def |(that: BitArraySet): BitArraySet = this ++ that

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

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

}

private[immutable] object BitArraySet0 extends BitArraySet { thisSet ⇒

    override def isEmpty: Boolean = true

    override def +(i: Int): BitArraySet = BitArraySet(i)

    override def -(i: Int): BitArraySet = this

    override def ++(that: BitArraySet): BitArraySet = that

    override def contains(i: Int): Boolean = false

    override def iterator: IntIterator = IntIterator.empty

    override def equals(other: Any): Boolean = {
        other match {
            case that: AnyRef ⇒ this eq that
            case _            ⇒ false
        }
    }
    override def hashCode: Int = 1 // from j.u.Arrays.hashCode
}

private[immutable] final class BitArraySet32(val set: Int) extends BitArraySet { thisSet ⇒

    assert(set != 0L)

    override def isEmpty: Boolean = false

    override def +(i: Int): BitArraySet = {
        if (i < 32) {
            val set = this.set
            val newSet = set | (1 << i)
            if (newSet != set) new BitArraySet32(newSet) else this
        } else if (i < 64) {
            val newSet = Integer.toUnsignedLong(this.set) | (1L << i)
            new BitArraySet64(newSet)
        } else {
            val newSet = new BitArraySetN(new Array[Int]((i / 32) + 1))
            newSet.set(0) = set
            newSet + i
        }
    }

    override def -(i: Int): BitArraySet = {
        if (i < 32) {
            val set = this.set
            val newSet = set & (-1 & ~(1 << i))
            if (newSet == set)
                this
            else if (newSet == 0)
                BitArraySet0
            else
                new BitArraySet32(newSet)
        } else {
            this
        }
    }

    override def ++(that: BitArraySet): BitArraySet = {
        that match {
            case BitArraySet0 ⇒
                this

            case that: BitArraySet32 ⇒
                val thisSet = this.set
                val thatSet = that.set
                val newSet = thisSet | thatSet
                if (newSet == thisSet)
                    this
                else if (newSet == thatSet)
                    that
                else
                    new BitArraySet32(newSet)

            case that: BitArraySet64 ⇒
                val thatSet = that.set
                val newSet = Integer.toUnsignedLong(this.set) | thatSet
                if (newSet == thatSet)
                    that
                else
                    new BitArraySet64(newSet)

            case that: BitArraySetN ⇒
                that | this
        }
    }

    override def contains(i: Int): Boolean = {
        if (i < 32)
            (set & (1 << i)) != 0
        else
            false
    }

    override def iterator: IntIterator = new IntIterator {
        private[this] var i: Int = java.lang.Integer.numberOfTrailingZeros(set)
        def hasNext: Boolean = i < 32
        def next(): Int = {
            val currentI = this.i
            var i = currentI
            do { i += 1 } while (i < 32 && (set & (1 << i)) == 0);
            this.i = i
            currentI
        }
    }

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

    override def hashCode: Int = 31 * set
}

private[immutable] final class BitArraySet64(val set: Long) extends BitArraySet { thisSet ⇒

    assert(set != 0L)

    override def isEmpty: Boolean = false

    override def +(i: Int): BitArraySet = {
        if (i < 64) {
            val set = this.set
            val newSet = set | (1L << i)
            if (newSet != set) new BitArraySet64(newSet) else this
        } else {
            val newSet = new BitArraySetN(new Array[Int]((i / 32) + 1))
            newSet.set(0) = set.toInt
            newSet.set(1) = (set >>> 32).toInt
            newSet + i
        }
    }

    override def -(i: Int): BitArraySet = {
        if (i < 64) {
            val set = this.set
            val newSet = set & (-1L & ~(1L << i))
            if (newSet == set)
                this
            else if (newSet == 0L)
                BitArraySet0
            else if ((newSet & BitArraySet.HigherWordMask) == 0)
                new BitArraySet32(newSet.toInt)
            else
                new BitArraySet64(newSet)
        } else {
            this
        }
    }

    override def ++(that: BitArraySet): BitArraySet = {
        that match {
            case BitArraySet0 ⇒
                this

            case that: BitArraySet32 ⇒
                val thisSet = this.set
                val newSet = thisSet | toUnsignedLong(that.set)
                if (newSet == thisSet)
                    this
                else
                    new BitArraySet64(newSet)

            case that: BitArraySet64 ⇒
                val thisSet = this.set
                val thatSet = that.set
                val newSet = thisSet | thatSet
                if (newSet == thisSet)
                    this
                else if (newSet == thatSet)
                    that
                else
                    new BitArraySet64(newSet)

            case that: BitArraySetN ⇒
                that | this
        }
    }

    override def contains(i: Int): Boolean = {
        if (i < 64)
            (set & (1L << i)) != 0L
        else
            false
    }

    override def iterator: IntIterator = new IntIterator {
        private[this] var i: Int = java.lang.Long.numberOfTrailingZeros(set)
        def hasNext: Boolean = i < 64
        def next(): Int = {
            val currentI = this.i
            var i = currentI
            do { i += 1 } while (i < 64 && (set & (1L << i)) == 0L)
            this.i = i
            currentI
        }
    }

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

    override def hashCode: Int = 31 * (set ^ (set >>> 32)).toInt // from j.u.Arrays.hashCode
}

private[immutable] final class BitArraySetN(val set: Array[Int]) extends BitArraySet { self ⇒

    override def isEmpty: Boolean = false

    override def +(i: Int): BitArraySet = {
        val bucket = i / 32
        val setLength = set.length
        if (bucket >= setLength) {
            val newSet = new Array[Int](bucket + 1)
            Array.copy(set, 0, newSet, 0, setLength)
            newSet(bucket) = (1 << (i - 32 * bucket))
            new BitArraySetN(newSet)
        } else {
            val oldBucketValue = set(bucket)
            val newBucketValue = oldBucketValue | (1 << (i - 32 * bucket))
            if (oldBucketValue == newBucketValue)
                this
            else {
                val newSet = new Array[Int](setLength)
                Array.copy(set, 0, newSet, 0, setLength)
                newSet(bucket) = newBucketValue
                new BitArraySetN(newSet)
            }
        }
    }

    override def -(i: Int): BitArraySet = {
        val setLength = set.length

        val bucket = i / 32
        if (bucket >= setLength)
            return this;

        val oldBucketValue = set(bucket)
        val newBucketValue = oldBucketValue & ((-1 & ~(1 << (i - 32 * bucket))))
        if (newBucketValue == oldBucketValue)
            return this;

        val lastBucket = setLength - 1
        if (newBucketValue == 0 && bucket == lastBucket) {
            // check how many buckets can be deleted....
            var emptyBuckets = 1
            while (emptyBuckets < setLength && set(lastBucket - emptyBuckets) == 0) {
                emptyBuckets += 1
            }
            (setLength - emptyBuckets) match {
                case 0 ⇒ BitArraySet0
                case 1 ⇒ new BitArraySet32(set(0))
                case 2 ⇒
                    val newSet = toUnsignedLong(set(0)) | toUnsignedLong(set(1)) << 32
                    new BitArraySet64(newSet)
                case x ⇒
                    val newSet = new Array[Int](x)
                    Array.copy(set, 0, newSet, 0, x)
                    new BitArraySetN(newSet)
            }
        } else {
            val newSet = new Array[Int](setLength)
            Array.copy(set, 0, newSet, 0, setLength)
            newSet(bucket) = newBucketValue
            new BitArraySetN(newSet)
        }
    }

    override def ++(that: BitArraySet): BitArraySet = {
        that match {
            case BitArraySet0 ⇒ this

            case that: BitArraySet32 ⇒
                val thisSet0 = this.set(0)
                val newSet0 = thisSet0 | that.set
                if (newSet0 == thisSet0)
                    this
                else {
                    val newSet = set.clone
                    newSet(0) = newSet0
                    new BitArraySetN(newSet)
                }

            case that: BitArraySet64 ⇒
                val thisSet = toUnsignedLong(this.set(0)) | toUnsignedLong(this.set(1)) << 32
                val newSet64 = thisSet | that.set
                if (newSet64 == thisSet)
                    this
                else {
                    val newSet = set.clone
                    newSet(0) = newSet64.toInt
                    newSet(1) = (newSet64 >>> 32).toInt
                    new BitArraySetN(newSet)
                }

            case that: BitArraySetN ⇒
                val thisSet = this.set
                val thatSet = that.set
                val thisSetLength = this.set.length
                val thatSetLength = that.set.length
                if (thisSetLength == thatSetLength) {
                    var i = 0
                    var takeThis = true
                    var takeThat = true
                    val newSet = new Array[Int](thisSetLength)
                    while (i < thisSetLength) {
                        val thisSetI = thisSet(i)
                        val thatSetI = thatSet(i)
                        val newSetI = thisSetI | thatSetI
                        takeThis &= (newSetI == thisSetI)
                        takeThat &= (newSetI == thatSetI)
                        newSet(i) = newSetI
                        i += 1
                    }
                    if (takeThis) this
                    else if (takeThat) that
                    else new BitArraySetN(newSet)
                } else if (thisSetLength > thatSetLength) {
                    var i = 0
                    var takeThis = true
                    val newSet = new Array[Int](thisSetLength)
                    while (i < thatSetLength) {
                        val thisSetI = thisSet(i)
                        val thatSetI = thatSet(i)
                        val newSetI = thisSetI | thatSetI
                        takeThis &= (newSetI == thisSetI)
                        newSet(i) = newSetI
                        i += 1
                    }
                    if (takeThis)
                        this
                    else {
                        Array.copy(set, i, newSet, i, thisSetLength - i)
                        new BitArraySetN(newSet)
                    }
                } else /*if (thisSetLength <= thatSetLength)*/ {
                    var i = 0
                    var takeThat = true
                    val newSet = new Array[Int](thatSetLength)
                    while (i < thisSetLength) {
                        val thisSetI = thisSet(i)
                        val thatSetI = thatSet(i)
                        val newSetI = thisSetI | thatSetI
                        takeThat &= (newSetI == thatSetI)
                        newSet(i) = newSetI
                        i += 1
                    }
                    if (takeThat)
                        that
                    else {
                        Array.copy(that.set, i, newSet, i, thatSetLength - i)
                        new BitArraySetN(newSet)
                    }
                }

        }
    }

    override def contains(i: Int): Boolean = {
        val set = this.set

        val bucket = i / 32
        if (bucket >= set.length)
            return false;

        (set(bucket) & (1 << (i - 32 * bucket))) != 0
    }

    override def iterator: IntIterator = new IntIterator {
        private[this] final val max: Int = set.length * 32
        private[this] var i: Int = -1
        private[this] def advanceIterator(): Unit = {
            val set = self.set
            var bucket = -1
            do {
                i += 1
                bucket = i / 32
            } while (i < max && (set(bucket) & (1 << (i - 32 * bucket))) == 0)
        }
        advanceIterator()
        def hasNext: Boolean = i < max
        def next(): Int = { val i = this.i; advanceIterator(); i }
    }

    override def equals(other: Any): Boolean = {
        other match {
            case that: BitArraySetN ⇒ java.util.Arrays.equals(this.set, that.set)
            case _                  ⇒ false
        }
    }

    override def hashCode: Int = java.util.Arrays.hashCode(set)
}

object BitArraySet {

    /**
     * Masks the higher word.
     */
    final val HigherWordMask = ~java.lang.Integer.toUnsignedLong(-1)

    final def empty: BitArraySet = BitArraySet0

    def apply(i: Int): BitArraySet = {
        if (i < 32)
            new BitArraySet32(1 << i)
        else if (i < 64)
            new BitArraySet64(1L << i)
        else
            new BitArraySetN(new Array[Int]((i / 32) + 1)) + i
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy