
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