Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
89 commits
Select commit Hold shift + click to select a range
3640ff4
Don't recheck inherited trait parameters during capture checking
odersky Oct 30, 2023
b65fd3a
Add SeqView to stdlib
odersky Oct 30, 2023
0ada1d4
Add IndexedSeqView to lib
odersky Oct 30, 2023
dbd0c0e
Add CheckedIndexedView to stdlib
odersky Oct 30, 2023
8a60bc2
Add ArrayBuffer (unchecked) to stdlib
odersky Oct 30, 2023
61bf139
Rename annotation source file
odersky Oct 30, 2023
6b91167
Also count @Sealed annotated abstract types as sealed
odersky Oct 30, 2023
d3876ad
Add ArrayBuffer and GrowableBuilder to stdlib
odersky Oct 30, 2023
75c2058
Coarse restriction to disallow local roots in external types
odersky Oct 30, 2023
bb0b774
Require array element types to be sealed
odersky Oct 31, 2023
6b5e494
Add ArrayBuilder.scala in unchanged form to stdlib
odersky Oct 31, 2023
609549c
Make ArrayBuilder capture checked
odersky Oct 31, 2023
d76f092
Add ArrayDeque.scala in unchanged for to stdlib
odersky Oct 31, 2023
e33fc7d
Make ArrayDeque capture checked
odersky Oct 31, 2023
37b41b6
Add Stepper.scala and ArraySeq.scala in unchanged form to stdlib
odersky Oct 31, 2023
ec70a23
Make Stepper capture checked
odersky Oct 31, 2023
24b8a4c
Don't generate capture set variables for self types of pure classes
odersky Oct 31, 2023
6ba065e
Make ArraySeq capture checked
odersky Oct 31, 2023
bb65046
Add mutable/IndexedSeq.scala to stdlib
odersky Oct 31, 2023
c811e35
Add Queue.scala to stdlib
odersky Oct 31, 2023
f0a1241
Add PriorityQueue.scala to stdlib
odersky Oct 31, 2023
4ac2139
Make PriorityQueue capture checked
odersky Oct 31, 2023
4795ef8
Add Stack.scala and ReusableBuilder.scala to stdlib
odersky Oct 31, 2023
0bf1903
Add Set.scala to stdlib
odersky Oct 31, 2023
35e7166
Make collection/Set capture checked
odersky Oct 31, 2023
14b5093
Add mutable/immutable Set to stdlib
odersky Oct 31, 2023
1f414a3
Make mutable/immutable Set capture checked
odersky Oct 31, 2023
f92c881
Add BitSet classes to stdlib (capture checked)
odersky Oct 31, 2023
6a831aa
Add SortedSet classes to stdlib
odersky Oct 31, 2023
3b6b684
Add Factory.scala to stdlib
odersky Oct 31, 2023
5852a76
Make Factory capture checked
odersky Oct 31, 2023
c9cb044
Avoid reporting post check messages several times
odersky Oct 31, 2023
0a350ea
Add SortedSet and BitSet to stdlib (capture checked)
odersky Oct 31, 2023
06744c2
Add BuildFrom.scala to stdlib
odersky Oct 31, 2023
51c9385
Make BuildFrom capture checked
odersky Oct 31, 2023
238317c
Add WithFilter.scala to stdlib
odersky Nov 1, 2023
1b757b9
Make WithFilter capture checked
odersky Nov 1, 2023
4956e6d
Add ArrayOps to stdlib
odersky Nov 1, 2023
7273c4d
Don't flag wildcard array arguments for not being sealed
odersky Nov 1, 2023
b67422e
Fix isPureClass test
odersky Nov 1, 2023
c64c057
Make sealed an annotation
odersky Nov 1, 2023
2083af3
Make ArrayOps capture checked
odersky Nov 1, 2023
9909d95
Add LazyZipOps and some other files to stdlib
odersky Nov 1, 2023
caeac20
Add mutable/TreeSet.scala to stdlib
odersky Nov 1, 2023
1f4f875
Add mutable and concurrent Map to stdlib
odersky Nov 1, 2023
3dc0eae
Add HashMaps to stdlib
odersky Nov 1, 2023
20f3a97
Add LongMap + friends to stdlib
odersky Nov 1, 2023
ae605d6
Add WeakHashMap and MultiMap to stdlib
odersky Nov 1, 2023
b0d3bbc
Add UnrolledBuffer to stdlib
odersky Nov 1, 2023
09e0868
Add mutable TreeMap and RedBlackTree to stdlib
odersky Nov 1, 2023
0888c40
Add mutable SortedMap and SeqMap to stdlib
odersky Nov 1, 2023
a76129f
Add AnyRefMap to stdlib
odersky Nov 1, 2023
73f9474
Add CollisionProofHashMap to stdlib
odersky Nov 1, 2023
ffbaf1f
Avoid infinite recursions when checking F-bounded types
odersky Nov 1, 2023
7304ba6
Add HashTable.scala to stdlib
odersky Nov 1, 2023
f3ed83b
Add HashSet to stdlib
odersky Nov 1, 2023
7d2f133
Add OpenHashMap to stdlib
odersky Nov 1, 2023
9021cfd
Add MapView to stdlib
odersky Nov 1, 2023
cb66516
Add StrictOptimizedMapOps to stdlib
odersky Nov 1, 2023
be20a7c
Add collection/SortedMap to stdlib
odersky Nov 1, 2023
766b020
Add more Ops classes to stdlib
odersky Nov 1, 2023
36975c1
Add remaining collection classes to stdlib
odersky Nov 1, 2023
b899f8d
Add immutable ArraySeq to stdlib
odersky Nov 2, 2023
1f3fe9e
Add immutable HashSet and HashMap to stdlib
odersky Nov 2, 2023
528c249
Add immutable IntMap and LongMap to stdlib
odersky Nov 2, 2023
02c6281
Add immutable ListSet and ListMap to stdlib
odersky Nov 2, 2023
2cb34e5
Add immutable Map to stdlib
odersky Nov 2, 2023
a1fc706
Add Range classes to stdlib
odersky Nov 2, 2023
5817d40
Add immutable Queue to stdlib
odersky Nov 2, 2023
c16afe5
Add immutable RedBlackTree to stdlib
odersky Nov 2, 2023
d526e10
Add immutable SeqMap to stdlib
odersky Nov 2, 2023
26dde72
Add immutable SortedMap to stdlib
odersky Nov 2, 2023
a08460d
Add immutable StrictOptimizedSeqOps to stdlib
odersky Nov 2, 2023
c66c833
Add Vector and VectorMap to stdlib
odersky Nov 2, 2023
eea6bca
Add immutable TreeSet and TreeMap to stdlib
odersky Nov 2, 2023
4625afc
Add immutable TreeSeqMap to stdlib
odersky Nov 2, 2023
9ba2c39
Add unchecked LazyList to stdlib
odersky Nov 2, 2023
bf58e2b
Survive "cannot establish a reference" errors in TreeTypeMap
odersky Nov 2, 2023
6ae16a4
Add checked LazyList to stdlib
odersky Nov 2, 2023
0acfb8c
Rename LazyList to LazyListIterable
odersky Nov 2, 2023
fd88dc1
Allow deep subtypes when compiling stdlib test
odersky Nov 3, 2023
9ae3ee7
Add generic/IsSeq to stdlib
odersky Nov 3, 2023
f8f2050
Make SubstRecThis typemap idempotent
odersky Nov 3, 2023
b19f981
Capturecheck all files in generic
odersky Nov 3, 2023
868d65b
Drop an unsafeAssumePure in Iterator
odersky Nov 3, 2023
f4066c0
Better error message for capture errors involving self types
odersky Nov 3, 2023
e22744d
Add sealed refs test and fix check files of other tests
odersky Nov 4, 2023
cfec1d0
Simplify CapturedVars phase
odersky Nov 4, 2023
5e49b12
Refine isParametric tests
odersky Nov 4, 2023
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add BitSet classes to stdlib (capture checked)
  • Loading branch information
