"r_vsync" console var; slightly faster light tracer
[dd2d.git] / conbuf.d
blob390bfb8aef13c436e73d66e90a543eafaf9a5621
1 module conbuf is aliced;
2 private:
4 // ////////////////////////////////////////////////////////////////////////// //
5 import core.sync.mutex : Mutex;
6 __gshared Mutex conbufLock;
7 shared static this () { conbufLock = new Mutex(); }
10 // ////////////////////////////////////////////////////////////////////////// //
11 version(test_cbuf)
12 enum ConBufSize = 64;
13 else
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 {
35 if (chrs.length) {
36 conbufLock.lock();
37 scope(exit) conbufLock.unlock();
38 import core.atomic;
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;
44 if (np == cbufhead) {
45 // we have to make some room; delete top line for this
46 for (;;) {
47 char och = cbuf.ptr[cbufhead];
48 cbufhead = (cbufhead+1)%ConBufSize;
49 if (cbufhead == np || och == '\n') break;
52 cbuf.ptr[np] = ch;
53 cbuftail = np;
59 // ////////////////////////////////////////////////////////////////////////// //
60 // warning! don't modify conbuf while the range is active!
61 public auto conbufLinesRev () nothrow @trusted @nogc {
62 static struct Line {
63 nothrow @trusted @nogc:
64 private:
65 int h, t; // head and tail, to check validity
66 int sp = -1, ep;
68 public:
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'); }
78 static struct Range {
79 nothrow @trusted @nogc:
80 private:
81 int h, t; // head and tail, to check validity
82 int pos; // position of prev line
83 Line line;
85 void toLineStart () {
86 line.ep = pos;
87 while (pos != cbufhead) {
88 int p = (pos+ConBufSize-1)%ConBufSize;
89 if (cbuf.ptr[p] == '\n') break;
90 pos = p;
92 line.sp = pos;
93 line.h = h;
94 line.t = t;
97 public:
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); }
101 void popFront () {
102 if (pos < 0 || pos == h || h != cbufhead || t != cbuftail) { line = Line.init; h = t = pos = -1; return; }
103 pos = (pos+ConBufSize-1)%ConBufSize;
104 toLineStart();
108 Range res;
109 res.h = cbufhead;
110 res.pos = res.t = cbuftail;
111 if (cbuf.ptr[res.pos] != '\n') res.pos = (res.pos+1)%ConBufSize;
112 res.toLineStart();
113 //{ import std.stdio; writeln("pos=", res.pos, "; head=", res.h, "; tail=", res.t, "; llen=", res.line.length, "; [", res.line, "]"); }
114 return res;
118 // ////////////////////////////////////////////////////////////////////////// //
119 public void conbufDump () {
120 import std.stdio;
121 int pp = cbufhead;
122 stdout.writeln("==========================");
123 for (;;) {
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');
128 break;
130 pp = (pp+1)%ConBufSize;
132 //foreach (auto s; conbufLinesRev) stdout.writeln(s, "|");
136 // ////////////////////////////////////////////////////////////////////////// //
137 version(test_cbuf) unittest {
138 conbufDump();
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));
148 conbufDump();