1 /++
2 	This module contains contains some misc. functions. (The name says that)
3 +/
4 module utils.misc;
5 
6 import std.stdio;
7 import std.datetime;
8 
9 ///`integer is a `long` on 64 bit systems, and `int` on 32 bit systems
10 alias integer = ptrdiff_t;
11 ///`uinteger` is a `ulong` on 64 bit systems, and `uint` on 32 bit systems
12 alias uinteger = size_t;
13 
14 ///Reads a file into an array of string
15 ///Throws exception on failure
16 string[] fileToArray(string fname){
17 	try{
18 		File f = File(fname,"r");
19 		string[] r;
20 		string line;
21 		integer i=0;
22 		r.length=0;
23 		while (!f.eof()){
24 			if (i+1>=r.length){
25 				r.length+=5;
26 			}
27 			line=f.readln;
28 			if (line.length>0 && line[line.length-1]=='\n'){
29 				line.length--;
30 			}
31 			r[i]=line;
32 			i++;
33 		}
34 		f.close;
35 		r.length = i;
36 		return r;
37 	}catch (Exception e){
38 		throw e;
39 	}
40 }
41 
42 /// Writes an array of string to a file
43 /// Throws exception on failure
44 void arrayToFile(string[] array, string fname){
45 	try{
46 		File f = File(fname,"w");
47 		uinteger i;
48 		for (i=0;i<array.length;i++){
49 			f.write(array[i],'\n');
50 		}
51 		f.close;
52 	}catch (Exception e){
53 		throw e;
54 	}
55 }
56 
57 /// Returns true if an aray has an element, false if no
58 bool hasElement(T)(T[] array, T element){
59 	bool r = false;
60 	foreach(cur; array){
61 		if (cur == element){
62 			r = true;
63 			break;
64 		}
65 	}
66 	return r;
67 }
68 ///
69 unittest{
70 	assert([0, 1, 2].hasElement(2) == true);
71 	assert([0, 1, 2].hasElement(4) == false);
72 }
73 /// Returns true if array contains all elements provided in an array, else, false
74 bool hasElement(T)(T[] array, T[] elements){
75 	bool r = true;
76 	elements = elements.dup;
77 	// go through the list and match as many elements as possible
78 	for (uinteger i = 0; i < elements.length; i ++){
79 		// check if it exists in array
80 		uinteger index = array.indexOf(elements[i]);
81 		if (index == -1){
82 			r = false;
83 			break;
84 		}
85 	}
86 	return r;
87 }
88 ///
89 unittest{
90 	assert([0, 1, 2].hasElement([2, 0, 1]) == true);
91 	assert([0, 1, 2].hasElement([2, 0, 1, 1, 0, 2]) == true); // it works different-ly from `LinkedList.hasElements`
92 	assert([0, 1, 2].hasElement([1, 2]) == true);
93 	assert([0, 1, 2].hasElement([2, 4]) == false);
94 }
95 /// Returns true if all elements in array match with another array's elements.
96 /// Index, and the number of times the element is present in each array doesn't matter
97 /// 
98 /// `toMatch` is the array to perform the check on
99 /// `elements` is the array containing the elements that will be compared against
100 bool matchElements(T)(T[] toMatch, T[] elements){
101 	bool r = true;
102 	foreach(currentToMatch; toMatch){
103 		if (!elements.hasElement(currentToMatch)){
104 			r = false;
105 			break;
106 		}
107 	}
108 	return r;
109 }
110 ///
111 unittest{
112 	assert("Hello".matchElements("aeloH") == true);
113 	assert("abcd".matchElements("cda") == false);
114 }
115 
116 /// Returns the index of an element in an array, negative one if not found
117 integer indexOf(T)(T[] array, T element){
118 	integer i;
119 	for (i = 0; i < array.length; i++){
120 		if (array[i] == element){
121 			break;
122 		}
123 	}
124 	//check if it was not found, and the loop just ended
125 	if (i >= array.length || array[i] != element){
126 		i = -1;
127 	}
128 	return i;
129 }
130 ///
131 unittest{
132 	assert([0, 1, 2].indexOf(1) == 1);
133 	assert([0, 1, 2].indexOf(4) == -1);
134 }
135 
136 /// Removes element(s) from an array, and returns the modified array;
137 T[] deleteElement(T)(T[] dat, uinteger pos, uinteger count=1){
138 	T[] ar1, ar2;
139 	ar1 = dat[0..pos];
140 	ar2 = dat[pos+count..dat.length];
141 	return ar1~ar2;
142 }
143 ///
144 unittest{
145 	assert([0, 1, 2].deleteElement(1) == [0, 2]);
146 	assert([0, 1, 2].deleteElement(0, 2) == [2]);
147 }
148 
149 /// Inserts an array into another array, returns the result;
150 T[] insertElement(T)(T[] dat, T[] ins, uinteger pos){
151 	T[] ar1, ar2;
152 	ar1 = dat[0..pos];
153 	ar2 = dat[pos..dat.length];
154 	return ar1~ins~ar2;
155 }
156 ///
157 unittest{
158 	assert([0, 2].insertElement([1, 1], 1) == [0, 1, 1, 2]);
159 	assert([2].insertElement([0, 1], 0) == [0, 1, 2]);
160 }
161 /// Inserts an element into an array
162 T[] insertElement(T)(T[] dat, T ins, uinteger pos){
163 	T[] ar1, ar2;
164 	ar1 = dat[0..pos];
165 	ar2 = dat[pos..dat.length];
166 	return ar1~[ins]~ar2;
167 }
168 ///
169 unittest{
170 	assert([0, 2].insertElement(1, 1) == [0, 1, 2]);
171 	assert([2].insertElement(1, 0) == [1, 2]);
172 }
173 
174 /// returns the reverse of an array
175 T[] reverseArray(T)(T[] s){
176 	integer i, writePos = 0;
177 	T[] r;
178 	r.length = s.length;
179 
180 	for (i = s.length-1; writePos < r.length; i--){
181 		r[writePos] = s[i];
182 		writePos ++;
183 	}
184 	return r;
185 }
186 ///
187 unittest{
188 	assert([1, 2, 3, 4].reverseArray == [4, 3, 2, 1]);
189 }
190 
191 /// Returns true if a string is a number, with a decimal point, or without
192 bool isNum(string s){
193 	bool r=true;
194 	uinteger i;
195 	bool hasDecimalPoint = false;
196 	for (i=0;i<s.length;i++){
197 		if (!"0123456789".hasElement(s[i])){
198 			if (s[i] == '.' && !hasDecimalPoint){
199 				hasDecimalPoint = true;
200 			}else{
201 				r = false;
202 				break;
203 			}
204 		}
205 	}
206 	return r;
207 }
208 ///
209 unittest{
210 	assert("32".isNum == true);
211 	assert("32.2".isNum == true);
212 	assert("32.2.4".isNum == false);
213 	assert("5.a".isNum == false);
214 	assert("thisIsAVar_1234".isNum == false);
215 }
216 
217 /// Returns a string with all uppercase alphabets converted into lowercase
218 string lowercase(string s){
219 	string tmstr;
220 	ubyte tmbt;
221 	ubyte diff = 'a' - 'A';
222 	for (integer i=0;i<s.length;i++){
223 		tmbt = cast(ubyte) s[i];
224 		if (tmbt>='A' && tmbt<='Z'){
225 			tmbt += diff;
226 			tmstr ~= cast(char) tmbt;
227 		}else{
228 			tmstr ~= s[i];
229 		}
230 	}
231 	
232 	return tmstr;
233 }
234 ///
235 unittest{
236 	assert("ABcD".lowercase == "abcd");
237 	assert("abYZ".lowercase == "abyz");
238 }
239 
240 /// returns true if all characters in a string are alphabets, uppercase, lowercase, or both
241 bool isAlphabet(string s){
242 	uinteger i;
243 	bool r=true;
244 	for (i=0;i<s.length;i++){
245 		if ((s[i] < 'a' || s[i] > 'z') && (s[i]<'A' || s[i] > 'Z')){
246 			r = false;
247 			break;
248 		}
249 	}
250 	return r;
251 }
252 ///
253 unittest{
254 	assert("aBcDEf".isAlphabet == true);
255 	assert("ABCd_".isAlphabet == false);
256 	assert("ABC12".isAlphabet == false);
257 }
258 
259 /// generates a markdown table for some data.
260 /// 
261 /// `headings` is the headings for each column. Left-to-Right
262 /// `data` contains each row's data. All rows must be same length
263 string[] makeTable(T)(string[] headings, T[][] data){
264 	assert(headings.length > 0, "cannot make table with no headings");
265 	assert(data.length > 0, "cannot make table with no data");
266 	assert(headings.length == data[0].length, "headings.length does not equal data.length "~to!string(headings.length)~"!="~
267 		to!string(data[0].length));
268 	import utils.lists;
269 	// stores the data in string
270 	string[][] sData;
271 	// convert it all to string
272 	static if (is (T == string)){
273 		sData = data;
274 	}else{
275 		sData.length = data.length;
276 		foreach (rowNum, row; data){
277 			sData[rowNum].length = row.length;
278 			foreach (cellNum, cell; row){
279 				sData[rowNum][cellNum] = to!string(cell);
280 			}
281 		}
282 	}
283 	// now make the table
284 	LinkedList!string table = new LinkedList!string;
285 	// add headings
286 	{
287 		string line;
288 		string alignment;
289 		line = headings[0];
290 		alignment = "---";
291 		for (uinteger i = 1; i < headings.length; i ++){
292 			line ~= " | "~headings[i];
293 			alignment ~= " | ---";
294 		}
295 		table.append([line, alignment]);
296 	}
297 	// now begin with the data
298 	foreach (row; sData){
299 		string line/* = row[0]*/;
300 		foreach (cell; row){
301 			line ~= cell~" | ";
302 		}
303 		line.length -= 3;
304 		table.append (line);
305 	}
306 	string[] r = table.toArray;
307 	.destroy(table);
308 	return r;
309 }