odersky committed Nov 4, 2023
commit f92c881562dedd6da200617f4f222f84e24c5525
348 changes: 348 additions & 0 deletions tests/pos-special/stdlib/collection/BitSet.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,348 @@
/*
* Scala (https://www.scala-lang.org)
*
* Copyright EPFL and Lightbend, Inc.
*
* Licensed under Apache License 2.0
* (http://www.apache.org/licenses/LICENSE-2.0).
*
* See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*/

package scala
package collection

import java.io.{ObjectInputStream, ObjectOutputStream}

import scala.annotation.nowarn
import scala.collection.Stepper.EfficientSplit
import scala.collection.mutable.Builder
import language.experimental.captureChecking

/** Base type of bitsets.
*
* This trait provides most of the operations of a `BitSet` independently of its representation.
* It is inherited by all concrete implementations of bitsets.
*
* @define bitsetinfo
* Bitsets are sets of non-negative integers which are represented as
* variable-size arrays of bits packed into 64-bit words. The lower bound of memory footprint of a bitset is
* determined by the largest number stored in it.
* @define coll bitset
* @define Coll `BitSet`
*/
trait BitSet extends SortedSet[Int] with BitSetOps[BitSet] {
override protected def fromSpecific(coll: IterableOnce[Int]^): BitSet = bitSetFactory.fromSpecific(coll)
override protected def newSpecificBuilder: Builder[Int, BitSet] = bitSetFactory.newBuilder
override def empty: BitSet = bitSetFactory.empty
@nowarn("""cat=deprecation&origin=scala\.collection\.Iterable\.stringPrefix""")
override protected[this] def stringPrefix = "BitSet"
override def unsorted: Set[Int] = this
}

