package scala.collection.immutable
import scala.collection.parallel.immutable.ParRange
import annotation.bridge
@SerialVersionUID(7618862778670199309L)
class Range(val start: Int, val end: Int, val step: Int)
extends IndexedSeq[Int]
with collection.CustomParallelizable[Int, ParRange]
with Serializable
{
override def par = new ParRange(this)
private lazy val numRangeElements: Int = Range.count(start, end, step, isInclusive)
protected def copy(start: Int, end: Int, step: Int): Range = new Range(start, end, step)
def by(step: Int): Range = copy(start, end, step)
def isInclusive = false
@inline final override def foreach[@specialized(Unit) U](f: Int => U) {
if (length > 0) {
val last = this.last
var i = start
while (i != last) {
f(i)
i += step
}
f(i)
}
}
override def length: Int = numRangeElements
override lazy val last: Int =
if (length == 0) Nil.last
else locationAfterN(length - 1)
final override def isEmpty = length == 0
@inline
final def apply(idx: Int): Int = {
if (idx < 0 || idx >= length) throw new IndexOutOfBoundsException(idx.toString)
locationAfterN(idx)
}
final override def take(n: Int): Range = (
if (n <= 0 || length == 0) newEmptyRange(start)
else if (n >= length) this
else new Range.Inclusive(start, locationAfterN(n - 1), step)
)
final override def drop(n: Int): Range = (
if (n <= 0 || length == 0) this
else if (n >= length) newEmptyRange(end)
else copy(locationAfterN(n), end, step)
)
final override def init: Range = {
if (isEmpty)
Nil.init
dropRight(1)
}
final override def tail: Range = {
if (isEmpty)
Nil.tail
drop(1)
}
private def skipCount(p: Int => Boolean): Int = {
var current = start
var counted = 0
while (counted < length && p(current)) {
counted += 1
current += step
}
counted
}
private def isWithinBoundaries(elem: Int) = (length > 0) && (
(step > 0 && start <= elem && elem <= last ) ||
(step < 0 && last <= elem && elem <= start)
)
private def locationAfterN(n: Int) = start + (step * n)
private def newEmptyRange(value: Int) = new Range(value, value, step)
final override def takeWhile(p: Int => Boolean): Range = take(skipCount(p))
final override def dropWhile(p: Int => Boolean): Range = drop(skipCount(p))
final override def span(p: Int => Boolean): (Range, Range) = splitAt(skipCount(p))
final override def splitAt(n: Int) = (take(n), drop(n))
final override def takeRight(n: Int): Range = drop(length - n)
final override def dropRight(n: Int): Range = take(length - n)
final override def reverse: Range =
if (length > 0) new Range.Inclusive(last, start, -step)
else this
def inclusive =
if (isInclusive) this
else new Range.Inclusive(start, end, step)
final def contains(x: Int) = isWithinBoundaries(x) && ((x - start) % step == 0)
override def toIterable = this
override def toSeq = this
override def equals(other: Any) = other match {
case x: Range =>
(x canEqual this) && (length == x.length) && (
(length == 0) ||
(start == x.start && last == x.last)
)
case _ =>
super.equals(other)
}
override def toString() = {
val endStr = if (length > Range.MAX_PRINT) ", ... )" else ")"
take(Range.MAX_PRINT).mkString("Range(", ", ", endStr)
}
}
object Range {
private[immutable] val MAX_PRINT = 512
def count(start: Int, end: Int, step: Int): Int =
count(start, end, step, false)
def count(start: Int, end: Int, step: Int, isInclusive: Boolean): Int = {
if (start >= 0 && end > start && end < scala.Int.MaxValue && step == 1)
(end - start) + ( if (isInclusive) 1 else 0 )
else
NumericRange.count[Long](start, end, step, isInclusive)
}
class Inclusive(start: Int, end: Int, step: Int) extends Range(start, end, step) {
override def isInclusive = true
override protected def copy(start: Int, end: Int, step: Int): Range = new Inclusive(start, end, step)
}
def apply(start: Int, end: Int, step: Int): Range = new Range(start, end, step)
def apply(start: Int, end: Int): Range = new Range(start, end, 1)
@inline def inclusive(start: Int, end: Int, step: Int): Range.Inclusive = new Inclusive(start, end, step)
@inline def inclusive(start: Int, end: Int): Range.Inclusive = new Inclusive(start, end, 1)
object BigInt {
def apply(start: BigInt, end: BigInt, step: BigInt) = NumericRange(start, end, step)
def inclusive(start: BigInt, end: BigInt, step: BigInt) = NumericRange.inclusive(start, end, step)
}
object Long {
def apply(start: Long, end: Long, step: Long) = NumericRange(start, end, step)
def inclusive(start: Long, end: Long, step: Long) = NumericRange.inclusive(start, end, step)
}
object BigDecimal {
implicit val bigDecAsIntegral = scala.math.Numeric.BigDecimalAsIfIntegral
def apply(start: BigDecimal, end: BigDecimal, step: BigDecimal) =
NumericRange(start, end, step)
def inclusive(start: BigDecimal, end: BigDecimal, step: BigDecimal) =
NumericRange.inclusive(start, end, step)
}
object Double {
implicit val bigDecAsIntegral = scala.math.Numeric.BigDecimalAsIfIntegral
implicit val doubleAsIntegral = scala.math.Numeric.DoubleAsIfIntegral
def toBD(x: Double): BigDecimal = scala.math.BigDecimal valueOf x
def apply(start: Double, end: Double, step: Double) =
BigDecimal(toBD(start), toBD(end), toBD(step)) mapRange (_.doubleValue)
def inclusive(start: Double, end: Double, step: Double) =
BigDecimal.inclusive(toBD(start), toBD(end), toBD(step)) mapRange (_.doubleValue)
}
class Partial[T, U](f: T => U) {
def by(x: T): U = f(x)
}
object Int {
def apply(start: Int, end: Int, step: Int) = NumericRange(start, end, step)
def inclusive(start: Int, end: Int, step: Int) = NumericRange.inclusive(start, end, step)
}
@deprecated("use Range instead", "2.9.0")
trait ByOne extends Range {
}
}