diff options
-rw-r--r-- | src/library/scala/BigInt.scala | 12 | ||||
-rw-r--r-- | src/library/scala/Range.scala | 90 | ||||
-rw-r--r-- | src/library/scala/runtime/RichLong.scala | 12 |
3 files changed, 76 insertions, 38 deletions
diff --git a/src/library/scala/BigInt.scala b/src/library/scala/BigInt.scala index a3d1545e2a..c03238680e 100644 --- a/src/library/scala/BigInt.scala +++ b/src/library/scala/BigInt.scala @@ -348,6 +348,18 @@ class BigInt(val bigInteger: BigInteger) extends java.lang.Number { */ def doubleValue = this.bigInteger.doubleValue + /** See <code>Iterator.range</code>. */ + def until(end: BigInt) = Range.BigInt(this, end, BigInt(1)) + + /** See <code>Iterator.range</code>. */ + def until(end: BigInt, step: BigInt) = Range.BigInt(this, end, step) + + /** like <code>until</code>, but includes the last index */ + def to(end: BigInt) = Range.BigInt.inclusive(this, end, BigInt(1)) + + /** like <code>until</code>, 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. * </p><pre> * <b>val</b> r1 = new Range(0, 100, 1) * <b>val</b> veryBig = Math.MAX_INT.toLong + 1 - * <b>val</b> r2 = new LongRange(veryBig, veryBig + 100, 1) + * <b>val</b> r2 = Range.Long(veryBig, veryBig + 100, 1) * assert(r1 sameElements r2.map(_ - veryBig)) * </pre> * * @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 <code>step</code>. */ - 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) {} /** <p> * The <code>Range</code> 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 <code>Iterator.range</code>. */ + def until(end: Long) = Range.Long(x, end, 1L) + + /** See <code>Iterator.range</code>. */ + def until(end: Long, step: Long) = Range.Long(x, end, step) + + /** like <code>until</code>, but includes the last index */ + def to(end: Long) = Range.Long.inclusive(x, end, 1L) + + /** like <code>until</code>, 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 |