X-Git-Url: http://nitlanguage.org diff --git a/lib/standard/stream.nit b/lib/standard/stream.nit index 45c9f32..a94601c 100644 --- a/lib/standard/stream.nit +++ b/lib/standard/stream.nit @@ -10,27 +10,35 @@ # You are allowed to redistribute it and sell it, alone or is a part of # another product. -# This module handle abstract input and output streams -package stream +# Input and output streams of characters +module stream -import string +intrude import ropes + +in "C" `{ + #include + #include + #include + #include + #include +`} # Abstract stream class -class IOS +interface IOS # close the stream - meth close is abstract + fun close is abstract end # Abstract input streams -class IStream -special IOS +interface IStream + super IOS # Read a character. Return its ASCII value, -1 on EOF or timeout - meth read_char: Int is abstract + fun read_char: Int is abstract # Read at most i bytes - meth read(i: Int): String + fun read(i: Int): String do - var s = new Buffer.with_capacity(i) + var s = new FlatBuffer.with_capacity(i) while i > 0 and not eof do var c = read_char if c >= 0 then @@ -42,18 +50,18 @@ special IOS end # Read a string until the end of the line. - meth read_line: String + fun read_line: String do assert not eof - var s = new Buffer + var s = new FlatBuffer append_line_to(s) return s.to_s end # Read all the stream until the eof. - meth read_all: String + fun read_all: String do - var s = new Buffer + var s = new FlatBuffer while not eof do var c = read_char if c >= 0 then s.add(c.ascii) @@ -61,39 +69,101 @@ special IOS return s.to_s end - # Read a string until the end of the line and append it to `s'. - meth append_line_to(s: Buffer) + # Read a string until the end of the line and append it to `s`. + fun append_line_to(s: Buffer) do - while true do + loop var x = read_char if x == -1 then if eof then return else var c = x.ascii - s.push(c) + s.chars.push(c) if c == '\n' then return end end end # Is there something to read. - meth eof: Bool is abstract + # This function returns 'false' if there is something to read. + fun eof: Bool is abstract +end + +# IStream capable of declaring if readable without blocking +interface PollableIStream + super IStream + + # Is there something to read? (without blocking) + fun poll_in: Bool is abstract + end # Abstract output stream -class OStream -special IOS +interface OStream + super IOS # write a string - meth write(s: String) is abstract + fun write(s: Text) is abstract # Can the stream be used to write - meth is_writable: Bool is abstract + fun is_writable: Bool is abstract +end + +# Things that can be efficienlty writen to a OStream +# +# The point of this interface it to allow is instance to be efficenty +# writen into a OStream without having to allocate a big String object +# +# ready-to-save documents usually provide this interface. +interface Streamable + # Write itself to a `stream` + # The specific logic it let to the concrete subclasses + fun write_to(stream: OStream) is abstract + + # Like `write_to` but return a new String (may be quite large) + # + # This funtionnality is anectodical, since the point + # of streamable object to to be efficienlty written to a + # stream without having to allocate and concatenate strings + fun write_to_string: String + do + var stream = new StringOStream + write_to(stream) + return stream.to_s + end +end + +redef class Text + super Streamable + redef fun write_to(stream) do stream.write(self) +end + +redef class RopeNode + super Streamable +end + +redef class Leaf + + redef fun write_to(s) do s.write(str) +end + +redef class Concat + + redef fun write_to(s) + do + if left != null then left.write_to(s) + if right != null then right.write_to(s) + end +end + +redef class RopeString + + redef fun write_to(s) do root.write_to(s) end # Input streams with a buffer -class BufferedIStream -special IStream - redef meth read_char +abstract class BufferedIStream + super IStream + redef fun read_char do assert not eof if _buffer_pos >= _buffer.length then @@ -102,41 +172,37 @@ special IStream if _buffer_pos >= _buffer.length then return -1 end - var c = _buffer[_buffer_pos] + var c = _buffer.chars[_buffer_pos] _buffer_pos += 1 return c.ascii end - redef meth read(i) + redef fun read(i) do - var s = new Buffer.with_capacity(i) - var j = _buffer_pos - var k = _buffer.length - while i > 0 do - if j >= k then + if _buffer.length == _buffer_pos then + if not eof then fill_buffer - if eof then return s.to_s - j = _buffer_pos - k = _buffer.length - end - while j < k and i > 0 do - s.add(_buffer[j]) - j += 1 - i -= 1 + return read(i) end + return "" end - _buffer_pos = j - return s.to_s + if _buffer_pos + i >= _buffer.length then + var from = _buffer_pos + _buffer_pos = _buffer.length + return _buffer.substring_from(from).to_s + end + _buffer_pos += i + return _buffer.substring(_buffer_pos - i, i).to_s end - redef meth read_all + redef fun read_all do - var s = new Buffer + var s = new FlatBuffer while not eof do var j = _buffer_pos var k = _buffer.length while j < k do - s.add(_buffer[j]) + s.add(_buffer.chars[j]) j += 1 end _buffer_pos = j @@ -145,12 +211,12 @@ special IStream return s.to_s end - redef meth append_line_to(s) + redef fun append_line_to(s) do - while true do + loop # First phase: look for a '\n' var i = _buffer_pos - while i < _buffer.length and _buffer[i] != '\n' do i += 1 + while i < _buffer.length and _buffer.chars[i] != '\n' do i += 1 # if there is something to append if i > _buffer_pos then @@ -160,7 +226,7 @@ special IStream # Copy from the buffer to the string var j = _buffer_pos while j < i do - s.add(_buffer[j]) + s.add(_buffer.chars[j]) j += 1 end end @@ -181,59 +247,60 @@ special IStream end end - redef meth eof do return _buffer_pos >= _buffer.length and end_reached + redef fun eof do return _buffer_pos >= _buffer.length and end_reached # The buffer - attr _buffer: nullable Buffer = null + var _buffer: nullable FlatBuffer = null # The current position in the buffer - attr _buffer_pos: Int = 0 + var _buffer_pos: Int = 0 # Fill the buffer - protected meth fill_buffer is abstract + protected fun fill_buffer is abstract # Is the last fill_buffer reach the end - protected meth end_reached: Bool is abstract + protected fun end_reached: Bool is abstract - # Allocate a `_buffer' for a given `capacity'. - protected meth prepare_buffer(capacity: Int) + # Allocate a `_buffer` for a given `capacity`. + protected fun prepare_buffer(capacity: Int) do - _buffer = new Buffer.with_capacity(capacity) + _buffer = new FlatBuffer.with_capacity(capacity) _buffer_pos = 0 # need to read end end -class IOStream -special IStream -special OStream +interface IOStream + super IStream + super OStream end ##############################################################" -class FDStream -special IOS +abstract class FDStream + super IOS # File description - attr _fd: Int + var fd: Int - redef meth close do native_close(_fd) + redef fun close do native_close(fd) - private meth native_close(i: Int): Int is extern "stream_FDStream_FDStream_native_close_1" - private meth native_read_char(i: Int): Int is extern "stream_FDStream_FDStream_native_read_char_1" - private meth native_read(i: Int, buf: NativeString, len: Int): Int is extern "stream_FDStream_FDStream_native_read_3" - private meth native_write(i: Int, buf: NativeString, len: Int): Int is extern "stream_FDStream_FDStream_native_write_3" + private fun native_close(i: Int): Int is extern "stream_FDStream_FDStream_native_close_1" + private fun native_read_char(i: Int): Int is extern "stream_FDStream_FDStream_native_read_char_1" + private fun native_read(i: Int, buf: NativeString, len: Int): Int is extern "stream_FDStream_FDStream_native_read_3" + private fun native_write(i: Int, buf: NativeString, len: Int): Int is extern "stream_FDStream_FDStream_native_write_3" + private fun native_write_char(i: Int, c: Char): Int is extern "stream_FDStream_FDStream_native_write_char_2" - init(fd: Int) do _fd = fd + init(fd: Int) do self.fd = fd end class FDIStream -special FDStream -special IStream - redef readable attr _eof: Bool = false + super FDStream + super IStream + redef var eof: Bool = false - redef meth read_char + redef fun read_char do - var nb = native_read_char(_fd) - if nb == -1 then _eof = true + var nb = native_read_char(fd) + if nb == -1 then eof = true return nb end @@ -241,29 +308,124 @@ special IStream end class FDOStream -special FDStream -special OStream - redef readable attr _is_writable: Bool + super FDStream + super OStream + redef var is_writable: Bool - redef meth write(s) + redef fun write(s) do - var nb = native_write(_fd, s.to_cstring, s.length) - if nb < s.length then _is_writable = false + var nb = native_write(fd, s.to_cstring, s.length) + if nb < s.length then is_writable = false end init(fd: Int) do - _is_writable = true + is_writable = true end end class FDIOStream -special FDIStream -special FDOStream -special IOStream + super FDIStream + super FDOStream + super IOStream init(fd: Int) do - _fd = fd - _is_writable = true + self.fd = fd + is_writable = true + end +end + +redef interface Object + # returns first available stream to read or write to + # return null on interruption (possibly a signal) + protected fun poll( streams : Sequence[FDStream] ) : nullable FDStream + do + var in_fds = new Array[Int] + var out_fds = new Array[Int] + var fd_to_stream = new HashMap[Int,FDStream] + for s in streams do + var fd = s.fd + if s isa FDIStream then in_fds.add( fd ) + if s isa FDOStream then out_fds.add( fd ) + + fd_to_stream[fd] = s + end + + var polled_fd = intern_poll( in_fds, out_fds ) + + if polled_fd == null then + return null + else + return fd_to_stream[polled_fd] + end end + + private fun intern_poll(in_fds: Array[Int], out_fds: Array[Int]) : nullable Int is extern import Array[Int].length, Array[Int].[], Int.as(nullable Int) `{ + int in_len, out_len, total_len; + struct pollfd *c_fds; + sigset_t sigmask; + int i; + int first_polled_fd = -1; + int result; + + in_len = Array_of_Int_length( in_fds ); + out_len = Array_of_Int_length( out_fds ); + total_len = in_len + out_len; + c_fds = malloc( sizeof(struct pollfd) * total_len ); + + /* input streams */ + for ( i=0; i 0 ) { + /* analyse results */ + for ( i=0; i