1 /** 2 nulib conversion functions. 3 4 Copyright: 5 Copyright © 2023-2025, Kitsunebi Games 6 Copyright © 2023-2025, Inochi2D Project 7 8 License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 9 Authors: Luna Nielsen 10 */ 11 module nulib.conv; 12 import nulib.c.stdlib; 13 import nulib.c.stdio; 14 import nulib.string; 15 import nulib.math; 16 import nulib.text.ascii; 17 import numem.core.traits; 18 import numem.core.hooks; 19 import numem.core.exception; 20 21 // TODO: This entire module should be rewritten into pure D. 22 // Relying on the C standard library here is probably 23 // not the best idea for portability. 24 25 /** 26 Converts the given string slice to an integral value. 27 28 Params: 29 str = The string to convert. 30 base = The base to read the string as. 31 32 Returns: 33 The integral value on success, or $(D 0) on failure. 34 */ 35 T to_integral(T)(inout(char)[] str, int base = 10) @nogc nothrow if (__traits(isIntegral, T)) { 36 if (str.length == 0) 37 return T.init; 38 39 auto tmp = _tmpbuffer!8(str); 40 ulong out_; 41 switch(base) { 42 case 8: 43 cast(void)sscanf(tmp.ptr, "%llo", &out_); 44 return cast(T)out_; 45 46 case 10: 47 static if (T.sizeof <= 4) 48 return cast(T)atoi(tmp.ptr); 49 else 50 return cast(T)atoll(tmp.ptr); 51 52 case 16: 53 cast(void)sscanf(tmp.ptr, "%8llx", &out_); 54 return cast(T)out_; 55 56 default: 57 return T.init; 58 } 59 } 60 61 /// ditto 62 alias toInt = to_integral; 63 64 /** 65 Converts the given string slice to an floating point value. 66 67 Params: 68 str = The string to convert. 69 70 Returns: 71 The floating point value on success, or $(D 0.0) on failure. 72 */ 73 T to_floating(T)(inout(char)[] str) @nogc nothrow if (__traits(isFloating, T)) { 74 auto tmp = _tmpbuffer!32(str); 75 return cast(T)atof(tmp.ptr); 76 } 77 78 /// ditto 79 alias toFloat = to_floating; 80 81 /** 82 Converts the given value to a string. 83 84 Params: 85 value = The input value. 86 87 Returns: 88 A string parsed from $(D input). 89 */ 90 nstring to_string(T)(T value) @nogc { 91 static if (isStringable!T) { 92 93 return nstring(assumeNoThrowNoGC((T value) { return input.toString(); }, value)); 94 } static if (isPointer!T) { 95 96 return to_string_impl("%p", value); 97 } else static if (__traits(isIntegral, T)) { 98 enum ifmtstr = __traits(isUnsigned, T) ? "%.*u" : "%.*i"; 99 100 return to_string_impl(ifmtstr, T.sizeof, value); 101 } else static if (__traits(isFloating, T)) { 102 103 return to_string_impl("%f", value); 104 } else { 105 106 return nstring(T.stringof); 107 } 108 } 109 110 /// ditto 111 alias text = to_string; 112 113 /** 114 Converts the given value to a hexidecimal string. 115 116 Params: 117 value = The input value. 118 119 Returns: 120 A string parsed from $(D input). 121 */ 122 nstring to_hex_string(T)(T value, bool lowercase = true) if (__traits(isIntegral, T)) { 123 nstring tmp = to_string_impl("%.*x", T.sizeof*2, value); 124 125 if (lowercase) { 126 foreach(ref char c; cast(char[])tmp[]) { 127 c = toLower(c); 128 } 129 } 130 return tmp; 131 } 132 133 /// ditto 134 alias toHexString = to_hex_string; 135 136 /** 137 Converts the given value to a octal string. 138 139 Params: 140 value = The input value. 141 142 Returns: 143 A string parsed from $(D input). 144 */ 145 nstring to_oct_string(T)(T value) if (__traits(isIntegral, T)) { 146 return to_string_impl("%.*o", T.sizeof*2, value); 147 } 148 149 /// ditto 150 alias toOctalString = to_oct_string; 151 152 153 154 /** 155 Parses a hexidecimal number from the source. 156 157 Params: 158 source = The source string 159 160 Returns: 161 The number parsed from the source string. 162 */ 163 T parseHex(T, S)(auto ref S source) @nogc nothrow 164 if (__traits(isIntegral, T)) { 165 enum maxRead = T.sizeof*2; 166 ulong result; 167 ubyte b; 168 169 foreach(i; 0..min(maxRead, source.length)) { 170 b = (source[i] & 0xF) + (source[i] >> 6) | ((source[i] >> 3) & 0x8); 171 result = (result << 4) | b; 172 } 173 return cast(T)result; 174 } 175 176 177 // 178 // IMPLEMENTATION DETAILS 179 // 180 181 private: 182 183 // Tables that contain the various printf modifiers 184 // used in string conversion. 185 __gshared const(char)*[4][2] _NU_IFMT_TABLE = [ 186 ["%hhu", "%hu", "%u", "%llu"], 187 ["%hhi", "%hi", "%i", "%lli"] 188 ]; 189 190 __gshared const(char)*[4][2] _NU_IFMT_TABLE_HEX = [ 191 ["%hhx", "%hx", "%x", "%llx"], 192 ["%hhX", "%hX", "%X", "%llX"] 193 ]; 194 195 __gshared const(char)*[4] _NU_IFMT_TABLE_OCT = 196 ["%hho", "%ho", "%o", "%llo"]; 197 198 nstring to_string_impl(T...)(const(char)* fmtstring, T input) @nogc { 199 int reqlen = snprintf(null, 0, fmtstring, input); 200 201 if (reqlen) { 202 size_t rlen = reqlen+1; 203 204 char* tmp = cast(char*)nu_malloc(rlen); 205 cast(void)snprintf(tmp, rlen, fmtstring, input); 206 207 nstring out_ = nstring(tmp[0..rlen]); 208 nu_free(cast(void*)tmp); 209 return out_; 210 } 211 212 return nstring.init; 213 } 214 215 /** 216 Creates a temporary buffer of the specified length. 217 */ 218 char[len] _tmpbuffer(uint len)(inout(char)[] str) return { 219 size_t tbOffset = min(8, str.length); 220 char[len] tmp = 0; 221 tmp[0..tbOffset] = str[0..tbOffset]; 222 return tmp; 223 }