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