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 ///Tests if the input string is integer and returns true if it is. 200 bool isInteger(S)(S s) pure @safe @nogc nothrow 201 if(is(S == string) || is(S == wstring) || is(S == dstring)) { 202 if (!s.length) 203 return false; 204 if(s[0] > '9' || s[0] < '0' || (s[0] != '-' && s.length >= 2)) 205 return false; 206 if (s.length >= 2) 207 foreach(c; s[1..$]) 208 if(c > '9' || c < '0') 209 return false; 210 211 return true; 212 213 } 214 215 /** 216 * Returns true if x is power of two. 217 */ 218 public bool isPowerOf2(T = uint)(T x) pure @safe @nogc nothrow{ 219 return x && ((x & (x - 1U)) == 0U); 220 } 221 222 /** 223 * From "Hackers Delight" 224 * val remains unchanged if it is already a power of 2. 225 */ 226 public T nextPow2(T)(T val) pure @safe @nogc nothrow{ 227 val--; 228 val |= val >> 16; 229 val |= val >> 8; 230 val |= val >> 4; 231 val |= val >> 2; 232 val |= val >> 1; 233 return val + 1; 234 } 235 /+ 236 /** 237 * Safely converts an array to a type. 238 * NOTE: by 0.10.0, an external library will replace this. 239 */ 240 public T reinterpretGet(T, S)(S[] source) pure @trusted { 241 T _reinterpretGet() pure @system { 242 return (cast(T[])(cast(void[])source))[0]; 243 } 244 if(S.sizeof * source.length == T.sizeof) 245 return _reinterpretGet(); 246 else 247 throw new Exception("Reinterpretation error!"); 248 }+/ 249 /+ 250 /** 251 * Safely converts the type of an array. 252 * NOTE: by 0.10.0, an external library will replace this. 253 */ 254 public T[] reinterpretCast(T, S)(S[] source) pure @trusted { 255 T[] _reinterpretCast() pure @system { 256 return cast(T[])(cast(void[])source); 257 } 258 if((S.sizeof * source.length) % T.sizeof == 0) 259 return _reinterpretCast(); 260 else 261 throw new Exception("Reinterpretation error!"); 262 }+/ 263 /+ 264 /** 265 * Safely converts a single instance into a bytestream. 266 * NOTE: by 0.10.0, an external library will replace this. 267 */ 268 public T[] toStream(T = ubyte, S)(S source) pure @trusted { 269 T[] _toStream() pure @system { 270 return cast(T[])(cast(void[])[source]); 271 } 272 if(S.sizeof % T.sizeof == 0) 273 return _toStream(); 274 else 275 throw new Exception("Reinterpretation error!"); 276 }+/ 277 alias toStream = reinterpretAsArray; 278 /** 279 * Checks whether object `o` have implemented the given interface. 280 * Checks are done on the basis of name strings. 281 */ 282 public bool isInterface(string I)(Object o) pure @safe nothrow { 283 foreach(Interface i; o.classinfo.interfaces) { 284 if(i.classinfo.name == I) return true; 285 } 286 return false; 287 } 288 /** 289 * Compares object pointers to detect duplicates. 290 */ 291 public bool cmpObjPtr(O)(O a, O b) @nogc @trusted pure nothrow { 292 bool _cmp() @nogc @system pure nothrow { 293 return cast(void*)a == cast(void*)b; 294 } 295 return _cmp(); 296 } 297 /** 298 * Calculates the MurMurHashV3/32 value of a string. 299 * CTFE friendly. 300 */ 301 uint hashCalc(string src, const uint seed = 0) @nogc @safe pure nothrow { 302 uint scramble(uint k) @nogc @safe pure nothrow { 303 k *= 0xcc9e2d51; 304 k = (k << 15) | (k >> 17); 305 k *= 0x1b873593; 306 return k; 307 } 308 size_t pos; 309 uint h = seed, k; 310 const int remainder = cast(int)(src.length % 4); 311 const size_t length = src.length - remainder; 312 for ( ; pos < length ; pos+=4) { 313 k = (cast(uint)src[pos+3] << 24) | (cast(uint)src[pos+2] << 16) | (cast(uint)src[pos+1] << 8) | (cast(uint)src[pos+0]); 314 h ^= scramble(k); 315 h = (h << 13) | (h >> 19); 316 h = h * 5 + 0xe6546b64; 317 } 318 //Read the rest 319 k = 0; 320 for (int i = remainder ; i ; i--) { 321 k <<= 8; 322 k |= cast(uint)src[pos+i-1]; 323 } 324 // A swap is *not* necessary here because the preceding loop already 325 // places the low bytes in the low places according to whatever endianness 326 // we use. Swaps only apply when the memory is copied in a chunk. 327 h ^= scramble(k); 328 329 //Finalize 330 h ^= cast(uint)src.length; 331 h ^= h >> 16; 332 h *= 0x85ebca6b; 333 h ^= h >> 13; 334 h *= 0xc2b2ae35; 335 h ^= h >> 16; 336 return h; 337 } 338 /** 339 * Removes all symbols from the string that is not in the symbol pool. 340 */ 341 S removeUnallowedSymbols(S)(S input, S symbolList) @safe pure nothrow { 342 S result; 343 foreach (c ; input) { 344 if (count(symbolList, c)) 345 result ~= c; 346 } 347 return result; 348 } 349 S removeUnallowedDups(S)(S input, S symbolList) @safe pure nothrow { 350 S result; 351 S foundDups; 352 foreach (c ; input) { 353 if (count(symbolList, c)) { 354 if (!count(foundDups)) { 355 result ~= c; 356 foundDups ~= c; 357 } 358 } else { 359 result ~= c; 360 } 361 } 362 return result; 363 } 364 /** 365 * Clamps a value between of two. 366 */ 367 pragma(inline, true) 368 T clamp(T)(ref T input, const T min, const T max) @nogc @safe pure nothrow { 369 if (input >= max) input = max; 370 else if (input <= min) input = min; 371 return input; 372 } 373 /** 374 * Returns the lesser of two values. 375 */ 376 pragma(inline, true) 377 T min(T)(T a, T b) @nogc @safe pure nothrow { 378 return a < b ? a : b; 379 } 380 /** 381 * Returns the greater of two values. 382 */ 383 pragma(inline, true) 384 T max(T)(T a, T b) @nogc @safe pure nothrow { 385 return a > b ? a : b; 386 }