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 }