]>
Dogcows Code - chaz/yoink/blob - src/stlplus/strings/string_int.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 ////////////////////////////////////////////////////////////////////////////////
9 #include "string_int.hpp"
16 ////////////////////////////////////////////////////////////////////////////////
19 static char to_char
[] = "0123456789abcdefghijklmnopqrstuvwxyz";
20 static int from_char
[] =
22 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
23 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
24 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
25 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
26 -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
27 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
28 -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
29 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -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 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
33 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
34 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
35 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
36 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
37 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
40 ////////////////////////////////////////////////////////////////////////////////
41 // Conversions to string
42 // Local generic routines
44 // signed version of the generic image generation function for all integer types
46 static std::string
simage (T i
, unsigned radix
, radix_display_t display
, unsigned width
)
47 throw(std::invalid_argument
)
49 if (radix
< 2 || radix
> 36)
50 throw std::invalid_argument("invalid radix value " + unsigned_to_string(radix
));
51 // untangle all the options
60 case radix_hash_style
:
63 case radix_hash_style_all
:
74 case radix_c_style_or_hash
:
85 throw std::invalid_argument("invalid radix display value");
87 // create constants of the same type as the template parameter to avoid type mismatches
89 const T
t_radix(radix
);
90 // the C representations for binary, octal and hex use 2's-complement representation
91 // all other represenations use sign-magnitude
93 if (hex
|| octal
|| binary
)
95 // bit-pattern representation
96 // this is the binary representation optionally shown in octal or hex
97 // first generate the binary by masking the bits
98 // ensure that it has at least one bit!
99 for (T
mask(1); ; mask
<<= 1)
101 result
.insert((std::string::size_type
)0, 1, i
& mask
? '1' : '0');
102 if (mask
== t_zero
) break;
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 2 bits (sign plus 1-bit magnitude)
116 if (result
.size() <= 2) 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");
189 // hex - similar to octal
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
= i
< t_zero
;
293 // create a representation of the magnitude by successive division
296 T ch
= abs(i
% t_radix
);
298 result
.insert((std::string::size_type
)0, 1, to_char
[ch
]);
300 while(i
!= t_zero
|| result
.size() < width
);
302 // add a sign only for negative values
304 result
.insert((std::string::size_type
)0, 1, '-');
305 // then prefix everything with the radix if the hashed representation was requested
307 result
.insert((std::string::size_type
)0, unsigned_to_string(radix
) + "#");
314 static std::string
uimage (T i
, unsigned radix
, radix_display_t display
, unsigned width
)
315 throw(std::invalid_argument
)
317 if (radix
< 2 || radix
> 36)
318 throw std::invalid_argument("invalid radix value " + unsigned_to_string(radix
));
319 // untangle all the options
328 case radix_hash_style
:
329 hashed
= radix
!= 10;
331 case radix_hash_style_all
:
342 case radix_c_style_or_hash
:
349 else if (radix
!= 10)
353 throw std::invalid_argument("invalid radix display value");
355 // create constants of the same type as the template parameter to avoid type mismatches
357 const T
t_radix(radix
);
358 // the C representations for binary, octal and hex use 2's-complement representation
359 // all other represenations use sign-magnitude
361 if (hex
|| octal
|| binary
)
363 // bit-pattern representation
364 // this is the binary representation optionally shown in octal or hex
365 // first generate the binary by masking the bits
366 // ensure at least one bit
367 for (T
mask(1); ; mask
<<= 1)
369 result
.insert((std::string::size_type
)0, 1, i
& mask
? '1' : '0');
370 if (mask
== t_zero
) break;
372 // the result is now the full width of the type - e.g. int will give a 32-bit result
373 // now interpret this as either binary, octal or hex and add the prefix
376 // the result is already binary - but the width may be wrong
377 // if this is still smaller than the width field, zero extend
378 // otherwise trim down to either the width or the smallest string that preserves the value
379 while (result
.size() < width
)
380 result
.insert((std::string::size_type
)0, 1, '0');
381 while (result
.size() > width
)
383 // do not trim to less than 1 bit (1-bit magnitude)
384 if (result
.size() <= 1) break;
385 // only trim if it doesn't change the sign and therefore the value
386 if (result
[0] != '0') break;
390 result
.insert((std::string::size_type
)0, "0b");
394 // the result is currently binary - but before converting get the width right
395 // the width is expressed in octal digits so make the binary 3 times this
396 // if this is still smaller than the width field, sign extend
397 // otherwise trim down to either the width or the smallest string that preserves the value
398 // also ensure that the binary is a multiple of 3 bits to make the conversion to octal easier
399 while (result
.size() < 3*width
)
400 result
.insert((std::string::size_type
)0, 1, '0');
401 while (result
.size() > 3*width
)
403 // do not trim to less than 1 bit (1-bit magnitude)
404 if (result
.size() <= 1) break;
405 // only trim if it doesn't change the sign and therefore the value
406 if (result
[0] != '0') break;
409 while (result
.size() % 3 != 0)
410 result
.insert((std::string::size_type
)0, 1, '0');
411 // now convert to octal
412 std::string octal_result
;
413 for (unsigned i
= 0; i
< result
.size()/3; i
++)
415 // yuck - ugly or what?
416 if (result
[i
*3] == '0')
418 if (result
[i
*3+1] == '0')
420 if (result
[i
*3+2] == '0')
427 if (result
[i
*3+2] == '0')
435 if (result
[i
*3+1] == '0')
437 if (result
[i
*3+2] == '0')
444 if (result
[i
*3+2] == '0')
451 result
= octal_result
;
452 // add the prefix if the leading digit is not already 0
453 if (result
.empty() || result
[0] != '0') result
.insert((std::string::size_type
)0, "0");
458 while (result
.size() < 4*width
)
459 result
.insert((std::string::size_type
)0, 1, '0');
460 while (result
.size() > 4*width
)
462 // do not trim to less than 1 bit (1-bit magnitude)
463 if (result
.size() <= 1) break;
464 // only trim if it doesn't change the sign and therefore the value
465 if (result
[0] != '0') break;
468 while (result
.size() % 4 != 0)
469 result
.insert((std::string::size_type
)0, 1, '0');
470 // now convert to hex
471 std::string hex_result
;
472 for (unsigned i
= 0; i
< result
.size()/4; i
++)
474 // yuck - ugly or what?
475 if (result
[i
*4] == '0')
477 if (result
[i
*4+1] == '0')
479 if (result
[i
*4+2] == '0')
481 if (result
[i
*4+3] == '0')
488 if (result
[i
*4+3] == '0')
496 if (result
[i
*4+2] == '0')
498 if (result
[i
*4+3] == '0')
505 if (result
[i
*4+3] == '0')
514 if (result
[i
*4+1] == '0')
516 if (result
[i
*4+2] == '0')
518 if (result
[i
*4+3] == '0')
525 if (result
[i
*4+3] == '0')
533 if (result
[i
*4+2] == '0')
535 if (result
[i
*4+3] == '0')
542 if (result
[i
*4+3] == '0')
552 result
.insert((std::string::size_type
)0, "0x");
557 // convert to sign-magnitude
558 // the representation is:
560 // create a representation of the magnitude by successive division
565 result
.insert((std::string::size_type
)0, 1, to_char
[(int)ch
]);
567 while(i
!= t_zero
|| result
.size() < width
);
568 // prefix everything with the radix if the hashed representation was requested
570 result
.insert((std::string::size_type
)0, unsigned_to_string(radix
) + "#");
575 ////////////////////////////////////////////////////////////////////////////////
576 // exported conversions to string
578 std::string
short_to_string(short i
, unsigned radix
, radix_display_t display
, unsigned width
)
579 throw(std::invalid_argument
)
581 return simage(i
, radix
, display
, width
);
584 std::string
unsigned_short_to_string(unsigned short i
, unsigned radix
, radix_display_t display
, unsigned width
)
585 throw(std::invalid_argument
)
587 return uimage(i
, radix
, display
, width
);
590 std::string
int_to_string(int i
, unsigned radix
, radix_display_t display
, unsigned width
)
591 throw(std::invalid_argument
)
593 return simage(i
, radix
, display
, width
);
596 std::string
unsigned_to_string(unsigned i
, unsigned radix
, radix_display_t display
, unsigned width
)
597 throw(std::invalid_argument
)
599 return uimage(i
, radix
, display
, width
);
602 std::string
long_to_string(long i
, unsigned radix
, radix_display_t display
, unsigned width
)
603 throw(std::invalid_argument
)
605 return simage(i
, radix
, display
, width
);
608 std::string
unsigned_long_to_string(unsigned long i
, unsigned radix
, radix_display_t display
, unsigned width
)
609 throw(std::invalid_argument
)
611 return uimage(i
, radix
, display
, width
);
614 ////////////////////////////////////////////////////////////////////////////////
615 // Conversions FROM string
616 // local template function
617 // Note: this has been copied and modified for the inf class - so any changes here must be made there too
621 static T
svalue(const std::string
& str
, unsigned radix
)
622 throw(std::invalid_argument
)
624 if (radix
!= 0 && (radix
< 2 || radix
> 36))
625 throw std::invalid_argument("invalid radix value " + unsigned_to_string(radix
));
626 std::string::size_type i
= 0;
627 // the radix passed as a parameter is just the default - it can be
628 // overridden by either the C prefix or the hash prefix. Note: a leading zero
629 // is the C-style prefix for octal - I only make this override the default
630 // when the default prefix is not specified
631 // First check for a C-style prefix
632 bool c_style
= false;
633 if (i
< str
.size() && str
[i
] == '0')
635 // octal, binary or hex
636 if (i
+1 < str
.size() && tolower(str
[i
+1]) == 'x')
642 else if (i
+1 < str
.size() && tolower(str
[i
+1]) == 'b')
655 // now check for a hash-style prefix if a C-style prefix was not found
658 // scan for the sequence {digits}#
659 bool hash_found
= false;
660 std::string::size_type j
= i
;
661 for (; j
< str
.size(); j
++)
663 if (!isdigit(str
[j
]))
672 // use the hash prefix to define the radix
673 // i points to the start of the radix and j points to the # character
674 std::string slice
= str
.substr(i
, j
-i
);
675 radix
= string_to_unsigned(slice
);
681 if (radix
< 2 || radix
> 36)
682 throw std::invalid_argument("invalid radix value " + unsigned_to_string(radix
));
686 // the C style formats are bit patterns not integer values - these need
687 // to be sign-extended to get the right value
691 for (std::string::size_type j
= i
; j
< str
.size(); j
++)
702 throw std::invalid_argument("invalid binary character in string " + str
);
709 for (std::string::size_type j
= i
; j
< str
.size(); j
++)
738 throw std::invalid_argument("invalid octal character in string " + str
);
745 for (std::string::size_type j
= i
; j
< str
.size(); j
++)
747 switch(tolower(str
[j
]))
798 throw std::invalid_argument("invalid hex character in string " + str
);
803 // now sign-extend to the right number of bits for the type
804 while (binary
.size() < sizeof(T
)*8)
805 binary
.insert((std::string::size_type
)0, 1, binary
.empty() ? '0' : binary
[0]);
806 // now convert the value
807 for (std::string::size_type j
= 0; j
< binary
.size(); j
++)
810 int ch
= from_char
[(unsigned char)binary
[j
]] ;
816 // now scan for a sign and find whether this is a negative number
817 bool negative
= false;
831 for (; i
< str
.size(); i
++)
834 int ch
= from_char
[(unsigned char)str
[i
]] ;
835 if (ch
== -1 || (unsigned)ch
>= radix
)
836 throw std::invalid_argument("invalid character in string " + str
);
847 static T
uvalue(const std::string
& str
, unsigned radix
)
848 throw(std::invalid_argument
)
850 if (radix
!= 0 && (radix
< 2 || radix
> 36))
851 throw std::invalid_argument("invalid radix value " + unsigned_to_string(radix
));
853 // the radix passed as a parameter is just the default - it can be
854 // overridden by either the C prefix or the hash prefix. Note: a leading
855 // zero is the C-style prefix for octal - I only make this override the
856 // default when the default prefix is not specified
857 // First check for a C-style prefix
858 bool c_style
= false;
859 if (i
< str
.size() && str
[i
] == '0')
862 if (i
+1 < str
.size() && tolower(str
[i
+1]) == 'x')
868 else if (i
+1 < str
.size() && tolower(str
[i
+1]) == 'b')
881 // now check for a hash-style prefix if a C-style prefix was not found
884 // scan for the sequence {digits}#
885 bool hash_found
= false;
887 for (; j
< str
.size(); j
++)
889 if (!isdigit(str
[j
]))
898 // use the hash prefix to define the radix
899 // i points to the start of the radix and j points to the # character
900 std::string slice
= str
.substr(i
, j
-i
);
901 radix
= string_to_unsigned(slice
);
907 if (radix
< 2 || radix
> 36)
908 throw std::invalid_argument("invalid radix value " + unsigned_to_string(radix
));
912 // the C style formats are bit patterns not integer values - these need
913 // to be sign-extended to get the right value
917 for (unsigned j
= i
; j
< str
.size(); j
++)
928 throw std::invalid_argument("invalid hex character in string " + str
);
935 for (unsigned j
= i
; j
< str
.size(); j
++)
964 throw std::invalid_argument("invalid octal character in string " + str
);
971 for (unsigned j
= i
; j
< str
.size(); j
++)
973 switch(tolower(str
[j
]))
1024 throw std::invalid_argument("invalid hex character in string " + str
);
1029 // now zero-extend to the right number of bits for the type
1030 while (binary
.size() < sizeof(T
)*8)
1031 binary
.insert((std::string::size_type
)0, 1, '0');
1032 // now convert the value
1033 for (unsigned j
= 0; j
< binary
.size(); j
++)
1036 int ch
= from_char
[(unsigned char)binary
[j
]] ;
1042 // now scan for a sign and find whether this is a negative number
1048 throw std::invalid_argument("invalid sign character in string " + str
+ " for unsigned value");
1056 for (; i
< str
.size(); i
++)
1059 int ch
= from_char
[(unsigned char)str
[i
]] ;
1060 if (ch
== -1 || (unsigned)ch
>= radix
)
1062 throw std::invalid_argument("invalid character in string " + str
);
1070 ////////////////////////////////////////////////////////////////////////////////
1071 // exported functions
1073 short string_to_short(const std::string
& str
, unsigned radix
)
1074 throw(std::invalid_argument
)
1076 return svalue
<short>(str
, radix
);
1079 unsigned short string_to_unsigned_short(const std::string
& str
, unsigned radix
)
1080 throw(std::invalid_argument
)
1082 return uvalue
<unsigned short>(str
, radix
);
1085 int string_to_int(const std::string
& str
, unsigned radix
)
1086 throw(std::invalid_argument
)
1088 return svalue
<int>(str
, radix
);
1091 unsigned string_to_unsigned(const std::string
& str
, unsigned radix
)
1092 throw(std::invalid_argument
)
1094 return uvalue
<unsigned>(str
, radix
);
1097 long string_to_long(const std::string
& str
, unsigned radix
)
1098 throw(std::invalid_argument
)
1100 return svalue
<long>(str
, radix
);
1103 unsigned long string_to_unsigned_long(const std::string
& str
, unsigned radix
)
1104 throw(std::invalid_argument
)
1106 return uvalue
<unsigned long>(str
, radix
);
1109 ////////////////////////////////////////////////////////////////////////////////
1111 } // end namespace stlplus
This page took 0.088175 seconds and 4 git commands to generate.