@SerialVersionUID(3L)
object BitSet extends SpecificIterableFactory[Int, BitSet] {
private[collection] final val ordMsg = "No implicit Ordering[${B}] found to build a SortedSet[${B}]. You may want to upcast to a Set[Int] first by calling `unsorted`."
private[collection] final val zipOrdMsg = "No implicit Ordering[${B}] found to build a SortedSet[(Int, ${B})]. You may want to upcast to a Set[Int] first by calling `unsorted`."

def empty: BitSet = immutable.BitSet.empty
def newBuilder: Builder[Int, BitSet] = immutable.BitSet.newBuilder
def fromSpecific(it: IterableOnce[Int]): BitSet = immutable.BitSet.fromSpecific(it)

@SerialVersionUID(3L)
private[collection] abstract class SerializationProxy(@transient protected val coll: BitSet) extends Serializable {

@transient protected var elems: Array[Long] = _

private[this] def writeObject(out: ObjectOutputStream): Unit = {
out.defaultWriteObject()
val nwords = coll.nwords
out.writeInt(nwords)
var i = 0
while(i < nwords) {
out.writeLong(coll.word(i))
i += 1
}
}

private[this] def readObject(in: ObjectInputStream): Unit = {
in.defaultReadObject()
val nwords = in.readInt()
elems = new Array[Long](nwords)
var i = 0
while(i < nwords) {
elems(i) = in.readLong()
i += 1
}
}

protected[this] def readResolve(): Any
}
}

