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

org.opalj.collection.mutable.FixedSizeBitSet.scala Maven / Gradle / Ivy

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

import java.io.Serializable

/**
 * A bit set with a given upper bound for the largest value that can be stored in the set.
 * The upper bound is only used to create an optimal underlying representation. It has no
 * impact on equals and/or hashcode computations. I.e., two sets with two different upper bounds
 * which contain the same values, are equal and have the same hashcode.
 *
 * Conceptually, the an array of long values is used to store the values.
 *
 * @note If values are added to the set that are larger than the specified size the behavior is
 *       undefined!
 *
 * @author Michael Eichberg
 */
sealed abstract class FixedSizeBitSet extends BitSet with Serializable {

    def +=(i: Int): this.type

    /**
     * Adds the given value to the set if the value is not in the set and returns true;
     * otherwise returns false. That is, the value is definitively in the set afterwards.
     */
    def add(i: Int): Boolean

    def -=(i: Int): this.type

    override def toString: String = mkString("FixedSizeBitSet(", ",", ")")
}

private[mutable] object ZeroLengthBitSet extends FixedSizeBitSet {
    override def isEmpty: Boolean = true
    override def +=(i: Int): this.type = throw new UnsupportedOperationException("fixed size is 0")
    override def add(i: Int): Boolean = throw new UnsupportedOperationException("fixed size is 0")
    override def -=(i: Int): this.type = this
    override def contains(i: Int): Boolean = false
    override def iterator: IntIterator = IntIterator.empty
    override def equals(other: Any): Boolean = {
        other match {
            case that: FixedSizeBitSet ⇒ that.isEmpty
            case _                     ⇒ false
        }
    }
    override def hashCode: Int = 1 // same as Arrays.hashCode(empty long array)
}

private[mutable] final class FixedSizeBitSet64 extends FixedSizeBitSet { thisSet ⇒

    private[mutable] var set: Long = 0L

    override def isEmpty: Boolean = set == 0L
    override def +=(i: Int): this.type = { set |= 1L << i; this }
    override def add(i: Int): Boolean = {
        val oldSet = set
        val newSet = oldSet | 1L << i
        if (newSet != oldSet) { set = newSet; true } else false
    }
    override def -=(i: Int): this.type = { set &= (-1L & ~(1L << i)); this }
    override def contains(i: Int): Boolean = (set & (1L << i)) != 0L

    override def iterator: IntIterator = new IntIterator {
        private[this] var i: Int = -1
        private[this] def advanceIterator(): Unit = {
            do { i += 1 } while (i < 64 && !thisSet.contains(i))
        }
        advanceIterator()
        def hasNext: Boolean = i < 64
        def next(): Int = { val i = this.i; advanceIterator(); i }
    }

    override def equals(other: Any): Boolean = {
        other match {
            case that: FixedSizeBitSet64  ⇒ that.set == this.set
            case that: FixedSizeBitSet128 ⇒ that.set2 == 0L && that.set1 == this.set
            case that: FixedSizeBitSetN   ⇒ that.equals(this)
            case ZeroLengthBitSet         ⇒ this.set == 0L
            case _                        ⇒ false
        }
    }

    override def hashCode: Int = {
        val elementHash = (set ^ (set >>> 32)).toInt
        if (elementHash == 0)
            1
        else
            31 + elementHash
    }
}

