1 module m3.Transform; 2 3 private: 4 5 static import core.stdc.stdlib; 6 alias strtol = core.stdc.stdlib.strtol; 7 alias strtoul = core.stdc.stdlib.strtoul; 8 alias strtof = core.stdc.stdlib.strtof; 9 alias strtod = core.stdc.stdlib.strtod; 10 11 static import core.stdc.stdio; 12 alias sprintf = core.stdc.stdio.sprintf; 13 14 static import core.stdc.string; 15 alias strlen = core.stdc..string.strlen; 16 alias strtok = core.stdc..string.strtok; 17 18 static import std.traits; 19 alias isNumeric = std.traits.isNumeric; 20 alias isBoolean = std.traits.isBoolean; 21 alias isSomeString = std.traits.isSomeString; 22 alias isSomeChar = std.traits.isSomeChar; 23 24 static import m3.m3; 25 26 public: 27 28 @nogc 29 T convert(T)(string str) nothrow if (isNumeric!(T) || isBoolean!(T)) { 30 static if (is(T : ulong)) { 31 immutable ulong value = strtoul(str.ptr, null, 0); 32 static if (is(T == ulong)) 33 return value; 34 else 35 return cast(T) value; 36 } else static if (is(T : long)) { 37 immutable long value = strtol(str.ptr, null, 0); 38 static if (is(T == long)) 39 return value; 40 else 41 return cast(T) value; 42 } else static if (is(T == float)) 43 return strtof(str.ptr, null); 44 else static if (is(T : real)) { 45 immutable real value = strtod(str.ptr, null); 46 static if (is(T == real)) 47 return value; 48 else 49 return cast(T) value; 50 } else static if (is(T == bool)) 51 return strtol(str.ptr, null, 0); 52 else 53 static assert(0); 54 } 55 56 @nogc 57 string convert(T)(T value) nothrow if (isNumeric!(T) || isBoolean!(T)) { 58 static char[16] buf; 59 60 static if (is(T : ulong)) 61 sprintf(buf.ptr, "%u", value); 62 else static if (is(T : long)) 63 sprintf(buf.ptr, "%d", value); 64 else static if (is(T : real)) 65 sprintf(buf.ptr, "%f", value); 66 else static if (is(T == bool)) 67 sprintf(buf.ptr, "%d", value); 68 else 69 static assert(0); 70 71 return cast(immutable) buf[0 .. strlen(buf.ptr)]; 72 } 73 74 @nogc 75 string format(size_t SIZE = 256, Args...)(string format, auto ref Args args) nothrow { 76 static assert(SIZE >= (Args.length * 16)); 77 78 static char[SIZE] buf = void; 79 80 size_t i = 0, j = 0; 81 foreach (immutable size_t ai, arg; args) { 82 for (; j < format.length; j++) { 83 if (format[j] == '{') { 84 if ((j + 1) < format.length && format[j + 1] == '}') { 85 static if (isSomeString!(Args[ai])) 86 immutable string s = arg; 87 else static if (isSomeChar!(Args[ai])) { 88 const char[1] str = arg; 89 immutable string s = cast(immutable) str; 90 } else static if (is(Args[ai] == class)) 91 immutable string s = arg ? arg.toString() : null.stringof; 92 else static if (is(Args[ai] == struct)) 93 immutable string s = arg.toString(); 94 else static if (is(Args[ai] : U[], U)) 95 static assert(0, "Arrays cannot be formated."); 96 else 97 immutable string s = convert(arg); 98 99 buf[i .. i + s.length] = s; 100 101 i += s.length; 102 j += 2; 103 104 break; 105 } 106 } 107 108 buf[i] = format[j]; 109 i++; 110 } 111 } 112 113 if (j < format.length) { 114 immutable size_t r = format.length - j; 115 buf[i .. i + r] = format[j .. $]; 116 117 i += r; 118 } 119 120 return cast(immutable) buf[0 .. i]; 121 } 122 123 @nogc 124 string[] split(string str, char delim) nothrow { 125 size_t count = 0; 126 foreach (char c; str) { 127 if (c == delim) 128 count++; 129 } 130 131 if (count == 0) 132 return null; 133 134 count++; 135 136 string[] result = m3.m3.make!(string[])(count); 137 size_t i = 0; 138 139 char* p = strtok(cast(char*) str.ptr, &delim); 140 result[i++] = cast(immutable) p[0 .. strlen(p)]; 141 142 while (count > i) { 143 p = strtok(null, &delim); 144 if (p) 145 result[i++] = cast(immutable) p[0 .. strlen(p)]; 146 else 147 break; 148 } 149 150 return result; 151 } 152 153 version (unittest) { 154 class A { 155 @nogc 156 override string toString() const pure nothrow { 157 return "A"; 158 } 159 } 160 161 struct B { 162 @nogc 163 string toString() const pure nothrow { 164 return "B"; 165 } 166 } 167 } 168 169 @nogc 170 unittest { 171 // Convert to 172 173 assert(convert!(int)("152") == 152); 174 assert(convert!(uint)("152") == 152); 175 176 assert(convert!(byte)("152")); 177 assert(convert!(ubyte)("152") == 152); 178 179 assert(convert!(short)("152") == 152); 180 assert(convert!(ushort)("152") == 152); 181 182 assert(convert!(long)("152") == 152); 183 assert(convert!(ulong)("152") == 152); 184 185 assert(convert!(int)("152.52") == 152); 186 187 assert(convert!(float)("152.52") is 152.52f); 188 assert(convert!(double)("152.52") == 152.52); 189 //assert(convert!(real)("152.52") == real(152.52)); 190 191 // Convert from 192 193 assert(convert(152) == "152"); 194 assert(convert(152.52f) == "152.520004"); 195 assert(convert(152.52) == "152.520000"); 196 assert(convert(false) == "0"); 197 assert(convert(true) == "1"); 198 199 // Format 200 201 assert(format("test_{}.png", 1) == "test_1.png"); 202 assert(format("test_{}.png", '0') == "test_0.png"); 203 assert(format("{} + {} = {}", 42, 23, 42 + 23) == "42 + 23 = 65"); 204 assert(format("Erst kommt die {}, dann die {} und am Ende die {}. Nicht zu vergessen die {}, die kommt vor {}.", 11, 12, 42, 23, 42) == 205 "Erst kommt die 11, dann die 12 und am Ende die 42. Nicht zu vergessen die 23, die kommt vor 42."); 206 assert(format("Hallo {}, ich bin {} und {} Jahre alt.", "Foo", "Bar", 42) == "Hallo Foo, ich bin Bar und 42 Jahre alt."); 207 208 const int[2] iarr = [1, 2]; 209 assert(!__traits(compiles, { format("Foo {} Bar", iarr); })); 210 211 A a; 212 B b; 213 214 assert(format(" A : {}, B = {}", a, b) == " A : null, B = B"); 215 216 // split 217 218 string str = "Foo:Bar:Quatz"; 219 auto result = str.split(':'); 220 221 assert(result.length == 3); 222 assert(result[0] == "Foo"); 223 assert(result[1] == "Bar"); 224 assert(result[2] == "Quatz"); 225 226 m3.m3.destruct(result); 227 }