]>
Dogcows Code - chaz/yoink/blob - src/stlplus/strings/string_inf.cpp
1 ////////////////////////////////////////////////////////////////////////////////
3 // Author: Andy Rushton
4 // Copyright: (c) Southampton University 1999-2004
5 // (c) Andy Rushton 2004-2009
6 // License: BSD License, see ../docs/license.html
8 // String conversion functions for the infinite precision integer type inf
10 ////////////////////////////////////////////////////////////////////////////////
12 // can be excluded from the build to break the dependency on the portability library
13 #ifndef NO_STLPLUS_INF
15 #include "string_inf.hpp"
16 #include "string_basic.hpp"
19 ////////////////////////////////////////////////////////////////////////////////
24 ////////////////////////////////////////////////////////////////////////////////
26 static char to_char
[] = "0123456789abcdefghijklmnopqrstuvwxyz";
27 static int from_char
[] =
29 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
30 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
31 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
32 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
33 -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
34 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
35 -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
36 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
37 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
38 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
39 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
40 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
41 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
42 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
43 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
44 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
47 ////////////////////////////////////////////////////////////////////////////////
49 std::string
inf_to_string(const stlplus::inf
& data
, unsigned radix
, radix_display_t display
, unsigned width
)
50 throw(std::invalid_argument
)
53 if (radix
< 2 || radix
> 36)
54 throw std::invalid_argument("invalid radix value");
56 // untangle all the options
65 case radix_hash_style
:
68 case radix_hash_style_all
:
79 case radix_c_style_or_hash
:
90 throw std::invalid_argument("invalid radix display value");
92 // create constants of the same type as the template parameter to avoid type mismatches
94 const inf
t_radix(radix
);
95 // the C representations for binary, octal and hex use 2's-complement representation
96 // all other represenations use sign-magnitude
97 if (hex
|| octal
|| binary
)
99 // bit-pattern representation
100 // this is the binary representation optionally shown in octal or hex
101 // first generate the binary by masking the bits
102 for (unsigned j
= local_i
.bits(); j
--; )
103 result
+= (local_i
.bit(j
) ? '1' : '0');
104 // the result is now the full width of the type - e.g. int will give a 32-bit result
105 // now interpret this as either binary, octal or hex and add the prefix
108 // the result is already binary - but the width may be wrong
109 // if this is still smaller than the width field, sign extend
110 // otherwise trim down to either the width or the smallest string that preserves the value
111 while (result
.size() < width
)
112 result
.insert((std::string::size_type
)0, 1, result
[0]);
113 while (result
.size() > width
)
115 // do not trim to less than 1 bit (sign only)
116 if (result
.size() <= 1) break;
117 // only trim if it doesn't change the sign and therefore the value
118 if (result
[0] != result
[1]) break;
122 result
.insert((std::string::size_type
)0, "0b");
126 // the result is currently binary - but before converting get the width right
127 // the width is expressed in octal digits so make the binary 3 times this
128 // if this is still smaller than the width field, sign extend
129 // otherwise trim down to either the width or the smallest string that preserves the value
130 // also ensure that the binary is a multiple of 3 bits to make the conversion to octal easier
131 while (result
.size() < 3*width
)
132 result
.insert((std::string::size_type
)0, 1, result
[0]);
133 while (result
.size() > 3*width
)
135 // do not trim to less than 2 bits (sign plus 1-bit magnitude)
136 if (result
.size() <= 2) break;
137 // only trim if it doesn't change the sign and therefore the value
138 if (result
[0] != result
[1]) break;
141 while (result
.size() % 3 != 0)
142 result
.insert((std::string::size_type
)0, 1, result
[0]);
143 // now convert to octal
144 std::string octal_result
;
145 for (unsigned i
= 0; i
< result
.size()/3; i
++)
147 // yuck - ugly or what?
148 if (result
[i
*3] == '0')
150 if (result
[i
*3+1] == '0')
152 if (result
[i
*3+2] == '0')
159 if (result
[i
*3+2] == '0')
167 if (result
[i
*3+1] == '0')
169 if (result
[i
*3+2] == '0')
176 if (result
[i
*3+2] == '0')
183 result
= octal_result
;
185 result
.insert((std::string::size_type
)0, "0");
190 while (result
.size() < 4*width
)
191 result
.insert((std::string::size_type
)0, 1, result
[0]);
192 while (result
.size() > 4*width
)
194 // do not trim to less than 2 bits (sign plus 1-bit magnitude)
195 if (result
.size() <= 2) break;
196 // only trim if it doesn't change the sign and therefore the value
197 if (result
[0] != result
[1]) break;
200 while (result
.size() % 4 != 0)
201 result
.insert((std::string::size_type
)0, 1, result
[0]);
202 // now convert to hex
203 std::string hex_result
;
204 for (unsigned i
= 0; i
< result
.size()/4; i
++)
206 // yuck - ugly or what?
207 if (result
[i
*4] == '0')
209 if (result
[i
*4+1] == '0')
211 if (result
[i
*4+2] == '0')
213 if (result
[i
*4+3] == '0')
220 if (result
[i
*4+3] == '0')
228 if (result
[i
*4+2] == '0')
230 if (result
[i
*4+3] == '0')
237 if (result
[i
*4+3] == '0')
246 if (result
[i
*4+1] == '0')
248 if (result
[i
*4+2] == '0')
250 if (result
[i
*4+3] == '0')
257 if (result
[i
*4+3] == '0')
265 if (result
[i
*4+2] == '0')
267 if (result
[i
*4+3] == '0')
274 if (result
[i
*4+3] == '0')
284 result
.insert((std::string::size_type
)0, "0x");
289 // convert to sign-magnitude
290 // the representation is:
291 // [radix#][sign]magnitude
292 bool negative
= local_i
.negative();
294 // create a representation of the magnitude by successive division
297 std::pair
<inf
,inf
> divided
= local_i
.divide(t_radix
);
298 unsigned remainder
= divided
.second
.to_unsigned();
299 char digit
= to_char
[remainder
];
300 result
.insert((std::string::size_type
)0, 1, digit
);
301 local_i
= divided
.first
;
303 while(!local_i
.zero() || result
.size() < width
);
305 // add a sign only for negative values
307 result
.insert((std::string::size_type
)0, 1, '-');
308 // then prefix everything with the radix if the hashed representation was requested
310 result
.insert((std::string::size_type
)0, unsigned_to_string(radix
) + "#");
315 ////////////////////////////////////////////////////////////////////////////////
316 // Conversions FROM string
318 inf
string_to_inf(const std::string
& str
, unsigned radix
) throw(std::invalid_argument
)
321 if (radix
!= 0 && (radix
< 2 || radix
> 36))
322 throw std::invalid_argument("invalid radix value " + unsigned_to_string(radix
));
324 // the radix passed as a parameter is just the default - it can be
325 // overridden by either the C prefix or the hash prefix
326 // Note: a leading zero is the C-style prefix for octal - I only make this
327 // override the default when the default radix is not specified
328 // first check for a C-style prefix
329 bool c_style
= false;
330 if (i
< str
.size() && str
[i
] == '0')
333 if (i
+1 < str
.size() && tolower(str
[i
+1]) == 'x')
339 else if (i
+1 < str
.size() && tolower(str
[i
+1]) == 'b')
352 // now check for a hash-style prefix if a C-style prefix was not found
355 // scan for the sequence {digits}#
356 bool hash_found
= false;
358 for (; j
< str
.size(); j
++)
360 if (!isdigit(str
[j
]))
369 // use the hash prefix to define the radix
370 // i points to the start of the radix and j points to the # character
371 std::string slice
= str
.substr(i
, j
-i
);
372 radix
= string_to_unsigned(slice
);
378 if (radix
< 2 || radix
> 36)
379 throw std::invalid_argument("invalid radix value");
382 // the C style formats are bit patterns not integer values - these need
383 // to be sign-extended to get the right value
387 for (unsigned j
= i
; j
< str
.size(); j
++)
398 throw std::invalid_argument("invalid binary character in string " + str
);
404 for (unsigned j
= i
; j
< str
.size(); j
++)
433 throw std::invalid_argument("invalid octal character in string " + str
);
439 for (unsigned j
= i
; j
< str
.size(); j
++)
441 switch(tolower(str
[j
]))
492 throw std::invalid_argument("invalid hex character in string " + str
);
496 // now convert the value
497 result
.resize(binary
.size());
498 for (unsigned j
= 0; j
< binary
.size(); j
++)
499 result
.preset(binary
.size() - j
- 1, binary
[j
] == '1');
503 // now scan for a sign and find whether this is a negative number
504 bool negative
= false;
518 for (; i
< str
.size(); i
++)
520 result
*= inf(radix
);
521 int ch
= from_char
[(unsigned char)str
[i
]] ;
523 throw std::invalid_argument("invalid character in string " + str
+ " for radix " + unsigned_to_string(radix
));
532 ////////////////////////////////////////////////////////////////////////////////
534 } // end namespace stlplus
This page took 0.060558 seconds and 4 git commands to generate.