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 }