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 }