summaryrefslogtreecommitdiff
path: root/src/library/scala/Range.scala
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2009-06-05 21:08:02 +0000
committerPaul Phillips <paulp@improving.org>2009-06-05 21:08:02 +0000
commitc260301efef7c83d6fb8094954ae0ae555dc5b0f (patch)
tree1884e94efefa23ad91c5e597cf69f33cde79b6ec /src/library/scala/Range.scala
parent9f6fe27b218039362ce72d90e548e06eed323dc7 (diff)
downloadscala-c260301efef7c83d6fb8094954ae0ae555dc5b0f.tar.gz
scala-c260301efef7c83d6fb8094954ae0ae555dc5b0f.tar.bz2
scala-c260301efef7c83d6fb8094954ae0ae555dc5b0f.zip
Fixed a couple bugs in GenericRange and added t...
Fixed a couple bugs in GenericRange and added the fun and exciting BigDecimal Range. It throws an exception if it ever can't do anything exactly, so it shouldn't be too dangerous to rely upon.
Diffstat (limited to 'src/library/scala/Range.scala')
-rw-r--r--src/library/scala/Range.scala42
1 files changed, 24 insertions, 18 deletions
diff --git a/src/library/scala/Range.scala b/src/library/scala/Range.scala
index 4cf8bac950..3c8138fb87 100644
--- a/src/library/scala/Range.scala
+++ b/src/library/scala/Range.scala
@@ -34,21 +34,19 @@ import util.control.Exception.catching
* @version 2.8
*/
abstract class GenericRange[T]
- (val start: T, val end: T, val step: T)
+ (val start: T, val end: T, val step: T, val isInclusive: Boolean = false)
(implicit num: Integral[T])
extends VectorView[T, Vector[T]] with RangeToString[T] {
import num._
- // 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.)
require(!(step equiv zero))
require(genericLength <= fromInt(Math.MAX_INT), "Implementation restricts ranges to Math.MAX_INT elements.")
+ // By adjusting end based on isInclusive, we can treat all ranges as exclusive.
+ private lazy val trueEnd: T = if (isInclusive) end + step else end
protected def underlying = Vector.empty[T]
/** Create a new range with the start and end values of this range and
@@ -74,9 +72,8 @@ extends VectorView[T, Vector[T]] with RangeToString[T] {
}
lazy val genericLength: T = {
- def plen(start: T, end: T, step: T) =
- if (trueEnd <= start) zero
- else (trueEnd - start - one) / step + one
+ def plen(s: T, e: T, stp: T) =
+ if (e <= s) zero else ((e - s) / stp)
if (step > zero) plen(start, trueEnd, step)
else plen(trueEnd, start, -step)
@@ -88,7 +85,7 @@ extends VectorView[T, Vector[T]] with RangeToString[T] {
def apply(idx: Int): T = applyAt(fromInt(idx))
def applyAt(idx: T): T = {
if (idx < zero || idx >= genericLength) throw new IndexOutOfBoundsException(idx.toString)
- start + idx * step
+ start + (idx * step)
}
// The contains situation makes for some interesting code.
@@ -119,7 +116,7 @@ private[scala] trait RangeToString[T] extends VectorView[T, Vector[T]] {
// if the Range is unduly large. This interacts poorly with the REPL.
override def toString() = {
val MAX_PRINT = 512 // some arbitrary value
- val str = (this take MAX_PRINT).toString
+ val str = (this take MAX_PRINT).mkString(", ")
if (length > MAX_PRINT) str.replaceAll("""\)$""", ", ...)")
else str
@@ -128,18 +125,13 @@ private[scala] trait RangeToString[T] extends VectorView[T, Vector[T]] {
object GenericRange {
- import Numeric._
-
class Inclusive[T](start: T, end: T, step: T)(implicit num: Integral[T])
- extends GenericRange(start, end, step)
- {
- val isInclusive = true
+ extends GenericRange(start, end, step, true) {
def exclusive: Exclusive[T] = new Exclusive(start, end, step)
}
+
class Exclusive[T](start: T, end: T, step: T)(implicit num: Integral[T])
- extends GenericRange(start, end, step)
- {
- val isInclusive = false
+ extends GenericRange(start, end, step, false) {
def inclusive: Inclusive[T] = new Inclusive(start, end, step)
}
@@ -229,10 +221,24 @@ object Range {
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)
}
+ // The BigDecimal and Double ranges will throw an exception if they cannot
+ // step exactly as requested.
+ object BigDecimal {
+ def apply(start: BigDecimal, end: BigDecimal, step: BigDecimal) =
+ GenericRange(start, end, step)(Numeric.BigDecimalAsIfIntegral)
+ def inclusive(start: BigDecimal, end: BigDecimal, step: BigDecimal) =
+ GenericRange.inclusive(start, end, step)(Numeric.BigDecimalAsIfIntegral)
+ }
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)
}
+ object Double {
+ def apply(start: Double, end: Double, step: Double) =
+ BigDecimal(scala.BigDecimal(start), scala.BigDecimal(end), scala.BigDecimal(step))
+ def inclusive(start: Double, end: Double, step: Double) =
+ BigDecimal.inclusive(scala.BigDecimal(start), scala.BigDecimal(end), scala.BigDecimal(step))
+ }
// Illustrating genericity with Int Range, which should have the same behavior
// as the original Range class. However we leave the original Range