Skip to content

Commit 9e4cec8

Browse files
committed
# This is a combination of 2 commits.
# This is the 1st commit message: Optimize BitSet#min and max for case of Ordering.Int # This is the commit message #2: Fix buggy bitset min and max implementations
1 parent 837309f commit 9e4cec8

File tree

3 files changed

+90
-1
lines changed

3 files changed

+90
-1
lines changed

src/library/scala/collection/BitSet.scala

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,62 @@ trait BitSetOps[+C <: BitSet with BitSetOps[C]]
140140

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

143+
override def max[B >: Int](implicit ord: Ordering[B]): Int =
144+
if (Ordering.Int eq ord) {
145+
var i = nwords - 1
146+
var currentWord = 0L
147+
while(i >= 0) {
148+
currentWord = word(i)
149+
if (currentWord != 0L) {
150+
return ((i + 1) * WordLength) - java.lang.Long.numberOfLeadingZeros(currentWord) - 1
151+
}
152+
i -= 1
153+
}
154+
throw new UnsupportedOperationException("empty.max")
155+
} else if (Ordering.Int.reverse eq ord) {
156+
val thisnwords = nwords
157+
var i = 0
158+
var currentWord = 0L
159+
while(i < thisnwords) {
160+
currentWord = word(i)
161+
if (currentWord != 0L) {
162+
return java.lang.Long.numberOfTrailingZeros(currentWord) + (i * WordLength)
163+
}
164+
i += 1
165+
}
166+
throw new UnsupportedOperationException("empty.max")
167+
} else {
168+
super.max(ord)
169+
}
170+
171+
override def min[B >: Int](implicit ord: Ordering[B]): Int =
172+
if (Ordering.Int eq ord) {
173+
val thisnwords = nwords
174+
var i = 0
175+
var currentWord = 0L
176+
while(i < thisnwords) {
177+
currentWord = word(i)
178+
if (currentWord != 0L) {
179+
return java.lang.Long.numberOfTrailingZeros(currentWord) + (i * WordLength)
180+
}
181+
i += 1
182+
}
183+
throw new UnsupportedOperationException("empty.min")
184+
} else if (Ordering.Int.reverse eq ord) {
185+
var i = nwords - 1
186+
var currentWord = 0L
187+
while(i >= 0) {
188+
currentWord = word(i)
189+
if (currentWord != 0L) {
190+
return ((i + 1) * WordLength) - java.lang.Long.numberOfLeadingZeros(currentWord) - 1
191+
}
192+
i -= 1
193+
}
194+
throw new UnsupportedOperationException("empty.min")
195+
} else {
196+
super.min(ord)
197+
}
198+
143199
override def foreach[U](f: Int => U): Unit = {
144200
/* NOTE: while loops are significantly faster as of 2.11 and
145201
one major use case of bitsets is performance. Also, there

src/library/scala/math/Ordering.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ object Ordering extends LowPriorityOrderingImplicits {
234234
override def hashCode(): Int = outer.hashCode() * reverseSeed
235235
}
236236

237-
private final val IntReverse: Ordering[Int] = new Reverse(Ordering.Int)
237+
final val IntReverse: Ordering[Int] = new Reverse(Ordering.Int)
238238

239239
private final class IterableOrdering[CC[X] <: Iterable[X], T](private val ord: Ordering[T]) extends Ordering[CC[T]] {
240240
def compare(x: CC[T], y: CC[T]): Int = {
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package scala.collection.immutable
2+
import org.scalacheck._
3+
import org.scalacheck.Prop._
4+
import org.scalacheck.Prop.BooleanOperators
5+
import Gen._
6+
object BitSetProperties extends Properties("immutable.BitSet") {
7+
override def overrideParameters(p: Test.Parameters): Test.Parameters =
8+
p.withMinSuccessfulTests(500)
9+
.withInitialSeed(42L)
10+
// the top of the range shouldn't be too high, else we may not get enough overlap
11+
implicit val arbitraryBitSet: Arbitrary[BitSet] = Arbitrary(
12+
oneOf(
13+
const(BitSet()),
14+
oneOf(0 to 100).map(i => BitSet(i)),
15+
listOfN(200, oneOf(0 to 10000)).map(_.to(BitSet))
16+
)
17+
)
18+
19+
property("min") = forAll { (bs: BitSet) =>
20+
bs.nonEmpty ==> (bs.min ?= bs.toList.min)
21+
}
22+
property("min reverse") = forAll { (bs: BitSet) =>
23+
bs.nonEmpty ==> (bs.min(Ordering.Int.reverse) ?= bs.toList.min(Ordering.Int.reverse))
24+
}
25+
26+
property("max") = forAll { (bs: BitSet) =>
27+
bs.nonEmpty ==> (bs.max ?= bs.toList.max)
28+
}
29+
30+
property("max reverse") = forAll { (bs: BitSet) =>
31+
bs.nonEmpty ==> (bs.max(Ordering.Int.reverse) ?= bs.toList.max(Ordering.Int.reverse))
32+
}
33+
}

0 commit comments

Comments
 (0)