Skip to content

Commit

Permalink
Merge pull request #636 from dmurvihill/choose-big-int
Browse files Browse the repository at this point in the history
Add choose[BigInt]
  • Loading branch information
ashawley authored May 26, 2020
2 parents 308f0ef + 5da0cd4 commit 433b7a2
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 0 deletions.
19 changes: 19 additions & 0 deletions jvm/src/test/scala/org/scalacheck/GenSpecification.scala
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,25 @@ object GenSpecification extends Properties("Gen") with GenSpecificationVersionSp
}
}

property("choose-big-int") = forAll(
nonEmptyContainerOf[Array, Byte](arbitrary[Byte]).map(BigInt(_)),
nonEmptyContainerOf[Array, Byte](arbitrary[Byte]).map(BigInt(_))
) { (l: BigInt, h: BigInt) =>
Try(choose(l, h)) match {
case Success(g) => forAll(g) { x => l <= x && x <= h }
case Failure(e: Choose.IllegalBoundsError[_]) => Prop(l > h)
case Failure(e) => throw e
}
}

property("Gen.choose(BigInt( 2^(2^18 - 1)), BigInt(-2^(2^18 - 1)))") = {
val (l, h) = (BigInt(-2).pow(262143),
BigInt( 2).pow(262143))
Prop.forAllNoShrink(Gen.choose(l, h)) { x =>
l <= x && x <= h
}
}

property("choose-xmap") = {
implicit val chooseDate: Choose[Date] =
Choose.xmap[Long, Date](new Date(_), _.getTime)
Expand Down
19 changes: 19 additions & 0 deletions src/main/scala/org/scalacheck/Gen.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import scala.collection.mutable.ArrayBuffer
import scala.concurrent.duration.{Duration, FiniteDuration}

import java.util.{ Calendar, UUID }
import java.nio.ByteBuffer

sealed abstract class Gen[+T] extends Serializable { self =>

Expand Down Expand Up @@ -446,6 +447,24 @@ object Gen extends GenArities with GenVersionSpecific {
implicit val chooseFiniteDuration: Choose[FiniteDuration] =
Choose.xmap[Long, FiniteDuration](Duration.fromNanos, _.toNanos)

implicit object chooseBigInt extends Choose[BigInt] {
def choose(low: BigInt, high: BigInt): Gen[BigInt] =
if (low > high) throw new IllegalBoundsError(low, high)
else if (low == high) low
else {
val range = high - low
Gen.containerOfN[Array, Long](
(range.bitLength + 64 - 1) / 64,
Gen.choose(Long.MinValue, Long.MaxValue)
).map(longs => {
longs(0) = longs(0) & (-1L >>> (64 - range.bitLength % 64))
val bb = ByteBuffer.allocate(longs.length * 8)
longs.foreach(bb.putLong)
BigInt(1, bb.array()) + low
}).filter(n => high >= n)
}
}

/** Transform a Choose[T] to a Choose[U] where T and U are two isomorphic
* types whose relationship is described by the provided transformation
* functions. (exponential functor map) */
Expand Down

0 comments on commit 433b7a2

Please sign in to comment.