1 module conbuf
is aliced
;
4 // ////////////////////////////////////////////////////////////////////////// //
5 import core
.sync
.mutex
: Mutex
;
6 __gshared Mutex conbufLock
;
7 shared static this () { conbufLock
= new Mutex(); }
10 // ////////////////////////////////////////////////////////////////////////// //
14 enum ConBufSize
= 256*1024;
16 // each line in buffer ends with '\n'; we don't keep offsets or lengthes, as
17 // it's fairly easy to search in buffer, and drawing console is not a common
18 // thing, so it doesn't have to be superfast.
19 __gshared
char[ConBufSize
] cbuf
= 0;
20 __gshared
int cbufhead
, cbuftail
; // `cbuftail` points *at* last char
21 __gshared
bool cbufLastWasCR
= false;
22 shared static this () { cbuf
.ptr
[0] = '\n'; }
24 shared ulong changeCount
= 1;
25 public @property ulong cbufLastChange () nothrow @trusted @nogc { import core
.atomic
; return atomicLoad(changeCount
); }
28 // ////////////////////////////////////////////////////////////////////////// //
29 public void cbufLock() () { pragma(inline
, true); conbufLock
.lock(); }
30 public void cbufUnlock() () { pragma(inline
, true); conbufLock
.unlock(); }
33 // ////////////////////////////////////////////////////////////////////////// //
34 public void cbufPut (const(char)[] chrs
...) nothrow @trusted @nogc {
37 scope(exit
) conbufLock
.unlock();
39 atomicOp
!"+="(changeCount
, 1);
40 foreach (char ch
; chrs
) {
41 if (cbufLastWasCR
&& ch
== '\x0a') { cbufLastWasCR
= false; continue; }
42 if ((cbufLastWasCR
= (ch
== '\x0d')) != false) ch
= '\x0a';
43 int np
= (cbuftail
+1)%ConBufSize
;
45 // we have to make some room; delete top line for this
47 char och
= cbuf
.ptr
[cbufhead
];
48 cbufhead
= (cbufhead
+1)%ConBufSize
;
49 if (cbufhead
== np || och
== '\n') break;
59 // ////////////////////////////////////////////////////////////////////////// //
60 // warning! don't modify conbuf while the range is active!
61 public auto conbufLinesRev () nothrow @trusted @nogc {
63 nothrow @trusted @nogc:
65 int h
, t
; // head and tail, to check validity
69 @property auto front () const { pragma(inline
, true); return (sp
>= 0 ? cbuf
.ptr
[sp
] : '\x00'); }
70 @property bool empty () const { pragma(inline
, true); return (sp
< 0 || h
!= cbufhead || t
!= cbuftail
); }
71 @property auto save () { pragma(inline
, true); return Line(h
, t
, sp
, ep
); }
72 void popFront () { pragma(inline
, true); if (sp
< 0 ||
(sp
= (sp
+1)%ConBufSize
) == ep
) sp
= -1; }
73 @property usize
opDollar () { pragma(inline
, true); return (sp
>= 0 ?
(sp
> ep ? ep
+ConBufSize
-sp
: ep
-sp
) : 0); }
74 alias length
= opDollar
;
75 char opIndex (usize pos
) { pragma(inline
, true); return (sp
>= 0 ? cbuf
.ptr
[sp
+pos
] : '\x00'); }
79 nothrow @trusted @nogc:
81 int h
, t
; // head and tail, to check validity
82 int pos
; // position of prev line
87 while (pos
!= cbufhead
) {
88 int p
= (pos
+ConBufSize
-1)%ConBufSize
;
89 if (cbuf
.ptr
[p
] == '\n') break;
98 @property auto front () pure { pragma(inline
, true); return line
; }
99 @property bool empty () const { pragma(inline
, true); return (pos
< 0 || pos
== h || h
!= cbufhead || t
!= cbuftail
); }
100 @property auto save () { pragma(inline
, true); return Range(h
, t
, pos
, line
); }
102 if (pos
< 0 || pos
== h || h
!= cbufhead || t
!= cbuftail
) { line
= Line
.init
; h
= t
= pos
= -1; return; }
103 pos
= (pos
+ConBufSize
-1)%ConBufSize
;
110 res
.pos
= res
.t
= cbuftail
;
111 if (cbuf
.ptr
[res
.pos
] != '\n') res
.pos
= (res
.pos
+1)%ConBufSize
;
113 //{ import std.stdio; writeln("pos=", res.pos, "; head=", res.h, "; tail=", res.t, "; llen=", res.line.length, "; [", res.line, "]"); }
118 // ////////////////////////////////////////////////////////////////////////// //
119 public void conbufDump () {
122 stdout
.writeln("==========================");
124 if (cbuf
.ptr
[pp
] == '\n') stdout
.write('|');
125 stdout
.write(cbuf
.ptr
[pp
]);
126 if (pp
== cbuftail
) {
127 if (cbuf
.ptr
[pp
] != '\n') stdout
.write('\n');
130 pp
= (pp
+1)%ConBufSize
;
132 //foreach (auto s; conbufLinesRev) stdout.writeln(s, "|");
136 // ////////////////////////////////////////////////////////////////////////// //
137 version(test_cbuf
) unittest {
139 cbufPut("boo\n"); conbufDump();
140 cbufPut("this is another line\n"); conbufDump();
141 cbufPut("one more line\n"); conbufDump();
142 cbufPut("foo\n"); conbufDump();
143 cbufPut("more lines!\n"); conbufDump();
144 cbufPut("and even more lines!\n"); conbufDump();
145 foreach (immutable idx
; 0..256) {
146 import std
.string
: format
;
147 cbufPut("line %s\n".format(idx
));