1 module nxt.string_ex; 2 3 /** Call `dg` with `src` as input. 4 * 5 * See_Also: https://youtu.be/V6KFtzF2Hx8 6 */ 7 auto toCStringThen(alias dg, uint smallSize = 512)(const(char)[] src) 8 if (is(typeof(dg((char[]).init)))) // TODO: assert that dg takes its parameter by scope 9 { 10 import core.memory : pureMalloc, pureFree; 11 const srcLength = src.length + 1; 12 char[smallSize] stackBuf = void; 13 14 const useHeap = srcLength > stackBuf.length; 15 scope char* ptr; 16 () @trusted { 17 if (useHeap) 18 ptr = cast(typeof(ptr))pureMalloc(src.length + 1); 19 else 20 ptr = stackBuf.ptr; 21 ptr[0 .. src.length] = src[]; 22 ptr[src.length] = '\0'; 23 } (); 24 scope(exit) 25 if (useHeap) 26 () @trusted { pureFree(ptr); } (); 27 28 scope char[] buf; 29 () @trusted { 30 buf = ptr[0 .. srcLength]; 31 } (); 32 33 return dg(buf); 34 } 35 36 /// 37 @safe pure nothrow @nogc unittest 38 { 39 enum smallSize = 4; 40 const src = "42"; 41 scope char[src.length + 1] y; 42 @safe void f(in char[] x) { y = x; } 43 src.toCStringThen!(f, smallSize)(); // uses stack 44 assert(y[0 .. $ - 1] == src); 45 assert(y[$ - 1 .. $] == "\0"); 46 } 47 48 /// 49 @safe pure nothrow @nogc unittest 50 { 51 enum smallSize = 4; 52 const src = "4200"; 53 scope char[src.length + 1] y; 54 @safe void f(in char[] x) { y = x; } 55 src.toCStringThen!(f, smallSize)(); // uses heap 56 assert(y[0 .. $ - 1] == src); 57 assert(y[$ - 1 .. $] == "\0"); 58 } 59 60 /** https://discord.com/channels/242094594181955585/625407836473524246/1018276401142575188 61 */ 62 struct Stringz 63 { 64 this(string s) @safe pure nothrow @nogc 65 in (s.length >= 1 && 66 s[$ - 1] == '\0') 67 { 68 this._data = s[0 .. $ - 1]; 69 } 70 string toString() const @property @safe pure nothrow @nogc { return _data; } 71 private string _data; 72 } 73 74 enum stringz(string literal) = () { 75 Stringz result; 76 result._data = literal; // ok - literals are 0-terminated 77 return result; 78 }(); 79 80 /// 81 @safe pure unittest { 82 enum _ = stringz!("42"); 83 assert(_.toString == "42"); 84 }