summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2011-07-01 06:58:03 +0000
committerPaul Phillips <paulp@improving.org>2011-07-01 06:58:03 +0000
commit300cb9e1ee6559ea08b58b04dd89de94e4449fce (patch)
treeaafc568430fc96757c484754f5639607e6f51ee9 /src
parent9d02b4adea3512e671e97c11dec9dd7fd8514c49 (diff)
downloadscala-300cb9e1ee6559ea08b58b04dd89de94e4449fce.tar.gz
scala-300cb9e1ee6559ea08b58b04dd89de94e4449fce.tar.bz2
scala-300cb9e1ee6559ea08b58b04dd89de94e4449fce.zip
Keep BufferedSource from losing buffered data w...
Keep BufferedSource from losing buffered data when a derivative iterator is created via getLines. Closes #4671, #4662, no review.
Diffstat (limited to 'src')
-rw-r--r--src/library/scala/io/BufferedSource.scala59
1 files changed, 49 insertions, 10 deletions
diff --git a/src/library/scala/io/BufferedSource.scala b/src/library/scala/io/BufferedSource.scala
index 60d67a0b58..b5144a891f 100644
--- a/src/library/scala/io/BufferedSource.scala
+++ b/src/library/scala/io/BufferedSource.scala
@@ -8,7 +8,7 @@
package scala.io
-import java.io.{ InputStream, BufferedReader, InputStreamReader }
+import java.io.{ InputStream, BufferedReader, InputStreamReader, PushbackReader }
import Source.DefaultBufSize
import scala.collection.Iterator
@@ -22,20 +22,59 @@ class BufferedSource(inputStream: InputStream, bufferSize: Int)(implicit val cod
def reader() = new InputStreamReader(inputStream, codec.decoder)
def bufferedReader() = new BufferedReader(reader(), bufferSize)
- override val iter = {
- val reader = bufferedReader()
- Iterator continually (codec wrap reader.read()) takeWhile (_ != -1) map (_.toChar)
+ // The same reader has to be shared between the iterators produced
+ // by iter and getLines. This is because calling hasNext can cause a
+ // block of data to be read from the stream, which will then be lost
+ // to getLines if it creates a new reader, even though next() was
+ // never called on the original.
+ private var charReaderCreated = false
+ private lazy val charReader = {
+ charReaderCreated = true
+ bufferedReader()
}
+ override lazy val iter = (
+ Iterator
+ continually (codec wrap charReader.read())
+ takeWhile (_ != -1)
+ map (_.toChar)
+ )
+
class BufferedLineIterator extends Iterator[String] {
- val bufReader = BufferedSource.this.bufferedReader()
- var nextLine = bufReader.readLine
+ // Don't want to lose a buffered char sitting in iter either. Yes,
+ // this is ridiculous, but if I can't get rid of Source, and all the
+ // Iterator bits are designed into Source, and people create Sources
+ // in the repl, and the repl calls toString for the result line, and
+ // that calls hasNext to find out if they're empty, and that leads
+ // to chars being buffered, and no, I don't work here, they left a
+ // door unlocked.
+ private val lineReader: BufferedReader = {
+ // To avoid inflicting this silliness indiscriminately, we can
+ // skip it if the char reader was never created: and almost always
+ // it will not have been created, since getLines will be called
+ // immediately on the source.
+ if (charReaderCreated && iter.hasNext) {
+ val pb = new PushbackReader(charReader)
+ pb unread iter.next()
+ new BufferedReader(pb, bufferSize)
+ }
+ else charReader
+ }
+ var nextLine: String = null
- override def hasNext = nextLine != null
+ override def hasNext = {
+ if (nextLine == null)
+ nextLine = lineReader.readLine
+
+ nextLine != null
+ }
override def next(): String = {
- val result = nextLine
- nextLine = bufReader.readLine
- result
+ val result = {
+ if (nextLine == null) lineReader.readLine
+ else try nextLine finally nextLine = null
+ }
+ if (result == null) Iterator.empty.next
+ else result
}
}