/** Base implementation type of bitsets */
trait BitSetOps[+C <: BitSet with BitSetOps[C]]
extends SortedSetOps[Int, SortedSet, C] { self =>
import BitSetOps._

def bitSetFactory: SpecificIterableFactory[Int, C]

def unsorted: Set[Int]

final def ordering: Ordering[Int] = Ordering.Int

/** The number of words (each with 64 bits) making up the set */
protected[collection] def nwords: Int

/** The words at index `idx`, or 0L if outside the range of the set
* '''Note:''' requires `idx >= 0`
*/
protected[collection] def word(idx: Int): Long

/** Creates a new set of this kind from an array of longs
*/
protected[collection] def fromBitMaskNoCopy(elems: Array[Long]): C

def contains(elem: Int): Boolean =
0 <= elem && (word(elem >> LogWL) & (1L << elem)) != 0L

def iterator: Iterator[Int] = iteratorFrom(0)

def iteratorFrom(start: Int): Iterator[Int] = new AbstractIterator[Int] {
private[this] var currentPos = if (start > 0) start >> LogWL else 0
private[this] var currentWord = if (start > 0) word(currentPos) & (-1L << (start & (WordLength - 1))) else word(0)
final override def hasNext: Boolean = {
while (currentWord == 0) {
if (currentPos + 1 >= nwords) return false
currentPos += 1
currentWord = word(currentPos)
}
true
}
final override def next(): Int = {
if (hasNext) {
val bitPos = java.lang.Long.numberOfTrailingZeros(currentWord)
currentWord &= currentWord - 1
(currentPos << LogWL) + bitPos
} else Iterator.empty.next()
}
}

override def stepper[S <: Stepper[_]](implicit shape: StepperShape[Int, S]): S with EfficientSplit = {
val st = scala.collection.convert.impl.BitSetStepper.from(this)
val r =
if (shape.shape == StepperShape.IntShape) st
else {
assert(shape.shape == StepperShape.ReferenceShape, s"unexpected StepperShape: $shape")
AnyStepper.ofParIntStepper(st)
}
r.asInstanceOf[S with EfficientSplit]
}

override def size: Int = {
var s = 0
var i = nwords
while (i > 0) {
i -= 1
s += java.lang.Long.bitCount(word(i))
}
s
}

override def isEmpty: Boolean = 0 until nwords forall (i => word(i) == 0)

@inline private[this] def smallestInt: Int = {
val thisnwords = nwords
var i = 0
while(i < thisnwords) {
val currentWord = word(i)
if (currentWord != 0L) {
return java.lang.Long.numberOfTrailingZeros(currentWord) + (i * WordLength)
}
i += 1
}
throw new UnsupportedOperationException("empty.smallestInt")
}

@inline private[this] def largestInt: Int = {
var i = nwords - 1
while(i >= 0) {
val currentWord = word(i)
if (currentWord != 0L) {
return ((i + 1) * WordLength) - java.lang.Long.numberOfLeadingZeros(currentWord) - 1
}
i -= 1
}
throw new UnsupportedOperationException("empty.largestInt")
}

override def max[B >: Int](implicit ord: Ordering[B]): Int =
if (Ordering.Int eq ord) largestInt
else if (Ordering.Int isReverseOf ord) smallestInt
else super.max(ord)


override def min[B >: Int](implicit ord: Ordering[B]): Int =
if (Ordering.Int eq ord) smallestInt
else if (Ordering.Int isReverseOf ord) largestInt
else super.min(ord)

override def foreach[U](f: Int => U): Unit = {
/* NOTE: while loops are significantly faster as of 2.11 and
one major use case of bitsets is performance. Also, there
is nothing to do when all bits are clear, so use that as
the inner loop condition. */
var i = 0
while (i < nwords) {
var w = word(i)
var j = i * WordLength
while (w != 0L) {
if ((w&1L) == 1L) f(j)
w = w >>> 1
j += 1
}
i += 1
}
}

/** Creates a bit mask for this set as a new array of longs
*/
def toBitMask: Array[Long] = {
val a = new Array[Long](nwords)
var i = a.length
while(i > 0) {
i -= 1
a(i) = word(i)
}
a
}

def rangeImpl(from: Option[Int], until: Option[Int]): C = {
val a = coll.toBitMask
val len = a.length
if (from.isDefined) {
val f = from.get
val w = f >> LogWL
val b = f & (WordLength - 1)
if (w >= 0) {
java.util.Arrays.fill(a, 0, math.min(w, len), 0)
if (b > 0 && w < len) a(w) &= ~((1L << b) - 1)
}
}
if (until.isDefined) {
val u = until.get
val w = u >> LogWL
val b = u & (WordLength - 1)
if (w < len) {
java.util.Arrays.fill(a, math.max(w + 1, 0), len, 0)
if (w >= 0) a(w) &= (1L << b) - 1
}
}
coll.fromBitMaskNoCopy(a)
}

override def concat(other: collection.IterableOnce[Int]): C = other match {
case otherBitset: BitSet =>
val len = coll.nwords max otherBitset.nwords
val words = new Array[Long](len)
for (idx <- 0 until len)
words(idx) = this.word(idx) | otherBitset.word(idx)
fromBitMaskNoCopy(words)
case _ => super.concat(other)
}

override def intersect(other: Set[Int]): C = other match {
case otherBitset: BitSet =>
val len = coll.nwords min otherBitset.nwords
val words = new Array[Long](len)
for (idx <- 0 until len)
words(idx) = this.word(idx) & otherBitset.word(idx)
fromBitMaskNoCopy(words)
case _ => super.intersect(other)
}

abstract override def diff(other: Set[Int]): C = other match {
case otherBitset: BitSet =>
val len = coll.nwords
val words = new Array[Long](len)
for (idx <- 0 until len)
words(idx) = this.word(idx) & ~otherBitset.word(idx)
fromBitMaskNoCopy(words)
case _ => super.diff(other)
}

/** Computes the symmetric difference of this bitset and another bitset by performing
* a bitwise "exclusive-or".
*
* @param other the other bitset to take part in the symmetric difference.
* @return a bitset containing those bits of this
* bitset or the other bitset that are not contained in both bitsets.
*/
def xor(other: BitSet): C = {
val len = coll.nwords max other.nwords
val words = new Array[Long](len)
for (idx <- 0 until len)
words(idx) = coll.word(idx) ^ other.word(idx)
coll.fromBitMaskNoCopy(words)
}

@`inline` final def ^ (other: BitSet): C = xor(other)

/**
* Builds a new bitset by applying a function to all elements of this bitset
* @param f the function to apply to each element.
* @return a new bitset resulting from applying the given function ''f'' to
* each element of this bitset and collecting the results
*/
def map(f: Int => Int): C = fromSpecific(new View.Map(this, f))

def flatMap(f: Int => IterableOnce[Int]): C = fromSpecific(new View.FlatMap(this, f))

def collect(pf: PartialFunction[Int, Int]): C = fromSpecific(super[SortedSetOps].collect(pf))

override def partition(p: Int => Boolean): (C, C) = {
val left = filter(p)
(left, this &~ left)
}
}

