comparison d2/qtd/ctfe/Integer.d @ 344:96a75b1e5b26

project structure changes
author Max Samukha <maxter@spambox.com>
date Fri, 14 May 2010 12:14:37 +0300
parents qt/qtd/ctfe/Integer.d@f9559a957be9
children 6fe37cbd9510
comparison
equal deleted inserted replaced
343:552647ec0f82 344:96a75b1e5b26
1 /**
2 * CTFE Integer routines.
3 *
4 * Authors: Daniel Keep <daniel.keep@gmail.com>
5 * Copyright: See LICENSE.
6 */
7 module qtd.ctfe.Integer;
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 {
152 static assert( format_ctfe(0) == "0", "got: " ~ format_ctfe(0) );
153 static assert( format_ctfe(1) == "1" );
154 static assert( format_ctfe(-1) == "-1" );
155 static assert( format_ctfe(42) == "42" );
156 static assert( format_ctfe(0xf00, 16) == "f00" );
157 static assert( format_ctfe(0123, 8) == "123" );
158
159 static assert( parse_ctfe!(long)("0") == 0 );
160 static assert( parse_ctfe!(long)("1") == 1 );
161 static assert( parse_ctfe!(long)("-1") == -1 );
162 static assert( parse_ctfe!(long)("42") == 42 );
163 static assert( parse_ctfe!(long)("f00", false, 16) == 0xf00 );
164 static assert( parse_ctfe!(long)("123", false, 8) == 0123 );
165 static assert( parse_ctfe!(long)("123ax", true) == 3 );
166 static assert( parse_ctfe!(long)("123ax", true, 16) == 4 );
167
168 static assert( parseAll_ctfe!(long)("123") == 123 );
169 }