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