1 module source.strtoint;
2 
3 ulong strToInt(string s) in {
4 	assert(s.length > 0, "s must not be empty");
5 } do {
6 	if (s[0] != '0' || s.length < 3) {
7 		goto ParseDec;
8 	}
9 	
10 	switch(s[1]) {
11 		case 'x', 'X':
12 			return strToHexInt(s[2 .. $]);
13 		
14 		case 'b', 'B':
15 			return strToBinInt(s[2 .. $]);
16 		
17 		default:
18 			// Break to parse as decimal.
19 			break;
20 	}
21 	
22 ParseDec:
23 	return strToDecInt(s);
24 }
25 
26 unittest {
27 	assert(strToInt("0") == 0);
28 	assert(strToInt("42") == 42);
29 	assert(strToInt("123") == 123);
30 	assert(strToInt("0x0") == 0);
31 	assert(strToInt("0xaa") == 170);
32 	assert(strToInt("0b101") == 5);
33 }
34 
35 ulong strToDecInt(string s) in {
36 	assert(s.length > 0, "s must not be empty");
37 } do {
38 	ulong ret = 0;
39 	
40 	for (uint i = 0; i < s.length; i++) {
41 		if (s[i] == '_') continue;
42 		
43 		ret *= 10;
44 		
45 		auto d = s[i] - '0';
46 		assert(d < 10, "Only digits are expected here");
47 		ret += d;
48 	}
49 	
50 	return ret;
51 }
52 
53 unittest {
54 	assert(strToDecInt("0") == 0);
55 	assert(strToDecInt("42") == 42);
56 	assert(strToDecInt("1234567890") == 1234567890);
57 	assert(strToDecInt("18446744073709551615") == 18446744073709551615UL);
58 	assert(strToDecInt("34_56") == 3456);
59 }
60 
61 ulong strToBinInt(string s) in {
62 	assert(s.length > 0, "s must not be empty");
63 } do {
64 	ulong ret = 0;
65 	
66 	for (uint i = 0; i < s.length; i++) {
67 		if (s[i] == '_') continue;
68 		
69 		ret <<= 1;
70 		auto d = s[i] - '0';
71 		assert(d < 2, "Only 0 and 1 are expected here");
72 		ret |= d;
73 	}
74 	
75 	return ret;
76 }
77 
78 unittest {
79 	assert(strToBinInt("0") == 0);
80 	assert(strToBinInt("1010") == 10);
81 	assert(strToBinInt("0101010") == 42);
82 	assert(strToBinInt(
83 		"1111111111111111111111111111111111111111111111111111111111111111",
84 	) == 18446744073709551615UL);
85 	assert(strToBinInt("11_101_00") == 116);
86 }
87 
88 ulong strToHexInt(string s) in {
89 	assert(s.length > 0, "s must not be empty");
90 } do {
91 	ulong ret = 0;
92 	
93 	for (uint i = 0; i < s.length; i++) {
94 		// TODO: Filter these out at lexing.
95 		if (s[i] == '_') continue;
96 		
97 		// XXX: This would allow to reduce data dependacy here by using
98 		// the string length and shifting the whole amount at once.
99 		ret *= 16;
100 		
101 		auto d = s[i] - '0';
102 		if (d < 10) {
103 			ret += d;
104 			continue;
105 		}
106 		
107 		auto h = (s[i] | 0x20) - 'a' + 10;
108 		assert(h - 10 < 6, "Only hex digits are expected here");
109 		ret += h;
110 	}
111 	
112 	return ret;
113 }
114 
115 unittest {
116 	assert(strToHexInt("0") == 0);
117 	assert(strToHexInt("A") == 10);
118 	assert(strToHexInt("a") == 10);
119 	assert(strToHexInt("F") == 15);
120 	assert(strToHexInt("f") == 15);
121 	assert(strToHexInt("42") == 66);
122 	assert(strToHexInt("AbCdEf0") == 180150000);
123 	assert(strToHexInt("12345aBcDeF") == 1251004370415);
124 	assert(strToHexInt("FFFFFFFFFFFFFFFF") == 18446744073709551615UL);
125 	assert(strToHexInt("a_B_c") == 2748);
126 }