1 /++
2 	This module contains functions for converting between different number bases.  
3 	Like converting to/from hex...
4 +/
5 module utils.baseconv;
6 
7 import utils.misc;
8 import std.math;
9 
10 private uinteger toDenary(ushort fromBase, ubyte[] dat){
11 	uinteger r = 0, i = 0;
12 	foreach_reverse(cur; dat){
13 		r += pow(fromBase,i)*cur;
14 		i++;
15 	}
16 	return r;
17 }
18 ///
19 unittest{
20 	assert(toDenary(2, [1, 0, 0, 1]) == 9);
21 }
22 
23 private ubyte[] fromDenary(ushort toBase, uinteger dat){
24 	ubyte rem;
25 	ubyte[] r;
26 	while (dat>0){
27 		rem = cast(ubyte)dat%toBase;
28 		dat = (dat-rem)/toBase;
29 		r = [rem]~r;
30 	}
31 	
32 	return r;
33 }
34 ///
35 unittest{
36 	assert(fromDenary(2, 9) == [1, 0, 0, 1]);
37 }
38 
39 private string toFormat(ubyte[] ar, char[] rep){
40 	uinteger i;
41 	char[] r;
42 	r.length = ar.length;
43 	for (i=0; i<ar.length; i++){
44 		r[i] = rep[ar[i]];
45 	}
46 	return cast(string)r;
47 }
48 ///
49 unittest{
50 	assert([1, 0, 0, 1].toFormat(['0', '1']) == "1001");
51 }
52 
53 private ubyte[] fromFormat(string ar, char[] rep){
54 	uinteger i;
55 	ubyte[] r;
56 	r.length = ar.length;
57 	for (i=0; i<ar.length; i++){
58 		r[i] = cast(ubyte)rep.indexOf(ar[i]);
59 	}
60 	return r;
61 }
62 ///
63 unittest{
64 	assert("1001".fromFormat(['0', '1']) == [1, 0, 0, 1]);
65 }
66 //exported functions:
67 
68 /// Converts from denary to another base
69 /// 
70 /// denaryNumber is the denary to convert
71 /// newBaseDigits are the digits of the new base in the ascending order, for hex, this will be `cast(char[])"0123456789ABCDEF"`
72 /// newbaseDigits must have at least 2 digits
73 string denaryToBase(uinteger denaryNumber, char[] newBaseDigits){
74 	assert(newBaseDigits.length >= 2);
75 	return toFormat(fromDenary(cast(ushort)newBaseDigits.length, denaryNumber), newBaseDigits);
76 }
77 ///
78 unittest{
79 	assert(denaryToBase(161,cast(char[])"0123456789ABCDEF") == "A1");
80 }
81 
82 /// Converts from any base to denary using the digits of the provided base
83 /// 
84 /// baseNumber is the number in another base to convert to denary
85 /// baseDigits is the digits of the base to convert from, in asennding order
86 uinteger baseToDenary(string baseNumber, char[] baseDigits){
87 	assert(baseDigits.length >= 2);
88 	return toDenary(cast(ushort)baseDigits.length, fromFormat(baseNumber, baseDigits));
89 }
90 ///
91 unittest{
92 	assert(baseToDenary("A1", cast(char[])"0123456789ABCDEF") == 161);
93 }
94 
95 /// To 'encode' an unsigned integer into anarray of char
96 char[] denaryToChar(uinteger den){
97 	return cast(char[])fromDenary(256,den);
98 }
99 ///
100 unittest{
101 	assert(255.denaryToChar == cast(char[])[255]);
102 }
103 
104 /// To decode 'stream of char' into unsigned integer
105 uinteger charToDenary(char[] ch){
106 	return toDenary(256,cast(ubyte[])ch);
107 }
108 ///
109 unittest{
110 	assert(charToDenary(cast(char[])[255]) == 255);
111 }
112 
113 /// Converts a hex from string into unsigned integer
114 uinteger hexToDenary(string hex){
115 	return baseToDenary(hex, cast(char[])"0123456789ABCDEF");
116 }
117 ///
118 unittest{
119 	assert("A1".hexToDenary == 161);
120 }
121 
122 /// Converts unsigned integer into hex
123 string denaryToHex(uinteger den){
124 	return denaryToBase(den, cast(char[])"0123456789ABCDEF");
125 }
126 ///
127 unittest{
128 	assert(162.denaryToHex == "A2");
129 }
130 
131 /// Converts a binary number from string into denary
132 uinteger binaryToDenary(string bin){
133 	return baseToDenary(bin, ['0', '1']);
134 }
135 ///
136 unittest{
137 	assert("1001".binaryToDenary == 9);
138 }
139 
140 /// Converts a denary number into a binary number in string
141 string denaryToBinary(uinteger den){
142 	return denaryToBase(den, ['0', '1']);
143 }
144 ///
145 unittest{
146 	assert(9.denaryToBinary == "1001");
147 }