1 module PixelPerfectEngine.system.etc; 2 3 import std.conv; 4 import std.algorithm.mutation; 5 /* 6 * Copyright (C) 2015-2017, by Laszlo Szeremi under the Boost license. 7 * 8 * Pixel Perfect Engine, etc module 9 */ 10 11 12 ///Converts string[] to dstring[] 13 public dstring[] stringArrayConv(string[] s) pure @safe{ 14 dstring[] result; 15 foreach(ss; s){ 16 dstring ws; 17 foreach(c; ss){ 18 ws ~= c; 19 } 20 result ~= ws; 21 } 22 return result; 23 } 24 ///Returns a hexadecimal string representation of the integer. 25 S intToHex(S = string)(int i, int format = 0) pure @safe{ 26 S result; 27 do{ 28 switch(i & 0x000F){ 29 case 1: result = '1' ~ result; break; 30 case 2: result = '2' ~ result; break; 31 case 3: result = '3' ~ result; break; 32 case 4: result = '4' ~ result; break; 33 case 5: result = '5' ~ result; break; 34 case 6: result = '6' ~ result; break; 35 case 7: result = '7' ~ result; break; 36 case 8: result = '8' ~ result; break; 37 case 9: result = '9' ~ result; break; 38 case 10: result = 'A' ~ result; break; 39 case 11: result = 'B' ~ result; break; 40 case 12: result = 'C' ~ result; break; 41 case 13: result = 'D' ~ result; break; 42 case 14: result = 'E' ~ result; break; 43 case 15: result = 'F' ~ result; break; 44 default: result = '0' ~ result; break; 45 } 46 i = i >>> 4; 47 }while(i > 0); 48 if(result.length < format){ 49 for(size_t j = result.length ; j < format ; j++){ 50 result = '0' ~ result; 51 } 52 } 53 //result = result.dup.reverse; 54 return result; 55 } 56 ///Returns a octal string representation of the integer. 57 S intToOct(S = string)(int i, int format) pure @safe{ 58 string result; 59 do{ 60 switch(i & 0x0007){ 61 case 1: result = '1' ~ result; break; 62 case 2: result = '2' ~ result; break; 63 case 3: result = '3' ~ result; break; 64 case 4: result = '4' ~ result; break; 65 case 5: result = '5' ~ result; break; 66 case 6: result = '6' ~ result; break; 67 case 7: result = '7' ~ result; break; 68 default: result = '0' ~ result; break; 69 } 70 i = i >>> 3; 71 }while(i > 0); 72 if(result.length < format){ 73 for(size_t j = result.length ; j < format ; j++){ 74 result ~= '0'; 75 } 76 } 77 //result = result.dup.reverse; 78 return result; 79 } 80 ///Parses a hexadecimal int represented as a string. 81 ///Ignores characters that are not hexanumeric. 82 int parseHex(S)(S s) pure @safe{ 83 int result; 84 for(int i ; i < s.length; i++){ 85 switch(s[i]){ 86 case '0': result *= 16; break; 87 case '1': result += 1; result *= 16; break; 88 case '2': result += 2; result *= 16; break; 89 case '3': result += 3; result *= 16; break; 90 case '4': result += 4; result *= 16; break; 91 case '5': result += 5; result *= 16; break; 92 case '6': result += 6; result *= 16; break; 93 case '7': result += 7; result *= 16; break; 94 case '8': result += 8; result *= 16; break; 95 case '9': result += 9; result *= 16; break; 96 case 'a','A': result += 10; result *= 16; break; 97 case 'b','B': result += 11; result *= 16; break; 98 case 'c','C': result += 12; result *= 16; break; 99 case 'd','D': result += 13; result *= 16; break; 100 case 'e','E': result += 14; result *= 16; break; 101 case 'f','F': result += 15; result *= 16; break; 102 default: break; 103 } 104 } 105 return result; 106 } 107 ///Parses a octal int represented as a string. 108 ///Ignores characters that are not octal. 109 int parseOct(S)(S s) pure @safe{ 110 int result; 111 for(int i ; i < s.length; i++){ 112 113 switch(s[i]){ 114 case '0': result *= 8; break; 115 case '1': result += 1; result *= 8; break; 116 case '2': result += 2; result *= 8; break; 117 case '3': result += 3; result *= 8; break; 118 case '4': result += 4; result *= 8; break; 119 case '5': result += 5; result *= 8; break; 120 case '6': result += 6; result *= 8; break; 121 case '7': result += 7; result *= 8; break; 122 /+case '8': result += 8; break; 123 case '9': result += 9; break; 124 case 'a','A': result += 10; break; 125 case 'b','B': result += 11; break; 126 case 'c','C': result += 12; break; 127 case 'd','D': result += 13; break; 128 case 'e','E': result += 14; break; 129 case 'f','F': result += 15; break;+/ 130 default: break; 131 } 132 } 133 return result; 134 } 135 ///Parses a decimal int represented as a string. 136 ///Ignores characters that are not decimal. 137 int parseDec(S)(S s) pure @safe{ 138 int result; 139 for(int i ; i < s.length; i++){ 140 141 switch(s[i]){ 142 case '0': result *= 10; break; 143 case '1': result += 1; result *= 10; break; 144 case '2': result += 2; result *= 10; break; 145 case '3': result += 3; result *= 10; break; 146 case '4': result += 4; result *= 10; break; 147 case '5': result += 5; result *= 10; break; 148 case '6': result += 6; result *= 10; break; 149 case '7': result += 7; result *= 10; break; 150 case '8': result += 8; result *= 10; break; 151 case '9': result += 9; result *= 10; break; 152 /+case 'a','A': result += 10; break; 153 case 'b','B': result += 11; break; 154 case 'c','C': result += 12; break; 155 case 'd','D': result += 13; break; 156 case 'e','E': result += 14; break; 157 case 'f','F': result += 15; break;+/ 158 default: break; 159 } 160 } 161 return result; 162 } 163 ///Parses a comma separated string into a single array. 164 S[] csvParser(S)(S input, char separator = ',') pure @safe{ 165 S[] result; 166 int j; 167 for(int i ; i < input.length ; i++){ 168 if(input[i] == separator){ 169 result ~= input[j..i]; 170 j = i + 1; 171 } 172 } 173 174 return result; 175 } 176 ///Joins prettyprint strings to a single string for file storage. 177 S stringArrayJoin(S)(S[] input) pure @safe{ 178 S result; 179 foreach(s ; input){ 180 result ~= s ~ "\n"; 181 } 182 return result; 183 } 184 ///Tests if the input string is integer and returns true if it is. 185 bool isInteger(S)(S s) pure @safe{ 186 static if(S.mangleof == string.mangleof || S.mangleof == wstring.mangleof || S.mangleof == dstring.mangleof){ 187 foreach(c; s){ 188 if(c > '9' || c < '0') 189 return false; 190 } 191 return true; 192 }else static assert(false, "Template patameter " ~ S.stringof ~ " not supported in function 'bool isInteger(S)(S s)' 193 of module 'PixelPerfectEngine.system.etc'"); 194 } 195 196 /** 197 * Returns true if x is power of two. 198 */ 199 public bool isPowerOf2(T = uint)(T x) pure @safe @nogc nothrow{ 200 return x && ((x & (x - 1U)) == 0U); 201 } 202 203 /** 204 * From "Hackers Delight" 205 * val remains unchanged if it is already a power of 2. 206 */ 207 public T nextPow2(T)(T val) pure @safe @nogc nothrow{ 208 val--; 209 val |= val >> 16; 210 val |= val >> 8; 211 val |= val >> 4; 212 val |= val >> 2; 213 val |= val >> 1; 214 return val + 1; 215 } 216 /** 217 * Safely converts an array to a type. 218 * NOTE: by 0.10.0, an external library will replace this. 219 */ 220 public T reinterpretGet(T, S)(S[] source) pure @trusted { 221 T _reinterpretGet() pure @system { 222 return (cast(T[])(cast(void[])source))[0]; 223 } 224 if(S.sizeof * source.length == T.sizeof) 225 return _reinterpretGet(); 226 else 227 throw new Exception("Reinterpretation error!"); 228 } 229 /** 230 * Safely converts the type of an array. 231 * NOTE: by 0.10.0, an external library will replace this. 232 */ 233 public T[] reinterpretCast(T, S)(S[] source) pure @trusted { 234 T[] _reinterpretCast() pure @system { 235 return cast(T[])(cast(void[])source); 236 } 237 if((S.sizeof * source.length) % T.sizeof == 0) 238 return _reinterpretCast(); 239 else 240 throw new Exception("Reinterpretation error!"); 241 } 242 /** 243 * Safely converts a single instance into a bytestream. 244 * NOTE: by 0.10.0, an external library will replace this. 245 */ 246 public T[] toStream(T = ubyte, S)(S source) pure @trusted { 247 T[] _toStream() pure @system { 248 return cast(T[])(cast(void[])[source]); 249 } 250 if(S.sizeof % T.sizeof == 0) 251 return _toStream(); 252 else 253 throw new Exception("Reinterpretation error!"); 254 } 255 /** 256 * Checks whether object `o` have implemented the given interface. 257 * Checks are done on the basis of name strings. 258 */ 259 public bool isInterface(string I)(Object o) pure @safe nothrow { 260 foreach(Interface i; o.classinfo.interfaces) { 261 if(i.classinfo.name == I) return true; 262 } 263 return false; 264 } 265 /** 266 * Compares object pointers to detect duplicates. 267 */ 268 public bool cmpObjPtr(O)(O a, O b) @nogc @trusted pure nothrow { 269 bool _cmp() @nogc @system pure nothrow { 270 return cast(void*)a == cast(void*)b; 271 } 272 return _cmp(); 273 } 274 /** 275 * Calculates the MurMurHashV3/32 value of a string. 276 * CTFE friendly. 277 */ 278 uint hashCalc(string src, const uint seed = 0) @nogc @safe pure nothrow { 279 uint scramble(uint k) @nogc @safe pure nothrow { 280 k *= 0xcc9e2d51; 281 k = (k << 15) | (k >> 17); 282 k *= 0x1b873593; 283 return k; 284 } 285 size_t pos; 286 uint h = seed, k; 287 const int remainder = cast(int)(src.length % 4); 288 const size_t length = src.length - remainder; 289 for ( ; pos < length ; pos+=4) { 290 k = (cast(uint)src[pos+3] << 24) | (cast(uint)src[pos+2] << 16) | (cast(uint)src[pos+1] << 8) | (cast(uint)src[pos+0]); 291 h ^= scramble(k); 292 h = (h << 13) | (h >> 19); 293 h = h * 5 + 0xe6546b64; 294 } 295 //Read the rest 296 k = 0; 297 for (int i = remainder ; i ; i--) { 298 k <<= 8; 299 k |= cast(uint)src[pos+i-1]; 300 } 301 // A swap is *not* necessary here because the preceding loop already 302 // places the low bytes in the low places according to whatever endianness 303 // we use. Swaps only apply when the memory is copied in a chunk. 304 h ^= scramble(k); 305 306 //Finalize 307 h ^= cast(uint)src.length; 308 h ^= h >> 16; 309 h *= 0x85ebca6b; 310 h ^= h >> 13; 311 h *= 0xc2b2ae35; 312 h ^= h >> 16; 313 return h; 314 } 315 /** 316 * Clamps a value between of two. 317 */ 318 pragma(inline, true) 319 T clamp(T)(ref T input, const T min, const T max) @nogc @safe pure nothrow { 320 if (input >= max) input = max; 321 else if (input <= min) input = min; 322 return input; 323 } 324 /** 325 * Returns the lesser of two values. 326 */ 327 pragma(inline, true) 328 T min(T)(T a, T b) @nogc @safe pure nothrow { 329 return a < b ? a : b; 330 } 331 /** 332 * Returns the greater of two values. 333 */ 334 pragma(inline, true) 335 T max(T)(T a, T b) @nogc @safe pure nothrow { 336 return a > b ? a : b; 337 }