object BitSetOps {

/* Final vals can sometimes be inlined as constants (faster) */
private[collection] final val LogWL = 6
private[collection] final val WordLength = 64
private[collection] final val MaxSize = (Int.MaxValue >> LogWL) + 1

private[collection] def updateArray(elems: Array[Long], idx: Int, w: Long): Array[Long] = {
var len = elems.length
while (len > 0 && (elems(len - 1) == 0L || w == 0L && idx == len - 1)) len -= 1
var newlen = len
if (idx >= newlen && w != 0L) newlen = idx + 1
val newelems = new Array[Long](newlen)
Array.copy(elems, 0, newelems, 0, len)
if (idx < newlen) newelems(idx) = w
else assert(w == 0L)
newelems
}

private[collection] def computeWordForFilter(pred: Int => Boolean, isFlipped: Boolean, oldWord: Long, wordIndex: Int): Long =
if (oldWord == 0L) 0L else {
var w = oldWord
val trailingZeroes = java.lang.Long.numberOfTrailingZeros(w)
var jmask = 1L << trailingZeroes
var j = wordIndex * BitSetOps.WordLength + trailingZeroes
val maxJ = (wordIndex + 1) * BitSetOps.WordLength - java.lang.Long.numberOfLeadingZeros(w)
while (j != maxJ) {
if ((w & jmask) != 0L) {
if (pred(j) == isFlipped) {
// j did not pass the filter here
w = w & ~jmask
}
}
jmask = jmask << 1
j += 1
}
w
}
}
Loading