1 /* Invisible Vector Library
2 * coded by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
3 * Understanding is not required. Only obedience.
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 3 of the License ONLY.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 * wrap any low-level (or high-level) stream into refcounted struct.
19 * this struct can be used instead of `std.stdio.File` when you need
20 * a concrete type instead of working with generic stream templates.
21 * wrapped stream is thread-safe (i.e. reads, writes, etc), but
22 * wrapper itself isn't.
24 module iv
.vfs
.io
/*is aliced*/;
31 // ////////////////////////////////////////////////////////////////////////// //
32 // aaaaah, let's conflict with std.stdio!
33 public __gshared VFile stdin
, stdout
, stderr
;
35 shared static this () {
36 debug(vfs_rc
) { import core
.stdc
.stdio
: printf
; printf("******** SHARED CTOR FOR iv.vfs.io\n"); }
43 // ////////////////////////////////////////////////////////////////////////// //
44 public auto readTextFile(T
=string
) (const(char)[] fname
, int maxlen
=int.max
/8)
45 if (is(T
== string
) ||
is(T
== const(char)[]) ||
is(T
== char[]) ||
is(T
== const char[]))
47 return readTextFile(VFile(fname
), maxlen
);
51 //TODO: fallback to chunked reader if `fl.hasSize` is false
52 public auto readTextFile(T
=string
) (VFile fl
, int maxlen
=int.max
/8)
53 if (is(T
== string
) ||
is(T
== const(char)[]) ||
is(T
== char[]) ||
is(T
== const char[]) ||
54 is(T
== immutable(ubyte)[]) ||
is(T
== const(ubyte)[]) ||
is(T
== ubyte[]) ||
is(T
== const ubyte[]))
57 auto flen
= fl
.size
-fpos
;
58 if (flen
< 1) return cast(T
)null;
59 if (flen
> maxlen
) throw new Exception("text file too big");
60 auto res
= new char[](cast(int)flen
);
61 scope(failure
) delete res
; // make GC life easier
63 return cast(T
)res
; // it is safe to cast here
67 // ////////////////////////////////////////////////////////////////////////// //
68 /// read 0-terminated string from stream. very slow, no recoding.
69 /// eolhit will be set on EOF too.
70 public string
readZString(ST
) (auto ref ST fl
, bool* eolhit
=null, usize maxSize
=1024*1024) if (isReadableStream
!ST
) {
72 if (eolhit
is null) eolhit
= &eh
;
74 if (maxSize
== 0) return null;
78 if (fl
.rawRead((&ch
)[0..1]).length
== 0) { *eolhit
= true; break; }
79 if (ch
== 0) { *eolhit
= true; break; }
80 if (maxSize
== 0) break;
84 return cast(string
)res
; // it is safe to cast here
88 // ////////////////////////////////////////////////////////////////////////// //
89 /// read stream line by line. very slow, no recoding.
90 // hack around "has scoped destruction, cannot build closure"
91 public auto byLineCopy(bool keepTerm
=false) (VFile fl
) { return byLineCopyImpl
!keepTerm(fl
); }
92 public auto byLineCopy(bool keepTerm
=false, ST
) (auto ref ST fl
) if (!is(ST
== VFile
) && isRorWStream
!ST
) { return byLineCopyImpl
!keepTerm(fl
); }
94 public auto byLine(bool keepTerm
=false) (VFile fl
) { return byLineCopyImpl
!(keepTerm
, true)(fl
); }
95 public auto byLine(bool keepTerm
=false, ST
) (auto ref ST fl
) if (!is(ST
== VFile
) && isRorWStream
!ST
) { return byLineCopyImpl
!(keepTerm
, true)(fl
); }
97 private auto byLineCopyImpl(bool keepTerm
=false, bool reuseBuffer
=false, ST
) (auto ref ST fl
) {
98 static struct BLR(bool keepTerm
, bool reuse
, ST
) {
106 static if (!reuse
) string s
;
108 this() (auto ref ST ast
) {
110 if (st
.eof
) eof
= true; else popFront();
113 @property bool empty () const pure nothrow @safe @nogc { return eof
; }
114 @property auto front () inout nothrow @trusted @nogc { static if (reuse
) return buf
.ptr
[0..bufused
]; else return s
; }
118 if (rdpos
>= rdsize
) {
120 auto rd
= st
.rawRead(rdbuf
[]);
121 if (rd
.length
== 0) { futureeof
= true; return 0; }
122 rdsize
= cast(int)rd
.length
;
124 assert(rdpos
< rdsize
);
125 return rdbuf
.ptr
[rdpos
++];
127 void putch (char ch
) {
128 if (bufused
== buf
.length
) {
131 if (buf
.ptr
!is optr
) {
132 import core
.memory
: GC
;
133 if (buf
.ptr
is GC
.addrOf(buf
.ptr
)) GC
.setAttr(buf
.ptr
, GC
.BlkAttr
.NO_INTERIOR
);
137 buf
.ptr
[bufused
++] = ch
;
140 if (futureeof
) { eof
= true; futureeof
= false; }
142 static if (!reuse
) s
= null;
144 bool wasChar
= false;
147 if (futureeof
) break;
153 static if (keepTerm
) putch('\r');
157 static if (keepTerm
) { putch('\r'); putch('\n'); }
160 } else if (ch
== '\n') {
162 static if (keepTerm
) putch('\n');
172 static if (!reuse
) s
= (bufused ? buf
.ptr
[0..bufused
].idup
: "");
176 return BLR
!(keepTerm
, reuseBuffer
, ST
)(fl
);
180 // ////////////////////////////////////////////////////////////////////////// //
181 public auto readf(Char
:dchar, A
...) (VFile fl
, const(Char
)[] fmt
, A args
) { return readfImpl
!(Char
)(fl
, fmt
, args
); }
182 public auto readf(ST
, Char
:dchar, A
...) (auto ref ST fl
, const(Char
)[] fmt
, A args
) if (!is(ST
== VFile
) && isRorWStream
!ST
) { return readfImpl
!(Char
, ST
)(fl
, fmt
, args
); }
184 private auto readfImpl(Char
:dchar, ST
, A
...) (auto ref ST fl
, const(Char
)[] fmt
, A args
) {
185 import std
.format
: formattedRead
;
186 static struct Reader(ST
) {
190 this() (auto ref ST afl
) { fl
= afl
; if (fl
.eof
) eof
= true; else popFront(); }
191 @property bool empty () const pure nothrow @safe @nogc { return eof
; }
192 @property char front () const pure nothrow @safe @nogc { return ch
; }
193 void popFront() { if (!eof
) { eof
= (fl
.rawRead((&ch
)[0..1]).length
== 0); } }
195 auto rd
= Reader
!ST(fl
);
196 return formattedRead(rd
, fmt
, args
);
200 // ////////////////////////////////////////////////////////////////////////// //
201 public string
readln() (VFile fl
) { return readlnImpl(fl
); }
202 public string
readln(ST
) (auto ref ST fl
) if (!is(ST
== VFile
) && isRorWStream
!ST
) { return readlnImpl
!ST(fl
); }
203 public string
readln() () { return readlnImpl(stdin
); }
206 private string
readlnImpl(ST
) (auto ref ST fl
) {
208 if (fl
.eof
) return null;
212 if (fl
.rawRead((&ch
)[0..1]).length
!= 1) break;
213 if (ch
== '\n') break;
215 if (fl
.rawRead((&ch
)[0..1]).length
!= 1) break;
216 if (ch
== '\n') break;
217 if (res
.length
== MaxLen
) throw new Exception("line too long");
220 if (res
.length
== MaxLen
) throw new Exception("line too long");
223 return cast(string
)res
; // it is safe to cast here
227 // ////////////////////////////////////////////////////////////////////////// //
228 void writeImpl(S
...) (ref VFile
.UnlockedWriterImpl wr
, S args
) {
229 import std
.traits
: isBoolean
, isIntegral
, isAggregateType
, isSomeString
, isSomeChar
;
230 foreach (/*auto*/ arg
; args
) {
231 alias A
= typeof(arg
);
232 static if (isAggregateType
!A ||
is(A
== enum)) {
233 import std
.format
: formattedWrite
;
234 formattedWrite(wr
, "%s", arg
);
235 } else static if (isSomeString
!A
) {
237 } else static if (isIntegral
!A
) {
238 import std
.conv
: toTextRange
;
239 toTextRange(arg
, wr
);
240 } else static if (isBoolean
!A
) {
241 wr
.put(arg ?
"true" : "false");
242 } else static if (isSomeChar
!A
) {
245 import std
.format
: formattedWrite
;
246 formattedWrite(wr
, "%s", arg
);
252 // ////////////////////////////////////////////////////////////////////////// //
253 public void write(A
...) (A args
) {
254 import std
.traits
: isAggregateType
;
255 static if (A
.length
== 0) {
257 } else static if (is(A
[0] == VFile
)) {
259 static if (A
.length
== 1) {
261 } else static if (A
.length
== 2 &&
262 is(typeof(args
[1]) : const(char)[]) &&
263 !is(typeof(args
[1]) == enum) &&
264 !is(Unqual
!(typeof(args
[1])) == typeof(null)) &&
265 !isAggregateType
!(typeof(args
[1])))
267 import std
.traits
: isStaticArray
;
268 // specialization for strings -- a very frequent case
269 synchronized(args
[0].wst
) {
270 //auto wr = args[0].lockedWriter;
271 auto wr
= args
[0].unlockedWriter
;
272 static if (isStaticArray
!(typeof(args
[1]))) {
279 synchronized(args
[0].wst
) {
280 //auto wr = args[0].lockedWriter;
281 auto wr
= args
[0].unlockedWriter
;
282 writeImpl(wr
, args
[1..$]);
285 } else static if (A
.length
== 1 &&
286 is(typeof(args
[0]) : const(char)[]) &&
287 !is(typeof(args
[0]) == enum) &&
288 !is(Unqual
!(typeof(args
[0])) == typeof(null)) &&
289 !isAggregateType
!(typeof(args
[0])))
291 import std
.traits
: isStaticArray
;
292 synchronized(stdout
.wst
) {
293 //auto wr = stdout.lockedWriter;
294 auto wr
= stdout
.unlockedWriter
;
295 // specialization for strings -- a very frequent case
296 static if (isStaticArray
!(typeof(args
[0]))) {
303 synchronized(stdout
.wst
) {
304 //auto wr = stdout.lockedWriter;
305 auto wr
= stdout
.unlockedWriter
;
311 public void writeln(A
...) (A args
) { .write(args
, "\n"); }
314 // ////////////////////////////////////////////////////////////////////////// //
315 public void writef(Char
:dchar, A
...) (VFile fl
, const(Char
)[] fmt
, A args
) { if (!fl
.isOpen
) throw new VFSException("can't write to closed stream"); import std
.format
: formattedWrite
; synchronized(fl
.wst
) { auto wr
= fl
.unlockedWriter
; formattedWrite(wr
, fmt
, args
); } }
316 public void writef(Char
:dchar, A
...) (const(Char
)[] fmt
, A args
) { if (!stdout
.isOpen
) return; import std
.format
: formattedWrite
; synchronized(stdout
.wst
) { auto wr
= stdout
.lockedWriter
; formattedWrite(wr
, fmt
, args
); } }
318 public void writefln(Char
:dchar, A
...) (VFile fl
, const(Char
)[] fmt
, A args
) { if (!fl
.isOpen
) throw new VFSException("can't write to closed stream"); import std
.format
: formattedWrite
; synchronized(fl
.wst
) { auto wr
= fl
.lockedWriter
; formattedWrite(wr
, fmt
, args
); wr
.put("\n"); } }
319 public void writefln(Char
:dchar, A
...) (const(Char
)[] fmt
, A args
) { if (!stdout
.isOpen
) return; import std
.format
: formattedWrite
; synchronized(stdout
.wst
) { auto wr
= stdout
.lockedWriter
; formattedWrite(wr
, fmt
, args
); wr
.put("\n"); } }