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 }