Mercurial > projects > qtd
annotate d2/qtd/ctfe/Integer.d @ 411:6fe37cbd9510
Octal literals have been deprecated, fix build.
author | David Nadlinger <code@klickverbot.at> |
---|---|
date | Mon, 18 Apr 2011 00:16:33 +0200 |
parents | 96a75b1e5b26 |
children |
rev | line source |
---|---|
288 | 1 /** |
2 * CTFE Integer routines. | |
3 * | |
4 * Authors: Daniel Keep <daniel.keep@gmail.com> | |
5 * Copyright: See LICENSE. | |
6 */ | |
344 | 7 module qtd.ctfe.Integer; |
288 | 8 |
9 /** | |
10 * Formats an integer as a string. You can optionally specify a different | |
11 * base; any value between 2 and 16 inclusive is supported. | |
12 * | |
13 * Params: | |
14 * v = value to format. | |
15 * base = base to use; defaults to 10. | |
16 * Returns: | |
17 * integer formatted as a string. | |
18 */ | |
19 | |
20 string format_ctfe(intT)(intT v, int base = 10) | |
21 { | |
22 static if( !is( intT == ulong ) ) | |
23 { | |
24 return (v < 0) | |
25 ? "-" ~ format_ctfe(cast(ulong) -v, base) | |
26 : format_ctfe(cast(ulong) v, base); | |
27 } | |
28 else | |
29 { | |
30 assert( 2 <= base && base <= 16, | |
31 "base must be between 2 and 16; got " ~ format_ctfe(base, 10) ); | |
32 | |
33 string r = ""; | |
34 do | |
35 { | |
36 r = INT_CHARS[cast(size_t)(v % base)] ~ r; | |
37 v /= base; | |
38 } | |
39 while( v > 0 ); | |
40 return r; | |
41 } | |
42 } | |
43 | |
44 /** | |
45 * Parses an integer value from a string. You can optionally specify a | |
46 * different base; any value between 2 and 16 inclusive is supported. | |
47 * | |
48 * Note that this does not fail if it cannot consume the entire string; | |
49 * use returnUsed to determine the number of characters consumed. | |
50 * | |
51 * Params: | |
52 * str = string to parse. | |
53 * returnUsed = defaults to false; if set to true, returns the number of | |
54 * characters consumed from the string instead of the | |
55 * parsed value. | |
56 * base = base to use; defaults to 10. | |
57 * Returns: | |
58 * either the parsed integer or the number of characters consumed, | |
59 * depending on the value of returnUsed. | |
60 */ | |
61 | |
62 intT parse_ctfe(intT)(string str, bool returnUsed = false, int base = 10) | |
63 { | |
64 auto origStr = str; | |
65 | |
66 assert( 2 <= base && base <= 16, | |
67 "base must be between 2 and 16; got " ~ format_ctfe(base, 10) ); | |
68 | |
69 bool neg = false; | |
70 if( str.length > 0 && str[0] == '-' ) | |
71 { | |
72 neg = true; | |
73 str = str[1..$]; | |
74 } | |
75 | |
76 if( intT.min == 0 && neg ) | |
77 assert(false, "underwhile while parsing \"" ~ origStr | |
78 ~ "\" as a " ~ intT.stringof ~ ": cannot represent negative " | |
79 ~ "values"); | |
80 | |
81 intT r = 0; | |
82 size_t used = 0; | |
83 | |
84 foreach( c ; str ) | |
85 { | |
86 int cv = -1; | |
87 | |
88 if( '0' <= c && c <= '9' ) | |
89 cv = c - '0'; | |
90 | |
91 else if( 'A' <= c && c <= 'Z' ) | |
92 cv = 10 + c - 'A'; | |
93 | |
94 else if( 'a' <= c && c <= 'z' ) | |
95 cv = 10 + c - 'a'; | |
96 | |
97 if( cv >= base || cv < 0 ) | |
98 break; | |
99 | |
100 auto oldR = r; | |
101 r = r*base + cast(intT) cv; | |
102 ++ used; | |
103 | |
104 if( r < oldR ) | |
105 assert(false, "overflow while parsing \"" ~ origStr | |
106 ~ "\" as a " ~ intT.stringof); | |
107 } | |
108 | |
109 if( neg ) | |
110 { | |
111 r = -r; | |
112 ++used; | |
113 } | |
114 | |
115 if( returnUsed ) | |
116 { | |
117 assert( used < intT.max, "overflow attempting to return " | |
118 ~ "number of characters consumed in a " ~ intT.stringof ); | |
119 | |
120 return used; | |
121 } | |
122 else | |
123 return r; | |
124 } | |
125 | |
126 /** | |
127 * Like parse_ctfe, except it will raise an error if the provided string | |
128 * cannot be parsed in its entirety. | |
129 * | |
130 * Params: | |
131 * str = the string to parse. | |
132 * base = base to use; defaults to 10. | |
133 * Returns: | |
134 * the parsed integer. | |
135 */ | |
136 | |
137 intT parseAll_ctfe(intT)(string str, int base = 10) | |
138 { | |
139 auto used = parse_ctfe!(intT)(str, true, base); | |
140 assert( used == str.length, "could not parse entire string \"" ~ str | |
141 ~ "\"" ); | |
142 return parse_ctfe!(int)(str, false, base); | |
143 } | |
144 | |
145 private | |
146 { | |
147 const INT_CHARS = "0123456789abcdef"; | |
148 } | |
149 | |
150 version( Unittest ) | |
151 { | |
411
6fe37cbd9510
Octal literals have been deprecated, fix build.
David Nadlinger <code@klickverbot.at>
parents:
344
diff
changeset
|
152 import std.conv : octal; |
288 | 153 static assert( format_ctfe(0) == "0", "got: " ~ format_ctfe(0) ); |
154 static assert( format_ctfe(1) == "1" ); | |
155 static assert( format_ctfe(-1) == "-1" ); | |
156 static assert( format_ctfe(42) == "42" ); | |
157 static assert( format_ctfe(0xf00, 16) == "f00" ); | |
411
6fe37cbd9510
Octal literals have been deprecated, fix build.
David Nadlinger <code@klickverbot.at>
parents:
344
diff
changeset
|
158 static assert( format_ctfe(octal!123, 8) == "123" ); |
288 | 159 |
160 static assert( parse_ctfe!(long)("0") == 0 ); | |
161 static assert( parse_ctfe!(long)("1") == 1 ); | |
162 static assert( parse_ctfe!(long)("-1") == -1 ); | |
163 static assert( parse_ctfe!(long)("42") == 42 ); | |
164 static assert( parse_ctfe!(long)("f00", false, 16) == 0xf00 ); | |
411
6fe37cbd9510
Octal literals have been deprecated, fix build.
David Nadlinger <code@klickverbot.at>
parents:
344
diff
changeset
|
165 static assert( parse_ctfe!(long)("123", false, 8) == octal!123 ); |
288 | 166 static assert( parse_ctfe!(long)("123ax", true) == 3 ); |
167 static assert( parse_ctfe!(long)("123ax", true, 16) == 4 ); | |
168 | |
169 static assert( parseAll_ctfe!(long)("123") == 123 ); | |
170 } |