summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2011-03-08 15:40:53 +0000
committerPaul Phillips <paulp@improving.org>2011-03-08 15:40:53 +0000
commit783721e98a4f61fc0c72298811b15e99c058d5e6 (patch)
treecdc0786526c572cfb9198942d517fbfd36ed0ba5 /src
parent8328a880b60ded33d5d49b88bdc75020b577eb27 (diff)
downloadscala-783721e98a4f61fc0c72298811b15e99c058d5e6.tar.gz
scala-783721e98a4f61fc0c72298811b15e99c058d5e6.tar.bz2
scala-783721e98a4f61fc0c72298811b15e99c058d5e6.zip
An overhaul of slice and related implementation...
An overhaul of slice and related implementations (primarily that is drop and take.) In the course of trying to get it working consistently (mostly with respect to negative indices, which were dealt with arbitrarily differently across the 25+ concrete implementations) I fixed various bugs. Closes #4288, no review.
Diffstat (limited to 'src')
-rwxr-xr-xsrc/library/scala/collection/IndexedSeqOptimized.scala12
-rw-r--r--src/library/scala/collection/IterableLike.scala28
-rw-r--r--src/library/scala/collection/Iterator.scala38
-rwxr-xr-xsrc/library/scala/collection/LinearSeqOptimized.scala16
-rw-r--r--src/library/scala/collection/TraversableLike.scala81
-rw-r--r--src/library/scala/collection/generic/TraversableForwarder.scala25
-rw-r--r--src/library/scala/collection/immutable/List.scala6
-rw-r--r--src/library/scala/collection/immutable/Range.scala11
-rw-r--r--src/library/scala/collection/immutable/Stream.scala58
-rw-r--r--src/library/scala/collection/immutable/StreamViewLike.scala1
-rw-r--r--src/library/scala/collection/immutable/StringLike.scala8
-rw-r--r--src/library/scala/collection/immutable/StringOps.scala11
-rw-r--r--src/library/scala/io/Source.scala2
13 files changed, 127 insertions, 170 deletions
diff --git a/src/library/scala/collection/IndexedSeqOptimized.scala b/src/library/scala/collection/IndexedSeqOptimized.scala
index 0d95108235..e680d02183 100755
--- a/src/library/scala/collection/IndexedSeqOptimized.scala
+++ b/src/library/scala/collection/IndexedSeqOptimized.scala
@@ -102,17 +102,7 @@ trait IndexedSeqOptimized[+A, +Repr] extends IndexedSeqLike[A, Repr] { self =>
}
override /*IterableLike*/
- def slice(from: Int, until: Int): Repr = {
- var i = from max 0
- val end = until min length
- val b = newBuilder
- b.sizeHint(end - i)
- while (i < end) {
- b += this(i)
- i += 1
- }
- b.result
- }
+ def slice(from: Int, until: Int): Repr = sliceWithKnownSize(from max 0, until min length)
override /*IterableLike*/
def head: A = if (isEmpty) super.head else this(0)
diff --git a/src/library/scala/collection/IterableLike.scala b/src/library/scala/collection/IterableLike.scala
index 1b5bd4b822..16d7b0f66e 100644
--- a/src/library/scala/collection/IterableLike.scala
+++ b/src/library/scala/collection/IterableLike.scala
@@ -92,33 +92,13 @@ self =>
iterator.reduceRight(op)
override /*TraversableLike*/ def toIterable: Iterable[A] =
thisCollection
-
override /*TraversableLike*/ def head: A =
- if (isEmpty) throw new NoSuchElementException
- else iterator.next
-
- override /*TraversableLike*/ def take(n: Int): Repr = {
- val b = newBuilder
- b.sizeHintBounded(n, this)
- var i = 0
- val it = iterator
- while (i < n && it.hasNext) {
- b += it.next
- i += 1
- }
- b.result
- }
+ iterator.next
override /*TraversableLike*/ def slice(from: Int, until: Int): Repr = {
- val b = newBuilder
- b.sizeHintBounded(until - from, this)
- var i = from
- val it = iterator drop from
- while (i < until && it.hasNext) {
- b += it.next
- i += 1
- }
- b.result
+ val lo = from max 0
+ if (until <= lo) newBuilder.result
+ else newBuilder ++= (iterator drop lo take (until - lo)) result
}
override /*TraversableLike*/ def takeWhile(p: A => Boolean): Repr = {
diff --git a/src/library/scala/collection/Iterator.scala b/src/library/scala/collection/Iterator.scala
index 58df4ff0d4..18b0d1c5b5 100644
--- a/src/library/scala/collection/Iterator.scala
+++ b/src/library/scala/collection/Iterator.scala
@@ -284,15 +284,9 @@ trait Iterator[+A] extends TraversableOnce[A] {
/** Selects first ''n'' values of this iterator.
* @param n the number of values to take
* @return an iterator producing only of the first `n` values of this iterator, or else the
- * whole iterator, if it produces less than `n` values.
+ * whole iterator, if it produces fewer than `n` values.
*/
- def take(n: Int): Iterator[A] = new Iterator[A] {
- private var remaining = n
- def hasNext = remaining > 0 && self.hasNext
- def next(): A =
- if (hasNext) { remaining -= 1; self.next() }
- else empty.next()
- }
+ def take(n: Int): Iterator[A] = slice(0, n)
/** Advances this iterator past the first ''n'' elements,
* or the length of the iterator, whichever is smaller.
@@ -301,14 +295,7 @@ trait Iterator[+A] extends TraversableOnce[A] {
* @return an iterator which produces all values of the current iterator, except
* it omits the first `n` values.
*/
- def drop(n: Int): Iterator[A] = {
- @tailrec
- def loop(left: Int): Iterator[A] =
- if (left > 0 && hasNext) { next; loop(left - 1) }
- else this
-
- loop(n)
- }
+ def drop(n: Int): Iterator[A] = slice(n, Int.MaxValue)
/** Creates an iterator returning an interval of the values produced by this iterator.
* @param from the index of the first element in this iterator which forms part of the slice.
@@ -316,7 +303,24 @@ trait Iterator[+A] extends TraversableOnce[A] {
* @return an iterator which advances this iterator past the first `from` elements using `drop`,
* and then takes `until - from` elements, using `take`.
*/
- def slice(from: Int, until: Int): Iterator[A] = drop(from).take(until - from)
+ def slice(from: Int, until: Int): Iterator[A] = {
+ val lo = from max 0
+ var toDrop = lo
+ while (toDrop > 0 && self.hasNext) {
+ self.next
+ toDrop -= 1
+ }
+ new Iterator[A] {
+ private var remaining = until - lo
+ def hasNext = remaining > 0 && self.hasNext
+ def next(): A =
+ if (remaining > 0) {
+ remaining -= 1
+ self.next()
+ }
+ else empty.next()
+ }
+ }
/** Creates a new iterator that maps all produced values of this iterator
* to new values using a transformation function.
diff --git a/src/library/scala/collection/LinearSeqOptimized.scala b/src/library/scala/collection/LinearSeqOptimized.scala
index 5e47021110..f57dba2d3f 100755
--- a/src/library/scala/collection/LinearSeqOptimized.scala
+++ b/src/library/scala/collection/LinearSeqOptimized.scala
@@ -183,13 +183,21 @@ trait LinearSeqOptimized[+A, +Repr <: LinearSeqOptimized[A, Repr]] extends Linea
override /*IterableLike*/
def slice(from: Int, until: Int): Repr = {
+ var these: Repr = repr
+ var count = from max 0
+ if (until <= count)
+ return newBuilder.result
+
val b = newBuilder
- var i = from
- var these = this drop from
- while (i < until && !these.isEmpty) {
+ var sliceElems = until - count
+ while (these.nonEmpty && count > 0) {
+ these = these.tail
+ count -= 1
+ }
+ while (these.nonEmpty && sliceElems > 0) {
+ sliceElems -= 1
b += these.head
these = these.tail
- i += 1
}
b.result
}
diff --git a/src/library/scala/collection/TraversableLike.scala b/src/library/scala/collection/TraversableLike.scala
index 57191cdd9a..293cf86eb0 100644
--- a/src/library/scala/collection/TraversableLike.scala
+++ b/src/library/scala/collection/TraversableLike.scala
@@ -563,19 +563,7 @@ trait TraversableLike[+A, +Repr] extends HasNewBuilder[A, Repr]
* @return a $coll consisting only of the first `n` elements of this $coll,
* or else the whole $coll, if it has less than `n` elements.
*/
- def take(n: Int): Repr = {
- val b = newBuilder
- b.sizeHintBounded(n, this)
- var i = 0
- breakable {
- for (x <- this) {
- if (i >= n) break
- b += x
- i += 1
- }
- }
- b.result
- }
+ def take(n: Int): Repr = sliceWithKnownSize(0, n)
/** Selects all elements except first ''n'' ones.
* $orderDependent
@@ -583,41 +571,64 @@ trait TraversableLike[+A, +Repr] extends HasNewBuilder[A, Repr]
* @return a $coll consisting of all elements of this $coll except the first `n` ones, or else the
* empty $coll, if this $coll has less than `n` elements.
*/
- def drop(n: Int): Repr = {
- val b = newBuilder
- if (n >= 0) b.sizeHint(this, -n)
- var i = 0
- for (x <- this) {
- if (i >= n) b += x
- i += 1
- }
- b.result
- }
+ def drop(n: Int): Repr =
+ if (n <= 0) newBuilder ++= thisCollection result
+ else sliceWithKnownDelta(n, Int.MaxValue, -n)
- /** Selects an interval of elements.
- *
- * Note: `c.slice(from, to)` is equivalent to (but possibly more efficient than)
- * `c.drop(from).take(to - from)`
+ /** Selects an interval of elements. The returned collection is made up
+ * of all elements `x` which satisfy the invariant:
+ * {{{
+ * from <= indexOf(x) < until
+ * }}}
* $orderDependent
*
- * @param from the index of the first returned element in this $coll.
- * @param until the index one past the last returned element in this $coll.
- * @return a $coll containing the elements starting at index `from`
- * and extending up to (but not including) index `until` of this $coll.
+ * @param from the lowest index to include from this $coll.
+ * @param until the highest index to EXCLUDE from this $coll.
+ * @return a $coll containing the elements greater than or equal to
+ * index `from` extending up to (but not including) index `until`
+ * of this $coll.
*/
- def slice(from: Int, until: Int): Repr = {
- val b = newBuilder
- b.sizeHintBounded(until - from, this)
+ def slice(from: Int, until: Int): Repr = sliceWithKnownBound(from max 0, until)
+
+ // Precondition: from >= 0, until > 0, builder already configured for building.
+ private[this] def sliceInternal(from: Int, until: Int, b: Builder[A, Repr]): Repr = {
var i = 0
breakable {
for (x <- this) {
if (i >= from) b += x
i += 1
- if (i == until) break
+ if (i >= until) break
}
}
b.result
}
+ // Precondition: from >= 0
+ private[scala] def sliceWithKnownDelta(from: Int, until: Int, delta: Int): Repr = {
+ val b = newBuilder
+ if (until <= from) b.result
+ else {
+ b.sizeHint(this, delta)
+ sliceInternal(from, until, b)
+ }
+ }
+ // Precondition: from >= 0
+ private[scala] def sliceWithKnownSize(from: Int, until: Int): Repr = {
+ val b = newBuilder
+ if (until <= from) b.result
+ else {
+ b.sizeHint(until - from)
+ sliceInternal(from, until, b)
+ }
+ }
+ // Precondition: from >= 0
+ private[scala] def sliceWithKnownBound(from: Int, until: Int): Repr = {
+ val b = newBuilder
+ if (until <= from) b.result
+ else {
+ b.sizeHintBounded(until - from, this)
+ sliceInternal(from, until, b)
+ }
+ }
/** Takes longest prefix of elements that satisfy a predicate.
* $orderDependent
diff --git a/src/library/scala/collection/generic/TraversableForwarder.scala b/src/library/scala/collection/generic/TraversableForwarder.scala
index 100733abf4..0049d23a86 100644
--- a/src/library/scala/collection/generic/TraversableForwarder.scala
+++ b/src/library/scala/collection/generic/TraversableForwarder.scala
@@ -12,30 +12,19 @@ import scala.collection._
import mutable.{ Buffer, StringBuilder }
import immutable.{ List, Stream }
-/** <p>
- * This trait implements a forwarder for traversable objects. It forwards
- * all calls to a different iterable object, except for
- * </p>
- * <ul>
- * <li><code>toString</code>, <code>hashCode</code>, <code>equals</code>,
- * <code>stringPrefix</code>
- * </li>
- * <li><code>newBuilder</code>, <code>view</code></li>
- * <li>all calls creating a new iterable object of the same kind</li>
- * </ul>
- * <p>
- * The above methods are forwarded by subclass
- * <a href="TraversableProxy.html" target="ContentFrame">
- * <code>TraversableProxy</code></a>.
- * </p>
+/** This trait implements a forwarder for traversable objects. It forwards
+ * all calls to a different traversable, except for:
+ {{{
+ toString, hashCode, equals, stringPrefix, newBuilder, view
+ }}}
+ * All calls creating a new traversable of the same kind.
*
* @author Martin Odersky
* @version 2.8
* @since 2.8
*/
trait TraversableForwarder[+A] extends Traversable[A] {
-
- /** The iterable object to which calls are forwarded */
+ /** The traversable object to which calls are forwarded. */
protected def underlying: Traversable[A]
override def foreach[B](f: A => B): Unit = underlying.foreach(f)
diff --git a/src/library/scala/collection/immutable/List.scala b/src/library/scala/collection/immutable/List.scala
index b1daf5541e..c46c487968 100644
--- a/src/library/scala/collection/immutable/List.scala
+++ b/src/library/scala/collection/immutable/List.scala
@@ -171,12 +171,6 @@ sealed abstract class List[+A] extends LinearSeq[A]
these
}
- override def slice(start: Int, end: Int): List[A] = {
- var len = end
- if (start > 0) len -= start
- drop(start) take len
- }
-
override def takeRight(n: Int): List[A] = {
@tailrec
def loop(lead: List[A], lag: List[A]): List[A] = lead match {
diff --git a/src/library/scala/collection/immutable/Range.scala b/src/library/scala/collection/immutable/Range.scala
index 6d03adc8ea..f8b3dfa54f 100644
--- a/src/library/scala/collection/immutable/Range.scala
+++ b/src/library/scala/collection/immutable/Range.scala
@@ -139,17 +139,6 @@ extends IndexedSeq[Int]
drop(1)
}
- /** Creates a new range contained in the specified slice of this range.
- *
- * $doesNotUseBuilders
- *
- * @param from the start of the slice.
- * @param until the end of the slice.
- * @return a new range consisting of all the elements of this range contained in the specified slice.
- */
- final override def slice(from: Int, until: Int): Range =
- this drop from take (until - from)
-
// Counts how many elements from the start meet the given test.
private def skipCount(p: Int => Boolean): Int = {
var current = start
diff --git a/src/library/scala/collection/immutable/Stream.scala b/src/library/scala/collection/immutable/Stream.scala
index 26fa86861c..b12b312d21 100644
--- a/src/library/scala/collection/immutable/Stream.scala
+++ b/src/library/scala/collection/immutable/Stream.scala
@@ -14,8 +14,7 @@ package immutable
import generic._
import mutable.{Builder, StringBuilder, LazyBuilder, ListBuffer}
import scala.annotation.tailrec
-
-
+import Stream.cons
/** The class `Stream` implements lazy lists where elements
* are only evaluated when they are needed. Here is an example:
@@ -78,7 +77,7 @@ self =>
* @return The stream containing elements of this stream and the traversable object.
*/
def append[B >: A](rest: => TraversableOnce[B]): Stream[B] =
- if (isEmpty) rest.toStream else new Stream.Cons(head, tail append rest)
+ if (isEmpty) rest.toStream else cons(head, tail append rest)
/** Forces evaluation of the whole stream and returns it. */
def force: Stream[A] = {
@@ -143,7 +142,7 @@ self =>
// we assume there is no other builder factory on streams and therefore know that That = Stream[A]
if (isStreamBuilder(bf)) asThat(
if (isEmpty) that.toStream
- else new Stream.Cons(head, asStream[A](tail ++ that))
+ else cons(head, asStream[A](tail ++ that))
)
else super.++(that)(bf)
@@ -155,7 +154,7 @@ self =>
override final def scanLeft[B, That](z: B)(op: (B, A) => B)(implicit bf: CanBuildFrom[Stream[A], B, That]): That =
if (isStreamBuilder(bf)) asThat(
if (isEmpty) Stream(z)
- else new Stream.Cons(z, asStream[B](tail.scanLeft(op(z, head))(op)))
+ else cons(z, asStream[B](tail.scanLeft(op(z, head))(op)))
)
else super.scanLeft(z)(op)(bf)
@@ -169,7 +168,7 @@ self =>
override final def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Stream[A], B, That]): That = {
if (isStreamBuilder(bf)) asThat(
if (isEmpty) Stream.Empty
- else new Stream.Cons(f(head), asStream[B](tail map f))
+ else cons(f(head), asStream[B](tail map f))
)
else super.map(f)(bf)
}
@@ -246,7 +245,7 @@ self =>
def tailMap = asStream[B](tail withFilter p map f)
if (isStreamBuilder(bf)) asThat(
if (isEmpty) Stream.Empty
- else if (p(head)) new Stream.Cons(f(head), tailMap)
+ else if (p(head)) cons(f(head), tailMap)
else tailMap
)
else super.map(f)(bf)
@@ -362,7 +361,7 @@ self =>
// we assume there is no other builder factory on streams and therefore know that That = Stream[(A1, B)]
if (isStreamBuilder(bf)) asThat(
if (this.isEmpty || that.isEmpty) Stream.Empty
- else new Stream.Cons((this.head, that.head), asStream[(A1, B)](this.tail zip that.tail))
+ else cons((this.head, that.head), asStream[(A1, B)](this.tail zip that.tail))
)
else super.zip(that)(bf)
@@ -410,6 +409,8 @@ self =>
override def toString = super.mkString(stringPrefix + "(", ", ", ")")
+ override def splitAt(n: Int): (Stream[A], Stream[A]) = (take(n), drop(n))
+
/** Returns the <code>n</code> first elements of this stream, or else the whole
* stream, if it has less than <code>n</code> elements.
*
@@ -417,27 +418,20 @@ self =>
* @return the <code>n</code> first elements of this stream.
*/
override def take(n: Int): Stream[A] =
- if (n <= 0 || isEmpty) Stream.Empty
- else new Stream.Cons(head, if (n == 1) Stream.empty else tail take (n-1))
+ if (n <= 0 || isEmpty) Stream.empty
+ else if (n == 1) cons(head, Stream.empty)
+ else cons(head, tail take n-1)
- override def splitAt(n: Int): (Stream[A], Stream[A]) = (take(n), drop(n))
-
- /** A substream starting at index `from`
- * and extending up to (but not including) index `until`.
- *
- * @note This is equivalent to (but possibly more efficient than)
- * c.drop(from).take(to - from)
+ /** A substream starting at index `from` and extending up to (but not including)
+ * index `until`.
*
* @param start The index of the first element of the returned subsequence
* @param end The index of the element following the returned subsequence
- * @throws IndexOutOfBoundsException if <code>from &lt; 0</code>
- * or <code>length &lt; from + len<code>
- * @note Might return different results for different runs, unless this iterable is ordered
*/
- override def slice(start: Int, end: Int): Stream[A] = {
- var len = end
- if (start > 0) len -= start
- drop(start) take len
+ override def slice(from: Int, until: Int): Stream[A] = {
+ val lo = from max 0
+ if (until <= lo || isEmpty) Stream.empty
+ else this drop lo take (until - lo)
}
/** The stream without its last element.
@@ -446,7 +440,7 @@ self =>
override def init: Stream[A] =
if (isEmpty) super.init
else if (tail.isEmpty) Stream.Empty
- else new Stream.Cons(head, tail.init)
+ else cons(head, tail.init)
/** Returns the rightmost <code>n</code> elements from this iterable.
* @param n the number of elements to take
@@ -469,7 +463,7 @@ self =>
* @param p the test predicate.
*/
override def takeWhile(p: A => Boolean): Stream[A] =
- if (!isEmpty && p(head)) new Stream.Cons(head, tail takeWhile p)
+ if (!isEmpty && p(head)) cons(head, tail takeWhile p)
else Stream.Empty
/** Returns the longest suffix of this iterable whose first element
@@ -488,7 +482,7 @@ self =>
*/
override def distinct: Stream[A] =
if (isEmpty) this
- else new Stream.Cons(head, tail.filter(head !=).distinct)
+ else cons(head, tail.filter(head !=).distinct)
/** Returns a new sequence of given length containing the elements of this sequence followed by zero
* or more occurrences of given elements.
@@ -496,7 +490,7 @@ self =>
override def padTo[B >: A, That](len: Int, elem: B)(implicit bf: CanBuildFrom[Stream[A], B, That]): That = {
def loop(len: Int, these: Stream[A]): Stream[B] =
if (these.isEmpty) Stream.fill(len)(elem)
- else new Stream.Cons(these.head, loop(len - 1, these.tail))
+ else cons(these.head, loop(len - 1, these.tail))
if (isStreamBuilder(bf)) asThat(loop(len, this))
else super.padTo(len, elem)(bf)
@@ -519,7 +513,7 @@ self =>
override def flatten[B](implicit asTraversable: A => /*<:<!!!*/ TraversableOnce[B]): Stream[B] = {
def flatten1(t: Traversable[B]): Stream[B] =
if (!t.isEmpty)
- new Stream.Cons(t.head, flatten1(t.tail))
+ cons(t.head, flatten1(t.tail))
else
tail.flatten
@@ -593,7 +587,7 @@ object Stream extends SeqFactory[Stream] {
* to streams.
*/
class ConsWrapper[A](tl: => Stream[A]) {
- def #::(hd: A): Stream[A] = new Stream.Cons(hd, tl)
+ def #::(hd: A): Stream[A] = cons(hd, tl)
def #:::(prefix: Stream[A]): Stream[A] = prefix append tl
}
@@ -702,11 +696,11 @@ object Stream extends SeqFactory[Stream] {
}
private[immutable] def filteredTail[A](stream: Stream[A], p: A => Boolean) = {
- new Stream.Cons(stream.head, stream.tail filter p)
+ cons(stream.head, stream.tail filter p)
}
private[immutable] def collectedTail[A, B, That](stream: Stream[A], pf: PartialFunction[A, B], bf: CanBuildFrom[Stream[A], B, That]) = {
- new Stream.Cons(pf(stream.head), stream.tail.collect(pf)(bf).asInstanceOf[Stream[B]])
+ cons(pf(stream.head), stream.tail.collect(pf)(bf).asInstanceOf[Stream[B]])
}
/** A stream containing all elements of a given iterator, in the order they are produced.
diff --git a/src/library/scala/collection/immutable/StreamViewLike.scala b/src/library/scala/collection/immutable/StreamViewLike.scala
index a3da3fd1b6..7995507943 100644
--- a/src/library/scala/collection/immutable/StreamViewLike.scala
+++ b/src/library/scala/collection/immutable/StreamViewLike.scala
@@ -67,6 +67,7 @@ extends SeqView[A, Coll]
}
protected override def newPrepended[B >: A](elem: B): Transformed[B] = new Prepended[B] { protected[this] val fst = elem }
+ override def stringPrefix = "StreamView"
}
diff --git a/src/library/scala/collection/immutable/StringLike.scala b/src/library/scala/collection/immutable/StringLike.scala
index acb5dd586a..926fde4fe0 100644
--- a/src/library/scala/collection/immutable/StringLike.scala
+++ b/src/library/scala/collection/immutable/StringLike.scala
@@ -57,6 +57,14 @@ self =>
override def mkString = toString
+ override def slice(from: Int, until: Int): Repr = {
+ val start = from max 0
+ val end = until min length
+
+ if (start >= end) newBuilder.result
+ else newBuilder ++= toString.substring(start, end) result
+ }
+
/** Return the current string concatenated `n` times.
*/
def * (n: Int): String = {
diff --git a/src/library/scala/collection/immutable/StringOps.scala b/src/library/scala/collection/immutable/StringOps.scala
index fdc5a51d7d..06a62c2604 100644
--- a/src/library/scala/collection/immutable/StringOps.scala
+++ b/src/library/scala/collection/immutable/StringOps.scala
@@ -36,16 +36,5 @@ final class StringOps(override val repr: String) extends StringLike[String] {
/** Creates a string builder buffer as builder for this class */
override protected[this] def newBuilder = StringBuilder.newBuilder
- override def slice(from: Int, until: Int): String = {
- /** Slice must be forgiving on all out of bounds indices and
- * substring is not.
- */
- val start = from max 0
- val end = until min repr.length
-
- if (start >= end) ""
- else repr.substring(start, end)
- }
-
override def toString = repr
}
diff --git a/src/library/scala/io/Source.scala b/src/library/scala/io/Source.scala
index 2f9085211d..570c48a91a 100644
--- a/src/library/scala/io/Source.scala
+++ b/src/library/scala/io/Source.scala
@@ -199,7 +199,7 @@ abstract class Source extends Iterator[Char] {
*/
@deprecated("Use a collections method such as getLines().toIndexedSeq for random access.")
def getLine(line: Int): String = lineNum(line)
- private def lineNum(line: Int): String = getLines() drop (line - 1) next
+ private def lineNum(line: Int): String = getLines() drop (line - 1) take 1 mkString
class LineIterator() extends Iterator[String] {
private[this] val sb = new StringBuilder