diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/library/scala/collection/immutable/GenericRange.scala | 55 | ||||
-rw-r--r-- | src/library/scala/runtime/RichDouble.scala | 8 |
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, _)) |