1 /// Module to replace std.stdio write functions to @nogc ones
2 module mutils.stdio;
3 
4 import core.stdc.stdio : fwrite, printf, stdout;
5 import std.meta : aliasSeqOf;
6 import std.traits;
7 
8 import mutils.conv;
9 
10 static char[1024] gTmpStdioStrBuff; // Own buffer to be independant from mutils.conv 
11 
12 /**
13  * Writes string to stdout
14  * Compared to std.stdio.writeln this writeln is not using GC, can print @disable this() structs, can print core.simd.vector's
15  * write is not pure but we will pretend it is to enable write debug
16  **/
17 void write(T...)(auto ref const T el) @trusted {
18 	static void writeImpl(EL)(auto ref const EL el) {
19 		string elStr = to!(string)(el, gTmpStdioStrBuff[]);
20 		fwrite(elStr.ptr, 1, elStr.length, stdout);
21 	}
22 
23 	static auto assumePure(DG)(scope DG t)
24 			if (isFunctionPointer!DG || isDelegate!DG) {
25 		enum attrs = functionAttributes!DG | FunctionAttribute.pure_;
26 		return cast(SetFunctionAttributes!(DG, functionLinkage!DG, attrs)) t;
27 	}
28 
29 	assumePure(() => writeImpl(el[0]))();
30 	static if (T.length > 1) {
31 		write(el[1 .. $]);
32 	}
33 }
34 
35 /// Like write but adds new line at end
36 void writeln(T...)(auto ref const T el) {
37 	write(el, "\n");
38 }
39 
40 /// Like writeln but adds space beetwen arguments
41 void writelns(T...)(auto ref const T el) {
42 	foreach (e; el) {
43 		write(e, ' ');
44 	}
45 	write("\n");
46 }
47 
48 /// Writes format to stdout changing %s to proper argument
49 /// Only %s is supported, it is not printf
50 void writefln(T...)(string format, auto ref const T el) {
51 	alias indices = aliasSeqOf!([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 123]);
52 	int lastEnd = 0;
53 	int elementsWritten = 0;
54 	for (int i = 0; i < format.length; i++) {
55 		char c = format[i];
56 		if (c != '%') {
57 			continue;
58 		}
59 		assert(format[i + 1] == 's'); // Only %s is supported
60 		write(format[lastEnd .. i]);
61 		lastEnd = i + 2;
62 	sw:
63 		switch (elementsWritten) {
64 			foreach (elNum; indices[0 .. el.length]) {
65 		case elNum:
66 				write(el[elNum]);
67 				break sw;
68 			}
69 		default:
70 			assert(0, "Wrong number of specifiers and parameters");
71 		}
72 
73 		elementsWritten++;
74 
75 	}
76 	write("\n");
77 }
78 
79 private struct TestStruct {
80 @nogc nothrow @safe pure:
81 	@disable this();
82 	@disable this(this);
83 
84 	this(int i) {
85 	}
86 
87 	int a;
88 	double c;
89 }
90 
91 // Function because we dont want to prit something during tests
92 private void testMutilsStdio() @nogc nothrow @safe pure {
93 	TestStruct w = TestStruct(3);
94 	writeln(true);
95 	writeln(false);
96 	write("__text__ ");
97 	writeln(w, " <- this is struct");
98 	// arrays
99 	int[9] arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
100 	writeln(arr[]);
101 	writeln(arr);
102 	version (X86_64) {
103 		// simd
104 		import core.simd;
105 
106 		ubyte16 vec = 14;
107 		writeln(vec);
108 	}
109 	//  writeln spaced 	
110 	writelns(1, 2, 3, 4, 5, 6, 7, 8, 9);
111 	//  writefln
112 	writefln("%s <- this is something | and this is something -> %s", w, 1);
113 	//  writeln empty
114 	writeln();
115 }
116 
117 unittest {
118 	//testMutilsStdio();
119 }