lib/standard/stream: Renamed streams for more explicit denomination
[nit.git] / lib / io / push_back_reader.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # This file is free software, which comes along with NIT. This software is
4 # distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
5 # without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
6 # PARTICULAR PURPOSE. You can modify it is you want, provided this header
7 # is kept unaltered, and a notification of the changes is added.
8 # You are allowed to redistribute it and sell it, alone or is a part of
9 # another product.
10
11 # Input stream that permits to push bytes back to the stream.
12 module io::push_back_reader
13
14 # Input stream that permits to push bytes back to the stream.
15 class PushBackReader
16 super Reader
17
18 # Push the specified byte back to the stream.
19 #
20 # The specified byte is usually the last read byte that is not
21 # “unread” already.
22 fun unread_char(c: Char) is abstract
23
24 # Push the specified string back to the stream.
25 #
26 # The specified string is usually the last read string that is not
27 # “unread” already.
28 fun unread(s: String) do
29 for c in s.chars.reverse_iterator do unread_char(c)
30 end
31 end
32
33 # Decorates an input stream to permit to push bytes back to the input stream.
34 class PushBackDecorator
35 super PushBackReader
36
37 # The parent stream.
38 var parent: Reader
39
40 # The stack of the pushed-back bytes.
41 #
42 # Bytes are in the reverse order they will reappear in the stream.
43 # `unread` pushes bytes after already pushed-back bytes.
44 #
45 # TODO: With optimized bulk array copy operations, a reversed stack (like in
46 # OpenJDK) would be more efficient.
47 private var buf: Sequence[Char] = new Array[Char]
48
49 redef fun read_char: Int do
50 if buf.length <= 0 then return parent.read_char
51 return buf.pop.ascii
52 end
53
54 redef fun read(i: Int): String do
55 if i <= 0 then return ""
56 if buf.length <= 0 then return parent.read(i)
57 var s = new FlatBuffer.with_capacity(i)
58
59 loop
60 s.chars.push(buf.pop)
61 i -= 1
62 if i <= 0 then
63 return s.to_s
64 else if buf.length <= 0 then
65 s.append(parent.read(i))
66 return s.to_s
67 end
68 end
69 end
70
71 redef fun read_all: String do
72 if buf.length <= 0 then return parent.read_all
73 var s = new FlatBuffer
74
75 loop
76 s.chars.push(buf.pop)
77 if buf.length <= 0 then
78 s.append(parent.read_all)
79 return s.to_s
80 end
81 end
82 end
83
84 redef fun append_line_to(s: Buffer) do
85 if buf.length > 0 then
86 var c: Char
87
88 loop
89 c = buf.pop
90 s.chars.push(c)
91 if c == '\n' then return
92 if buf.length <= 0 then break
93 end
94 end
95 parent.append_line_to(s)
96 end
97
98 redef fun eof: Bool do return buf.length <= 0 and parent.eof
99
100 redef fun close do
101 buf.clear
102 parent.close
103 end
104
105 redef fun unread_char(c: Char) do buf.push(c)
106
107 redef fun unread(s: String) do
108 for c in s.chars.reverse_iterator do buf.push(c)
109 end
110 end