summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2009-10-18 13:23:17 +0000
committerPaul Phillips <paulp@improving.org>2009-10-18 13:23:17 +0000
commita1a8e9261e7f95d93dddcd5c2c049791691020f3 (patch)
tree37d92544223f312185a6b8e7c83d97a16bf36f21 /src
parentaaae8db368ea3d67cfc60df471fe908abb0f4fa2 (diff)
downloadscala-a1a8e9261e7f95d93dddcd5c2c049791691020f3.tar.gz
scala-a1a8e9261e7f95d93dddcd5c2c049791691020f3.tar.bz2
scala-a1a8e9261e7f95d93dddcd5c2c049791691020f3.zip
Made GenericRange covariant.
Added additional equality logic I realized was necessary.
Diffstat (limited to 'src')
-rw-r--r--src/library/scala/collection/immutable/GenericRange.scala55
-rw-r--r--src/library/scala/runtime/RichDouble.scala8
2 files changed, 41 insertions, 22 deletions
diff --git a/src/library/scala/collection/immutable/GenericRange.scala b/src/library/scala/collection/immutable/GenericRange.scala
index 7fe00a9427..9736817035 100644
--- a/src/library/scala/collection/immutable/GenericRange.scala
+++ b/src/library/scala/collection/immutable/GenericRange.scala
@@ -36,7 +36,7 @@ import util.Hashable
* @version 2.8
*/
@experimental
-abstract class GenericRange[T]
+abstract class GenericRange[+T]
(val start: T, val end: T, val step: T, val isInclusive: Boolean)
(implicit num: Integral[T])
extends VectorView[T, collection.immutable.Vector[T]]
@@ -52,24 +52,20 @@ extends VectorView[T, collection.immutable.Vector[T]]
// inclusive/exclusiveness captured this way because we do not have any
// concept of a "unit", we can't just add an epsilon to an exclusive
// endpoint to make it inclusive (as can be done with the int-based Range.)
- protected def limitTest(x: T) = !isEmpty && isInclusive && equiv(x, end)
+ protected def limitTest[U >: T](x: U)(implicit unum: Integral[U]) =
+ !isEmpty && isInclusive && unum.equiv(x, end)
+
protected def underlying = collection.immutable.Vector.empty[T]
- protected def divides(x: T, by: T) = equiv(x % by, zero)
/** Create a new range with the start and end values of this range and
* a new <code>step</code>.
*/
- def by(newStep: T): GenericRange[T] = copy(start, end, newStep)
+ def by[U >: T](newStep: U)(implicit unum: Integral[U]): GenericRange[U] =
+ copy(start, end, newStep)
/** Create a copy of this range.
*/
- def copy(start: T, end: T, step: T): GenericRange[T]
-
- /** Shift or multiply the entire range by some constant.
- */
- def -(shift: T) = this + negate(shift)
- def +(shift: T) = copy(this.start + shift, this.end + shift, step)
- def *(mult: T) = copy(this.start * mult, this.end * mult, step * mult)
+ def copy[U >: T](start: U, end: U, step: U)(implicit unum: Integral[U]): GenericRange[U]
override def foreach[U](f: T => U) {
var i = start
@@ -109,32 +105,42 @@ extends VectorView[T, collection.immutable.Vector[T]]
if (isInclusive) start > end
else start >= end
- // Since apply(Int) already exists, we are not allowed apply(T) since
- // they erase to the same thing.
- 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)
+ def apply(idx: Int): T = {
+ if (idx < 0 || idx >= length) throw new IndexOutOfBoundsException(idx.toString)
+ else start + (fromInt(idx) * step)
}
// a well-typed contains method.
- def containsTyped(x: T): Boolean =
+ def containsTyped[U >: T](x: U)(implicit unum: Integral[U]): Boolean = {
+ import unum._
+ def divides(d: U, by: U) = equiv(d % by, zero)
+
limitTest(x) || (
if (step > zero)
(start <= x) && (x < end) && divides(x - start, step)
else
(start >= x) && (x > end) && divides(start - x, step)
)
+ }
// The contains situation makes for some interesting code.
// I am not aware of any way to avoid a cast somewhere, because
// contains must take an Any.
override def contains(x: Any): Boolean =
- try containsTyped(x.asInstanceOf[T])
+ try {
+ // if we don't verify that x == typedX, then a range
+ // of e.g. Longs will appear to contain an Int because
+ // the cast will perform the conversion. (As of this writing
+ // it is anticipated that in scala 2.8, 5L != 5 although
+ // this is not yet implemented.)
+ val typedX = x.asInstanceOf[T]
+ containsTyped(typedX) && (x == typedX)
+ }
catch { case _: ClassCastException => super.contains(x) }
+ override lazy val hashCode = super.hashCode()
override def equals(other: Any) = other match {
- case x: GenericRange[_] => (genericLength == x.genericLength) && (genericLength match {
+ case x: GenericRange[_] => (length == x.length) && (length match {
case 0 => true
case 1 => x.start == start
case n => x.start == start && x.step == step
@@ -147,18 +153,23 @@ extends VectorView[T, collection.immutable.Vector[T]]
}
}
+
object GenericRange
{
class Inclusive[T](start: T, end: T, step: T)(implicit num: Integral[T])
extends GenericRange(start, end, step, true) {
+ def copy[U >: T](start: U, end: U, step: U)(implicit unum: Integral[U]): Inclusive[U] =
+ GenericRange.inclusive(start, end, step)
+
def exclusive: Exclusive[T] = GenericRange(start, end, step)
- def copy(start: T, end: T, step: T): Inclusive[T] = GenericRange.inclusive(start, end, step)
}
class Exclusive[T](start: T, end: T, step: T)(implicit num: Integral[T])
extends GenericRange(start, end, step, false) {
+ def copy[U >: T](start: U, end: U, step: U)(implicit unum: Integral[U]): Exclusive[U] =
+ GenericRange(start, end, step)
+
def inclusive: Inclusive[T] = GenericRange.inclusive(start, end, step)
- def copy(start: T, end: T, step: T): Exclusive[T] = GenericRange(start, end, step)
}
def apply[T](start: T, end: T, step: T)(implicit num: Integral[T]): Exclusive[T] =
diff --git a/src/library/scala/runtime/RichDouble.scala b/src/library/scala/runtime/RichDouble.scala
index a40b35d8e9..3d18aefce2 100644
--- a/src/library/scala/runtime/RichDouble.scala
+++ b/src/library/scala/runtime/RichDouble.scala
@@ -27,6 +27,14 @@ final class RichDouble(x: Double) extends Proxy with Ordered[Double] {
def ceil: Double = Math.ceil(x)
def floor: Double = Math.floor(x)
+ /** !!! At the time I wrote these Double ranges, BigDecimal(0.17) == 0.17d. Since
+ * this is no longer true, these ranges need to operate on Doubles, else
+ * (0.0 to 1.0 by 0.1).contains(0.1) will be false under the anticipated 2.8
+ * equality scheme. They only operate on BigDecimals because I wasn't 100%
+ * sure about when operations on Doubles are guaranteed to be exact and using
+ * BigDecimal seemed the conservative route.
+ */
+
/** See <code>BigDecimal.until</code>. */
def until(end: Double): Range.Partial[Double, GenericRange.Exclusive[BigDecimal]] =
new Range.Partial(until(end, _))