private[mutable] final class FixedSizeBitSet128 extends FixedSizeBitSet { thisSet ⇒

    private[mutable] var set1: Long = 0L
    private[mutable] var set2: Long = 0L

    override def isEmpty: Boolean = set1 == 0L && set2 == 0L

    override def +=(i: Int): this.type = {
        if (i <= 63)
            set1 |= 1L << i
        else {
            set2 |= 1L << (i - 64)
        }
        this
    }
    override def add(i: Int): Boolean = {
        if (i <= 63) {
            val oldSet1 = set1
            val newSet1 = oldSet1 | 1L << i
            if (oldSet1 != newSet1) { set1 = newSet1; true } else false
        } else {
            val oldSet2 = set2
            val newSet2 = oldSet2 | 1L << (i - 64)
            if (oldSet2 != newSet2) { set2 = newSet2; true } else false
        }
    }
    override def -=(i: Int): this.type = {
        if (i <= 63)
            set1 &= (-1L & ~(1L << i))
        else
            set2 &= (-1L & ~(1L << (i - 64)))
        this
    }
    override def contains(i: Int): Boolean = {
        if (i <= 63)
            (set1 & (1L << i)) != 0L
        else
            (set2 & (1L << (i - 64))) != 0L
    }

    override def iterator: IntIterator = new IntIterator {
        private[this] var i: Int = -1
        private[this] def advanceIterator(): Unit = {
            do { i += 1 } while (i < 128 && !thisSet.contains(i))
        }
        advanceIterator()
        def hasNext: Boolean = i < 128
        def next(): Int = { val i = this.i; advanceIterator(); i }
    }

    override def equals(other: Any): Boolean = {
        other match {
            case that: FixedSizeBitSet128 ⇒ this.set1 == that.set1 && this.set2 == that.set2
            case ZeroLengthBitSet         ⇒ this.set1 == 0L && this.set2 == 0L
            case that: FixedSizeBitSet64  ⇒ this.set2 == 0L && this.set1 == that.set
            case that: FixedSizeBitSetN   ⇒ that.equals(this)
            case _                        ⇒ false
        }
    }

    override def hashCode: Int = {
        var result = 1
        val set1Hash = (set1 ^ (set1 >>> 32)).toInt
        if (set1Hash != 0) result = 31 + set1Hash
        val set2Hash = (set2 ^ (set2 >>> 32)).toInt
        if (set2Hash != 0) 31 * result + set2Hash
        result
    }
}

private[mutable] final class FixedSizeBitSetN private[mutable] (
        private val set: Array[Long]
) extends FixedSizeBitSet { thisSet ⇒

    assert(set.length > 2)

    override def isEmpty: Boolean = {
        val set = this.set
        var i = 0
        val max = set.length
        while (i < max) { if (set(i) != 0L) return false; i += 1 }
        true
    }

    override def +=(i: Int): this.type = {
        val bucket = i / 64
        set(bucket) = set(bucket) | (1L << (i - 64 * bucket))
        this
    }
    override def add(i: Int): Boolean = {
        val bucket = i / 64
        val oldSet = set(bucket)
        val newSet = oldSet | (1L << (i - 64 * bucket))
        if (newSet != oldSet) { set(bucket) = newSet; true } else false
    }
    override def -=(i: Int): this.type = {
        val bucket = i / 64
        set(bucket) = set(bucket) & ((-1L & ~(1L << (i - 64 * bucket))))
        this
    }
    override def contains(i: Int): Boolean = {
        val bucket = i / 64
        (set(bucket) & (1L << (i - 64 * bucket))) != 0L
    }

    override def iterator: IntIterator = new IntIterator {
        private[this] val max: Int = set.length * 64
        private[this] var i: Int = -1
        private[this] def advanceIterator(): Unit = {
            do { i += 1 } while (i < max && !thisSet.contains(i))
        }
        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: FixedSizeBitSetN if this.set.length == that.set.length ⇒
                java.util.Arrays.equals(this.set, that.set)

            case ZeroLengthBitSet ⇒
                var i = 0
                val length = set.length
                while (i < length) { if (set(i) != 0) return false; i += 1 }
                true

            case that: FixedSizeBitSet64 ⇒
                var i = 1
                val length = set.length
                while (i < length) { if (set(i) != 0) return false; i += 1 }
                set(0) == that.set

            case that: FixedSizeBitSet128 ⇒
                var i = 2
                val length = set.length
                while (i < length) { if (set(i) != 0) return false; i += 1 }
                set(0) == that.set1 && set(1) == that.set2

            case _ ⇒
                super.equals(other)
        }
    }

    override def hashCode: Int = {
        val set = this.set
        var result = 1;
        var i = 0
        val max = set.length
        while (i < max) {
            val elementHash = (set(i) ^ (set(i) >>> 32)).toInt
            if (elementHash != 0)
                result = 31 * result + elementHash
            i += 1
        }
        result
    }
}

/** Factory to create fixed size bit arrays. */
object FixedSizeBitSet {

    final val empty: FixedSizeBitSet = ZeroLengthBitSet

    /**
     * Creates a new mutable bit set with a fixed size.
     *
     * @param max The maximum value (inclusive) you may want to store in the set.
     */
    def create(max: Int): FixedSizeBitSet = {
        // Note if max is zero, we may still want to be able to store the value 0!
        if (max < 64) new FixedSizeBitSet64
        else if (max < 128) new FixedSizeBitSet128
        else new FixedSizeBitSetN(new Array[Long]((max / 64) + 1))
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy