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