From e9a2726b588273bd9d126f58a23048c14f7d35cb Mon Sep 17 00:00:00 2001
From: Paul Phillips Iterator.range
. */
+ def until(end: BigInt) = Range.BigInt(this, end, BigInt(1))
+
+ /** See Iterator.range
. */
+ def until(end: BigInt, step: BigInt) = Range.BigInt(this, end, step)
+
+ /** like until
, but includes the last index */
+ def to(end: BigInt) = Range.BigInt.inclusive(this, end, BigInt(1))
+
+ /** like until
, but includes the last index */
+ def to(end: BigInt, step: BigInt) = Range.BigInt.inclusive(this, end, step)
+
/** Returns the decimal String representation of this BigInt.
*/
override def toString(): String = this.bigInteger.toString()
diff --git a/src/library/scala/Range.scala b/src/library/scala/Range.scala
index dbd4f82f69..b2cb8c07c4 100644
--- a/src/library/scala/Range.scala
+++ b/src/library/scala/Range.scala
@@ -19,24 +19,30 @@ import collection.generic.VectorView
* It must be supplied with Integral and Ordering implementations
* of the range type.
*
- * Built-in incarnations include BigIntRange and LongRange.
+ * Factories for likely types include Range.BigInt and Range.Long.
+ * Range.Int exists for completeness, but the Int-based scala.Range
+ * should be more performant.
*
* val r1 = new Range(0, 100, 1) * val veryBig = Math.MAX_INT.toLong + 1 - * val r2 = new LongRange(veryBig, veryBig + 100, 1) + * val r2 = Range.Long(veryBig, veryBig + 100, 1) * assert(r1 sameElements r2.map(_ - veryBig)) ** * @author Paul Phillips * @version 2.8 */ -class GenericRange[T] +abstract class GenericRange[T] (val start: T, val end: T, val step: T) (implicit num: Integral[T], ord: Ordering[T]) extends VectorView[T, Vector[T]] with RangeToString[T] { import num._ import ord._ + // this lets us pretend all ranges are exclusive + val isInclusive: Boolean + private val trueEnd = if (isInclusive) end + one else end + // todo? - we could lift the length restriction by implementing a range as a sequence of // subranges and limiting the subranges to MAX_INT. There's no other way around it because // the generics we inherit assume integer-based indexing (as well they should.) @@ -48,17 +54,19 @@ extends VectorView[T, Vector[T]] with RangeToString[T] { /** Create a new range with the start and end values of this range and * a new
step
.
*/
- def by(step: T): GenericRange[T] = new GenericRange(start, end, step)
+ def by(step: T): GenericRange[T] =
+ if (isInclusive) GenericRange.inclusive(start, end, step)
+ else GenericRange(start, end, step)
override def foreach[U](f: T => U) {
var i = start
if (step > zero) {
- while (i < end) {
+ while (i < trueEnd) {
f(i)
i = i + step
}
} else {
- while (i > end) {
+ while (i > trueEnd) {
f(i)
i = i + step
}
@@ -67,13 +75,11 @@ extends VectorView[T, Vector[T]] with RangeToString[T] {
lazy val genericLength: T = {
def plen(start: T, end: T, step: T) =
- if (end <= start) zero
- else (end - start - one) / step + one
- // if (lteq(end, start)) zero
- // else plus(quot((minus(minus(end, start), one)), step), one)
+ if (trueEnd <= start) zero
+ else (trueEnd - start - one) / step + one
- if (step > zero) plen(start, end, step)
- else plen(end, start, -step)
+ if (step > zero) plen(start, trueEnd, step)
+ else plen(trueEnd, start, -step)
}
lazy val length: Int = toInt(genericLength)
@@ -91,11 +97,9 @@ extends VectorView[T, Vector[T]] with RangeToString[T] {
try { _x.asInstanceOf[T] }
catch { case _: ClassCastException => return false }
- if (step > zero) start <= x && x < end
- else start >= x && x > end
+ if (step > zero) start <= x && x < trueEnd
+ else start >= x && x > trueEnd
}
-
- def inclusive = GenericRange.inclusive(start, end, step)
}
private[scala] trait RangeToString[T] extends VectorView[T, Vector[T]] {
@@ -110,39 +114,31 @@ private[scala] trait RangeToString[T] extends VectorView[T, Vector[T]] {
}
}
+
object GenericRange {
import Numeric._
import Ordering._
- // This is very ugly, but modelled on the existing range class for now
- private class Inclusive[T](start: T, end0: T, step: T)(implicit num: Integral[T], ord: Ordering[T])
- extends GenericRange(
- start,
- if (ord.gt(step, num.zero)) num.plus(end0, num.one) else num.minus(end0, num.one),
- step)
+ class Inclusive[T](start: T, end: T, step: T)(implicit num: Integral[T], ord: Ordering[T])
+ extends GenericRange(start, end, step)
{
- self =>
- override def by(step: T): GenericRange[T] = new Inclusive(start, end0, step)
+ val isInclusive = true
+ def exclusive: Exclusive[T] = new Exclusive(start, end, step)
+ }
+ class Exclusive[T](start: T, end: T, step: T)(implicit num: Integral[T], ord: Ordering[T])
+ extends GenericRange(start, end, step)
+ {
+ val isInclusive = false
+ def inclusive: Inclusive[T] = new Inclusive(start, end, step)
}
def apply[T](start: T, end: T, step: T)(implicit num: Integral[T], ord: Ordering[T]) =
- new GenericRange(start, end, step)
+ new Exclusive(start, end, step)
- def inclusive[T](start: T, end: T, step: T)(implicit num: Integral[T], ord: Ordering[T]): GenericRange[T] =
- new GenericRange.Inclusive(start, end, step)
+ def inclusive[T](start: T, end: T, step: T)(implicit num: Integral[T], ord: Ordering[T]) =
+ new Inclusive(start, end, step)
}
-class BigIntRange(start: BigInt, end: BigInt, step: BigInt)
-extends GenericRange(start, end, step)(Numeric.BigIntIsIntegral, Ordering.BigInt) {}
-class LongRange(start: Long, end: Long, step: Long)
-extends GenericRange(start, end, step)(Numeric.LongIsIntegral, Ordering.Long) {}
-
-// Illustrating genericity with IntRange, which should have the same behavior
-// as the original Range class. However we leave the original Range
-// indefinitely, for performance and because the compiler seems to bootstrap
-// off it and won't do so with our parameterized version without modifications.
-class IntRange(start: Int, end: Int, step: Int)
-extends GenericRange(start, end, step)(Numeric.IntIsIntegral, Ordering.Int) {}
/**
* The Range
class represents integer values in range
@@ -217,4 +213,22 @@ object Range {
def inclusive(start: Int, end: Int, step: Int): Range =
new Range.Inclusive(start, end, step)
+
+ object BigInt {
+ def apply(start: BigInt, end: BigInt, step: BigInt) = GenericRange(start, end, step)
+ def inclusive(start: BigInt, end: BigInt, step: BigInt) = GenericRange.inclusive(start, end, step)
+ }
+ object Long {
+ def apply(start: Long, end: Long, step: Long) = GenericRange(start, end, step)
+ def inclusive(start: Long, end: Long, step: Long) = GenericRange.inclusive(start, end, step)
+ }
+
+ // Illustrating genericity with Int Range, which should have the same behavior
+ // as the original Range class. However we leave the original Range
+ // indefinitely, for performance and because the compiler seems to bootstrap
+ // off it and won't do so with our parameterized version without modifications.
+ object Int {
+ def apply(start: Int, end: Int, step: Int) = GenericRange(start, end, step)
+ def inclusive(start: Int, end: Int, step: Int) = GenericRange.inclusive(start, end, step)
+ }
}
diff --git a/src/library/scala/runtime/RichLong.scala b/src/library/scala/runtime/RichLong.scala
index 78784170f3..5eddaf0ec3 100644
--- a/src/library/scala/runtime/RichLong.scala
+++ b/src/library/scala/runtime/RichLong.scala
@@ -20,6 +20,18 @@ final class RichLong(x: Long) extends Proxy with Ordered[Long] {
// Ordered[Long].compare
def compare(y: Long): Int = if (x < y) -1 else if (x > y) 1 else 0
+ /** See Iterator.range
. */
+ def until(end: Long) = Range.Long(x, end, 1L)
+
+ /** See Iterator.range
. */
+ def until(end: Long, step: Long) = Range.Long(x, end, step)
+
+ /** like until
, but includes the last index */
+ def to(end: Long) = Range.Long.inclusive(x, end, 1L)
+
+ /** like until
, but includes the last index */
+ def to(end: Long, step: Long) = Range.Long.inclusive(x, end, step)
+
def min(y: Long): Long = if (x < y) x else y
def max(y: Long): Long = if (x > y) x else y
def abs: Long = if (x < 0) -x else x
--
cgit v1.2.3