X-Git-Url: http://nitlanguage.org diff --git a/lib/standard/stream.nit b/lib/standard/stream.nit index 24681fe..4ad6af1 100644 --- a/lib/standard/stream.nit +++ b/lib/standard/stream.nit @@ -25,7 +25,7 @@ class IOError super Error end -# Abstract stream class +# Any kind of stream to read/write/both to or from a source abstract class Stream # Error produced by the file stream # @@ -39,7 +39,7 @@ abstract class Stream fun close is abstract end -# Abstract input streams +# A `Stream` that can be read from abstract class Reader super Stream # Read a character. Return its ASCII value, -1 on EOF or timeout @@ -220,6 +220,66 @@ abstract class Reader # Is there something to read. # This function returns 'false' if there is something to read. fun eof: Bool is abstract + + # Read the next sequence of non whitespace characters. + # + # Leading whitespace characters are skipped. + # The first whitespace character that follows the result is consumed. + # + # An empty string is returned if the end of the file or an error is encounter. + # + # ~~~ + # var w = new StringReader(" Hello, \n\t World!") + # assert w.read_word == "Hello," + # assert w.read_char == '\n'.ascii + # assert w.read_word == "World!" + # assert w.read_word == "" + # ~~~ + # + # `Char::is_whitespace` determines what is a whitespace. + fun read_word: String + do + var buf = new FlatBuffer + var c = read_nonwhitespace + if c > 0 then + buf.add(c.ascii) + while not eof do + c = read_char + if c < 0 then break + var a = c.ascii + if a.is_whitespace then break + buf.add(a) + end + end + var res = buf.to_s + return res + end + + # Skip whitespace characters (if any) then return the following non-whitespace character. + # + # Returns the code point of the character. + # Return -1 on end of file or error. + # + # In fact, this method works like `read_char` except it skips whitespace. + # + # ~~~ + # var w = new StringReader(" \nab\tc") + # assert w.read_nonwhitespace == 'a'.ascii + # assert w.read_nonwhitespace == 'b'.ascii + # assert w.read_nonwhitespace == 'c'.ascii + # assert w.read_nonwhitespace == -1 + # ~~~ + # + # `Char::is_whitespace` determines what is a whitespace. + fun read_nonwhitespace: Int + do + var c = -1 + while not eof do + c = read_char + if c < 0 or not c.ascii.is_whitespace then break + end + return c + end end # Iterator returned by `Reader::each_line`. @@ -269,7 +329,7 @@ class LineIterator end end -# `ReadStream` capable of declaring if readable without blocking +# `Reader` capable of declaring if readable without blocking abstract class PollableReader super Reader @@ -278,7 +338,7 @@ abstract class PollableReader end -# Abstract output stream +# A `Stream` that can be written to abstract class Writer super Stream # write a string @@ -288,12 +348,12 @@ abstract class Writer fun is_writable: Bool is abstract end -# Things that can be efficienlty writen to a `WriteStream` +# Things that can be efficienlty written to a `Writer` # -# The point of this interface it to allow is instance to be efficenty -# writen into a `WriteStream` without having to allocate a big String object +# The point of this interface is to allow the instance to be efficiently +# written into a `Writer`. # -# ready-to-save documents usually provide this interface. +# Ready-to-save documents usually provide this interface. interface Writable # Write itself to a `stream` # The specific logic it let to the concrete subclasses @@ -317,7 +377,7 @@ redef class Text redef fun write_to(stream) do stream.write(self) end -# Input streams with a buffer +# Input streams with a buffered input for efficiency purposes abstract class BufferedReader super Reader redef fun read_char @@ -332,22 +392,49 @@ abstract class BufferedReader return c.ascii end + # Peeks up to `n` bytes in the buffer, returns an empty string on EOF + # + # The operation does not consume the buffer + # + # ~~~nitish + # var x = new FileReader("File.txt") + # assert x.peek(5) == x.read(5) + # ~~~ + fun peek(i: Int): String do + if eof then return "" + var b = new FlatBuffer.with_capacity(i) + while i > 0 and not eof do + b.add _buffer[_buffer_pos] + _buffer_pos += 1 + i -= 1 + end + var nbuflen = b.length + (_buffer.length - _buffer_pos) + var nbuf = new FlatBuffer.with_capacity(nbuflen) + nbuf.append(b) + while _buffer_pos < _buffer.length do + nbuf.add(_buffer[_buffer_pos]) + _buffer_pos += 1 + end + _buffer_pos = 0 + _buffer = nbuf + return b.to_s + end + redef fun read(i) do if last_error != null then return "" - if _buffer.length == _buffer_pos then - if not eof then - return read(i) - end - return "" - end - if _buffer_pos + i >= _buffer.length then - var from = _buffer_pos - _buffer_pos = _buffer.length - return _buffer.substring_from(from).to_s + if eof then return "" + var p = _buffer_pos + var bufsp = _buffer.length - p + if bufsp >= i then + _buffer_pos += i + return _buffer.substring(p, i).to_s end - _buffer_pos += i - return _buffer.substring(_buffer_pos - i, i).to_s + _buffer_pos = _buffer.length + var readln = _buffer.length - p + var s = _buffer.substring(p, readln).to_s + fill_buffer + return s + read(i - readln) end redef fun read_all @@ -439,13 +526,13 @@ abstract class BufferedReader end end -# An Input/Output Stream +# A `Stream` that can be written to and read from abstract class Duplex super Reader super Writer end -# Stream to a String. +# `Stream` that can be used to write to a `String` # # Mainly used for compatibility with Writer type and tests. class StringWriter @@ -466,7 +553,7 @@ class StringWriter redef fun close do closed = true end -# Stream from a String. +# `Stream` used to read from a `String` # # Mainly used for compatibility with Reader type and tests. class StringReader