--- a/src/Pure/General/scan.scala Fri May 02 07:54:23 2014 +0200
+++ b/src/Pure/General/scan.scala Fri May 02 12:09:02 2014 +0200
@@ -408,4 +408,62 @@
scan_tree(rep, "", 0)
}
}
+
+
+
+ /** read file without decoding -- enables efficient length operation **/
+
+ private class Restricted_Seq(seq: IndexedSeq[Char], start: Int, end: Int)
+ extends CharSequence
+ {
+ def charAt(i: Int): Char =
+ if (0 <= i && i < length) seq(start + i)
+ else throw new IndexOutOfBoundsException
+
+ def length: Int = end - start // avoid potentially expensive seq.length
+
+ def subSequence(i: Int, j: Int): CharSequence =
+ if (0 <= i && i <= j && j <= length) new Restricted_Seq(seq, start + i, start + j)
+ else throw new IndexOutOfBoundsException
+
+ override def toString: String =
+ {
+ val buf = new StringBuilder(length)
+ for (offset <- start until end) buf.append(seq(offset))
+ buf.toString
+ }
+ }
+
+ abstract class Byte_Reader extends Reader[Char] { def close: Unit }
+
+ def byte_reader(file: JFile): Byte_Reader =
+ {
+ val stream = new BufferedInputStream(new FileInputStream(file))
+ val seq = new PagedSeq(
+ (buf: Array[Char], offset: Int, length: Int) =>
+ {
+ var i = 0
+ var c = 0
+ var eof = false
+ while (!eof && i < length) {
+ c = stream.read
+ if (c == -1) eof = true
+ else { buf(offset + i) = c.toChar; i += 1 }
+ }
+ if (i > 0) i else -1
+ })
+ val restricted_seq = new Restricted_Seq(seq, 0, file.length.toInt)
+
+ class Paged_Reader(override val offset: Int) extends Byte_Reader
+ {
+ override lazy val source: CharSequence = restricted_seq
+ def first: Char = if (seq.isDefinedAt(offset)) seq(offset) else '\032'
+ def rest: Paged_Reader = if (seq.isDefinedAt(offset)) new Paged_Reader(offset + 1) else this
+ def pos: InputPosition = new OffsetPosition(source, offset)
+ def atEnd: Boolean = !seq.isDefinedAt(offset)
+ override def drop(n: Int): Paged_Reader = new Paged_Reader(offset + n)
+ def close { stream.close }
+ }
+ new Paged_Reader(0)
+ }
}