-////////////////////////////////////////////////////////////////////////////////\r
-\r
-// Author: Andy Rushton\r
-// Copyright: (c) Southampton University 1999-2004\r
-// (c) Andy Rushton 2004-2009\r
-// License: BSD License, see ../docs/license.html\r
-\r
-// String conversion functions for the infinite precision integer type inf\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-// can be excluded from the build to break the dependency on the portability library\r
-#ifndef NO_STLPLUS_INF\r
-\r
-#include "string_inf.hpp"\r
-#include "string_basic.hpp"\r
-#include <ctype.h>\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
- ////////////////////////////////////////////////////////////////////////////////\r
-\r
- static char to_char [] = "0123456789abcdefghijklmnopqrstuvwxyz";\r
- static int from_char [] = \r
- {\r
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,\r
- -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,\r
- 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,\r
- -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,\r
- 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,\r
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1\r
- };\r
-\r
- ////////////////////////////////////////////////////////////////////////////////\r
-\r
- std::string inf_to_string(const stlplus::inf& data, unsigned radix, radix_display_t display, unsigned width)\r
- throw(std::invalid_argument)\r
- {\r
- std::string result;\r
- if (radix < 2 || radix > 36)\r
- throw std::invalid_argument("invalid radix value");\r
- inf local_i = data;\r
- // untangle all the options\r
- bool hashed = false;\r
- bool binary = false;\r
- bool octal = false;\r
- bool hex = false;\r
- switch(display)\r
- {\r
- case radix_none:\r
- break;\r
- case radix_hash_style:\r
- hashed = radix != 10;\r
- break;\r
- case radix_hash_style_all:\r
- hashed = true;\r
- break;\r
- case radix_c_style:\r
- if (radix == 16)\r
- hex = true;\r
- else if (radix == 8)\r
- octal = true;\r
- else if (radix == 2)\r
- binary = true;\r
- break;\r
- case radix_c_style_or_hash:\r
- if (radix == 16)\r
- hex = true;\r
- else if (radix == 8)\r
- octal = true;\r
- else if (radix == 2)\r
- binary = true;\r
- else if (radix != 10)\r
- hashed = true;\r
- break;\r
- default:\r
- throw std::invalid_argument("invalid radix display value");\r
- }\r
- // create constants of the same type as the template parameter to avoid type mismatches\r
- const inf t_zero(0);\r
- const inf t_radix(radix);\r
- // the C representations for binary, octal and hex use 2's-complement representation\r
- // all other represenations use sign-magnitude\r
- if (hex || octal || binary)\r
- {\r
- // bit-pattern representation\r
- // this is the binary representation optionally shown in octal or hex\r
- // first generate the binary by masking the bits\r
- for (unsigned j = local_i.bits(); j--; )\r
- result += (local_i.bit(j) ? '1' : '0');\r
- // the result is now the full width of the type - e.g. int will give a 32-bit result\r
- // now interpret this as either binary, octal or hex and add the prefix\r
- if (binary)\r
- {\r
- // the result is already binary - but the width may be wrong\r
- // if this is still smaller than the width field, sign extend\r
- // otherwise trim down to either the width or the smallest string that preserves the value\r
- while (result.size() < width)\r
- result.insert((std::string::size_type)0, 1, result[0]);\r
- while (result.size() > width)\r
- {\r
- // do not trim to less than 1 bit (sign only)\r
- if (result.size() <= 1) break;\r
- // only trim if it doesn't change the sign and therefore the value\r
- if (result[0] != result[1]) break;\r
- result.erase(0,1);\r
- }\r
- // add the prefix\r
- result.insert((std::string::size_type)0, "0b");\r
- }\r
- else if (octal)\r
- {\r
- // the result is currently binary - but before converting get the width right\r
- // the width is expressed in octal digits so make the binary 3 times this\r
- // if this is still smaller than the width field, sign extend\r
- // otherwise trim down to either the width or the smallest string that preserves the value\r
- // also ensure that the binary is a multiple of 3 bits to make the conversion to octal easier\r
- while (result.size() < 3*width)\r
- result.insert((std::string::size_type)0, 1, result[0]);\r
- while (result.size() > 3*width)\r
- {\r
- // do not trim to less than 2 bits (sign plus 1-bit magnitude)\r
- if (result.size() <= 2) break;\r
- // only trim if it doesn't change the sign and therefore the value\r
- if (result[0] != result[1]) break;\r
- result.erase(0,1);\r
- }\r
- while (result.size() % 3 != 0)\r
- result.insert((std::string::size_type)0, 1, result[0]);\r
- // now convert to octal\r
- std::string octal_result;\r
- for (unsigned i = 0; i < result.size()/3; i++)\r
- {\r
- // yuck - ugly or what?\r
- if (result[i*3] == '0')\r
- {\r
- if (result[i*3+1] == '0')\r
- {\r
- if (result[i*3+2] == '0')\r
- octal_result += '0';\r
- else\r
- octal_result += '1';\r
- }\r
- else\r
- {\r
- if (result[i*3+2] == '0')\r
- octal_result += '2';\r
- else\r
- octal_result += '3';\r
- }\r
- }\r
- else\r
- {\r
- if (result[i*3+1] == '0')\r
- {\r
- if (result[i*3+2] == '0')\r
- octal_result += '4';\r
- else\r
- octal_result += '5';\r
- }\r
- else\r
- {\r
- if (result[i*3+2] == '0')\r
- octal_result += '6';\r
- else\r
- octal_result += '7';\r
- }\r
- }\r
- }\r
- result = octal_result;\r
- // add the prefix\r
- result.insert((std::string::size_type)0, "0");\r
- }\r
- else\r
- {\r
- // similar to octal\r
- while (result.size() < 4*width)\r
- result.insert((std::string::size_type)0, 1, result[0]);\r
- while (result.size() > 4*width)\r
- {\r
- // do not trim to less than 2 bits (sign plus 1-bit magnitude)\r
- if (result.size() <= 2) break;\r
- // only trim if it doesn't change the sign and therefore the value\r
- if (result[0] != result[1]) break;\r
- result.erase(0,1);\r
- }\r
- while (result.size() % 4 != 0)\r
- result.insert((std::string::size_type)0, 1, result[0]);\r
- // now convert to hex\r
- std::string hex_result;\r
- for (unsigned i = 0; i < result.size()/4; i++)\r
- {\r
- // yuck - ugly or what?\r
- if (result[i*4] == '0')\r
- {\r
- if (result[i*4+1] == '0')\r
- {\r
- if (result[i*4+2] == '0')\r
- {\r
- if (result[i*4+3] == '0')\r
- hex_result += '0';\r
- else\r
- hex_result += '1';\r
- }\r
- else\r
- {\r
- if (result[i*4+3] == '0')\r
- hex_result += '2';\r
- else\r
- hex_result += '3';\r
- }\r
- }\r
- else\r
- {\r
- if (result[i*4+2] == '0')\r
- {\r
- if (result[i*4+3] == '0')\r
- hex_result += '4';\r
- else\r
- hex_result += '5';\r
- }\r
- else\r
- {\r
- if (result[i*4+3] == '0')\r
- hex_result += '6';\r
- else\r
- hex_result += '7';\r
- }\r
- }\r
- }\r
- else\r
- {\r
- if (result[i*4+1] == '0')\r
- {\r
- if (result[i*4+2] == '0')\r
- {\r
- if (result[i*4+3] == '0')\r
- hex_result += '8';\r
- else\r
- hex_result += '9';\r
- }\r
- else\r
- {\r
- if (result[i*4+3] == '0')\r
- hex_result += 'a';\r
- else\r
- hex_result += 'b';\r
- }\r
- }\r
- else\r
- {\r
- if (result[i*4+2] == '0')\r
- {\r
- if (result[i*4+3] == '0')\r
- hex_result += 'c';\r
- else\r
- hex_result += 'd';\r
- }\r
- else\r
- {\r
- if (result[i*4+3] == '0')\r
- hex_result += 'e';\r
- else\r
- hex_result += 'f';\r
- }\r
- }\r
- }\r
- }\r
- result = hex_result;\r
- // add the prefix\r
- result.insert((std::string::size_type)0, "0x");\r
- }\r
- }\r
- else\r
- {\r
- // convert to sign-magnitude\r
- // the representation is:\r
- // [radix#][sign]magnitude\r
- bool negative = local_i.negative();\r
- local_i.abs();\r
- // create a representation of the magnitude by successive division\r
- do\r
- {\r
- std::pair<inf,inf> divided = local_i.divide(t_radix);\r
- unsigned remainder = divided.second.to_unsigned();\r
- char digit = to_char[remainder];\r
- result.insert((std::string::size_type)0, 1, digit);\r
- local_i = divided.first;\r
- }\r
- while(!local_i.zero() || result.size() < width);\r
- // add the prefixes\r
- // add a sign only for negative values\r
- if (negative)\r
- result.insert((std::string::size_type)0, 1, '-');\r
- // then prefix everything with the radix if the hashed representation was requested\r
- if (hashed)\r
- result.insert((std::string::size_type)0, unsigned_to_string(radix) + "#");\r
- }\r
- return result;\r
- }\r
-\r
- ////////////////////////////////////////////////////////////////////////////////\r
- // Conversions FROM string\r
-\r
- inf string_to_inf(const std::string& str, unsigned radix) throw(std::invalid_argument)\r
- {\r
- inf result;\r
- if (radix != 0 && (radix < 2 || radix > 36))\r
- throw std::invalid_argument("invalid radix value " + unsigned_to_string(radix));\r
- unsigned i = 0;\r
- // the radix passed as a parameter is just the default - it can be\r
- // overridden by either the C prefix or the hash prefix\r
- // Note: a leading zero is the C-style prefix for octal - I only make this\r
- // override the default when the default radix is not specified\r
- // first check for a C-style prefix\r
- bool c_style = false;\r
- if (i < str.size() && str[i] == '0')\r
- {\r
- // binary or hex\r
- if (i+1 < str.size() && tolower(str[i+1]) == 'x')\r
- {\r
- c_style = true;\r
- radix = 16;\r
- i += 2;\r
- }\r
- else if (i+1 < str.size() && tolower(str[i+1]) == 'b')\r
- {\r
- c_style = true;\r
- radix = 2;\r
- i += 2;\r
- }\r
- else if (radix == 0)\r
- {\r
- c_style = true;\r
- radix = 8;\r
- i += 1;\r
- }\r
- }\r
- // now check for a hash-style prefix if a C-style prefix was not found\r
- if (i == 0)\r
- {\r
- // scan for the sequence {digits}#\r
- bool hash_found = false;\r
- unsigned j = i;\r
- for (; j < str.size(); j++)\r
- {\r
- if (!isdigit(str[j]))\r
- {\r
- if (str[j] == '#')\r
- hash_found = true;\r
- break;\r
- }\r
- }\r
- if (hash_found)\r
- {\r
- // use the hash prefix to define the radix\r
- // i points to the start of the radix and j points to the # character\r
- std::string slice = str.substr(i, j-i);\r
- radix = string_to_unsigned(slice);\r
- i = j+1;\r
- }\r
- }\r
- if (radix == 0)\r
- radix = 10;\r
- if (radix < 2 || radix > 36)\r
- throw std::invalid_argument("invalid radix value");\r
- if (c_style)\r
- {\r
- // the C style formats are bit patterns not integer values - these need\r
- // to be sign-extended to get the right value\r
- std::string binary;\r
- if (radix == 2)\r
- {\r
- for (unsigned j = i; j < str.size(); j++)\r
- {\r
- switch(str[j])\r
- {\r
- case '0':\r
- binary += '0';\r
- break;\r
- case '1':\r
- binary += '1';\r
- break;\r
- default:\r
- throw std::invalid_argument("invalid binary character in string " + str);\r
- }\r
- }\r
- }\r
- else if (radix == 8)\r
- {\r
- for (unsigned j = i; j < str.size(); j++)\r
- {\r
- switch(str[j])\r
- {\r
- case '0':\r
- binary += "000";\r
- break;\r
- case '1':\r
- binary += "001";\r
- break;\r
- case '2':\r
- binary += "010";\r
- break;\r
- case '3':\r
- binary += "011";\r
- break;\r
- case '4':\r
- binary += "100";\r
- break;\r
- case '5':\r
- binary += "101";\r
- break;\r
- case '6':\r
- binary += "110";\r
- break;\r
- case '7':\r
- binary += "111";\r
- break;\r
- default:\r
- throw std::invalid_argument("invalid octal character in string " + str);\r
- }\r
- }\r
- }\r
- else\r
- {\r
- for (unsigned j = i; j < str.size(); j++)\r
- {\r
- switch(tolower(str[j]))\r
- {\r
- case '0':\r
- binary += "0000";\r
- break;\r
- case '1':\r
- binary += "0001";\r
- break;\r
- case '2':\r
- binary += "0010";\r
- break;\r
- case '3':\r
- binary += "0011";\r
- break;\r
- case '4':\r
- binary += "0100";\r
- break;\r
- case '5':\r
- binary += "0101";\r
- break;\r
- case '6':\r
- binary += "0110";\r
- break;\r
- case '7':\r
- binary += "0111";\r
- break;\r
- case '8':\r
- binary += "1000";\r
- break;\r
- case '9':\r
- binary += "1001";\r
- break;\r
- case 'a':\r
- binary += "1010";\r
- break;\r
- case 'b':\r
- binary += "1011";\r
- break;\r
- case 'c':\r
- binary += "1100";\r
- break;\r
- case 'd':\r
- binary += "1101";\r
- break;\r
- case 'e':\r
- binary += "1110";\r
- break;\r
- case 'f':\r
- binary += "1111";\r
- break;\r
- default:\r
- throw std::invalid_argument("invalid hex character in string " + str);\r
- }\r
- }\r
- }\r
- // now convert the value\r
- result.resize(binary.size());\r
- for (unsigned j = 0; j < binary.size(); j++)\r
- result.preset(binary.size() - j - 1, binary[j] == '1');\r
- }\r
- else\r
- {\r
- // now scan for a sign and find whether this is a negative number\r
- bool negative = false;\r
- if (i < str.size())\r
- {\r
- switch (str[i])\r
- {\r
- case '-':\r
- negative = true;\r
- i++;\r
- break;\r
- case '+':\r
- i++;\r
- break;\r
- }\r
- }\r
- for (; i < str.size(); i++)\r
- {\r
- result *= inf(radix);\r
- int ch = from_char[(unsigned char)str[i]] ;\r
- if (ch == -1)\r
- throw std::invalid_argument("invalid character in string " + str + " for radix " + unsigned_to_string(radix));\r
- result += inf(ch);\r
- }\r
- if (negative)\r
- result.negate();\r
- }\r
- return result;\r
- }\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
-\r
-#endif\r
+////////////////////////////////////////////////////////////////////////////////
+
+// Author: Andy Rushton
+// Copyright: (c) Southampton University 1999-2004
+// (c) Andy Rushton 2004-2009
+// License: BSD License, see ../docs/license.html
+
+// String conversion functions for the infinite precision integer type inf
+
+////////////////////////////////////////////////////////////////////////////////
+
+// can be excluded from the build to break the dependency on the portability library
+#ifndef NO_STLPLUS_INF
+
+#include "string_inf.hpp"
+#include "string_basic.hpp"
+#include <ctype.h>
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ static char to_char [] = "0123456789abcdefghijklmnopqrstuvwxyz";
+ static int from_char [] =
+ {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
+ -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
+ -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ std::string inf_to_string(const stlplus::inf& data, unsigned radix, radix_display_t display, unsigned width)
+ throw(std::invalid_argument)
+ {
+ std::string result;
+ if (radix < 2 || radix > 36)
+ throw std::invalid_argument("invalid radix value");
+ inf local_i = data;
+ // untangle all the options
+ bool hashed = false;
+ bool binary = false;
+ bool octal = false;
+ bool hex = false;
+ switch(display)
+ {
+ case radix_none:
+ break;
+ case radix_hash_style:
+ hashed = radix != 10;
+ break;
+ case radix_hash_style_all:
+ hashed = true;
+ break;
+ case radix_c_style:
+ if (radix == 16)
+ hex = true;
+ else if (radix == 8)
+ octal = true;
+ else if (radix == 2)
+ binary = true;
+ break;
+ case radix_c_style_or_hash:
+ if (radix == 16)
+ hex = true;
+ else if (radix == 8)
+ octal = true;
+ else if (radix == 2)
+ binary = true;
+ else if (radix != 10)
+ hashed = true;
+ break;
+ default:
+ throw std::invalid_argument("invalid radix display value");
+ }
+ // create constants of the same type as the template parameter to avoid type mismatches
+ const inf t_zero(0);
+ const inf t_radix(radix);
+ // the C representations for binary, octal and hex use 2's-complement representation
+ // all other represenations use sign-magnitude
+ if (hex || octal || binary)
+ {
+ // bit-pattern representation
+ // this is the binary representation optionally shown in octal or hex
+ // first generate the binary by masking the bits
+ for (unsigned j = local_i.bits(); j--; )
+ result += (local_i.bit(j) ? '1' : '0');
+ // the result is now the full width of the type - e.g. int will give a 32-bit result
+ // now interpret this as either binary, octal or hex and add the prefix
+ if (binary)
+ {
+ // the result is already binary - but the width may be wrong
+ // if this is still smaller than the width field, sign extend
+ // otherwise trim down to either the width or the smallest string that preserves the value
+ while (result.size() < width)
+ result.insert((std::string::size_type)0, 1, result[0]);
+ while (result.size() > width)
+ {
+ // do not trim to less than 1 bit (sign only)
+ if (result.size() <= 1) break;
+ // only trim if it doesn't change the sign and therefore the value
+ if (result[0] != result[1]) break;
+ result.erase(0,1);
+ }
+ // add the prefix
+ result.insert((std::string::size_type)0, "0b");
+ }
+ else if (octal)
+ {
+ // the result is currently binary - but before converting get the width right
+ // the width is expressed in octal digits so make the binary 3 times this
+ // if this is still smaller than the width field, sign extend
+ // otherwise trim down to either the width or the smallest string that preserves the value
+ // also ensure that the binary is a multiple of 3 bits to make the conversion to octal easier
+ while (result.size() < 3*width)
+ result.insert((std::string::size_type)0, 1, result[0]);
+ while (result.size() > 3*width)
+ {
+ // do not trim to less than 2 bits (sign plus 1-bit magnitude)
+ if (result.size() <= 2) break;
+ // only trim if it doesn't change the sign and therefore the value
+ if (result[0] != result[1]) break;
+ result.erase(0,1);
+ }
+ while (result.size() % 3 != 0)
+ result.insert((std::string::size_type)0, 1, result[0]);
+ // now convert to octal
+ std::string octal_result;
+ for (unsigned i = 0; i < result.size()/3; i++)
+ {
+ // yuck - ugly or what?
+ if (result[i*3] == '0')
+ {
+ if (result[i*3+1] == '0')
+ {
+ if (result[i*3+2] == '0')
+ octal_result += '0';
+ else
+ octal_result += '1';
+ }
+ else
+ {
+ if (result[i*3+2] == '0')
+ octal_result += '2';
+ else
+ octal_result += '3';
+ }
+ }
+ else
+ {
+ if (result[i*3+1] == '0')
+ {
+ if (result[i*3+2] == '0')
+ octal_result += '4';
+ else
+ octal_result += '5';
+ }
+ else
+ {
+ if (result[i*3+2] == '0')
+ octal_result += '6';
+ else
+ octal_result += '7';
+ }
+ }
+ }
+ result = octal_result;
+ // add the prefix
+ result.insert((std::string::size_type)0, "0");
+ }
+ else
+ {
+ // similar to octal
+ while (result.size() < 4*width)
+ result.insert((std::string::size_type)0, 1, result[0]);
+ while (result.size() > 4*width)
+ {
+ // do not trim to less than 2 bits (sign plus 1-bit magnitude)
+ if (result.size() <= 2) break;
+ // only trim if it doesn't change the sign and therefore the value
+ if (result[0] != result[1]) break;
+ result.erase(0,1);
+ }
+ while (result.size() % 4 != 0)
+ result.insert((std::string::size_type)0, 1, result[0]);
+ // now convert to hex
+ std::string hex_result;
+ for (unsigned i = 0; i < result.size()/4; i++)
+ {
+ // yuck - ugly or what?
+ if (result[i*4] == '0')
+ {
+ if (result[i*4+1] == '0')
+ {
+ if (result[i*4+2] == '0')
+ {
+ if (result[i*4+3] == '0')
+ hex_result += '0';
+ else
+ hex_result += '1';
+ }
+ else
+ {
+ if (result[i*4+3] == '0')
+ hex_result += '2';
+ else
+ hex_result += '3';
+ }
+ }
+ else
+ {
+ if (result[i*4+2] == '0')
+ {
+ if (result[i*4+3] == '0')
+ hex_result += '4';
+ else
+ hex_result += '5';
+ }
+ else
+ {
+ if (result[i*4+3] == '0')
+ hex_result += '6';
+ else
+ hex_result += '7';
+ }
+ }
+ }
+ else
+ {
+ if (result[i*4+1] == '0')
+ {
+ if (result[i*4+2] == '0')
+ {
+ if (result[i*4+3] == '0')
+ hex_result += '8';
+ else
+ hex_result += '9';
+ }
+ else
+ {
+ if (result[i*4+3] == '0')
+ hex_result += 'a';
+ else
+ hex_result += 'b';
+ }
+ }
+ else
+ {
+ if (result[i*4+2] == '0')
+ {
+ if (result[i*4+3] == '0')
+ hex_result += 'c';
+ else
+ hex_result += 'd';
+ }
+ else
+ {
+ if (result[i*4+3] == '0')
+ hex_result += 'e';
+ else
+ hex_result += 'f';
+ }
+ }
+ }
+ }
+ result = hex_result;
+ // add the prefix
+ result.insert((std::string::size_type)0, "0x");
+ }
+ }
+ else
+ {
+ // convert to sign-magnitude
+ // the representation is:
+ // [radix#][sign]magnitude
+ bool negative = local_i.negative();
+ local_i.abs();
+ // create a representation of the magnitude by successive division
+ do
+ {
+ std::pair<inf,inf> divided = local_i.divide(t_radix);
+ unsigned remainder = divided.second.to_unsigned();
+ char digit = to_char[remainder];
+ result.insert((std::string::size_type)0, 1, digit);
+ local_i = divided.first;
+ }
+ while(!local_i.zero() || result.size() < width);
+ // add the prefixes
+ // add a sign only for negative values
+ if (negative)
+ result.insert((std::string::size_type)0, 1, '-');
+ // then prefix everything with the radix if the hashed representation was requested
+ if (hashed)
+ result.insert((std::string::size_type)0, unsigned_to_string(radix) + "#");
+ }
+ return result;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Conversions FROM string
+
+ inf string_to_inf(const std::string& str, unsigned radix) throw(std::invalid_argument)
+ {
+ inf result;
+ if (radix != 0 && (radix < 2 || radix > 36))
+ throw std::invalid_argument("invalid radix value " + unsigned_to_string(radix));
+ unsigned i = 0;
+ // the radix passed as a parameter is just the default - it can be
+ // overridden by either the C prefix or the hash prefix
+ // Note: a leading zero is the C-style prefix for octal - I only make this
+ // override the default when the default radix is not specified
+ // first check for a C-style prefix
+ bool c_style = false;
+ if (i < str.size() && str[i] == '0')
+ {
+ // binary or hex
+ if (i+1 < str.size() && tolower(str[i+1]) == 'x')
+ {
+ c_style = true;
+ radix = 16;
+ i += 2;
+ }
+ else if (i+1 < str.size() && tolower(str[i+1]) == 'b')
+ {
+ c_style = true;
+ radix = 2;
+ i += 2;
+ }
+ else if (radix == 0)
+ {
+ c_style = true;
+ radix = 8;
+ i += 1;
+ }
+ }
+ // now check for a hash-style prefix if a C-style prefix was not found
+ if (i == 0)
+ {
+ // scan for the sequence {digits}#
+ bool hash_found = false;
+ unsigned j = i;
+ for (; j < str.size(); j++)
+ {
+ if (!isdigit(str[j]))
+ {
+ if (str[j] == '#')
+ hash_found = true;
+ break;
+ }
+ }
+ if (hash_found)
+ {
+ // use the hash prefix to define the radix
+ // i points to the start of the radix and j points to the # character
+ std::string slice = str.substr(i, j-i);
+ radix = string_to_unsigned(slice);
+ i = j+1;
+ }
+ }
+ if (radix == 0)
+ radix = 10;
+ if (radix < 2 || radix > 36)
+ throw std::invalid_argument("invalid radix value");
+ if (c_style)
+ {
+ // the C style formats are bit patterns not integer values - these need
+ // to be sign-extended to get the right value
+ std::string binary;
+ if (radix == 2)
+ {
+ for (unsigned j = i; j < str.size(); j++)
+ {
+ switch(str[j])
+ {
+ case '0':
+ binary += '0';
+ break;
+ case '1':
+ binary += '1';
+ break;
+ default:
+ throw std::invalid_argument("invalid binary character in string " + str);
+ }
+ }
+ }
+ else if (radix == 8)
+ {
+ for (unsigned j = i; j < str.size(); j++)
+ {
+ switch(str[j])
+ {
+ case '0':
+ binary += "000";
+ break;
+ case '1':
+ binary += "001";
+ break;
+ case '2':
+ binary += "010";
+ break;
+ case '3':
+ binary += "011";
+ break;
+ case '4':
+ binary += "100";
+ break;
+ case '5':
+ binary += "101";
+ break;
+ case '6':
+ binary += "110";
+ break;
+ case '7':
+ binary += "111";
+ break;
+ default:
+ throw std::invalid_argument("invalid octal character in string " + str);
+ }
+ }
+ }
+ else
+ {
+ for (unsigned j = i; j < str.size(); j++)
+ {
+ switch(tolower(str[j]))
+ {
+ case '0':
+ binary += "0000";
+ break;
+ case '1':
+ binary += "0001";
+ break;
+ case '2':
+ binary += "0010";
+ break;
+ case '3':
+ binary += "0011";
+ break;
+ case '4':
+ binary += "0100";
+ break;
+ case '5':
+ binary += "0101";
+ break;
+ case '6':
+ binary += "0110";
+ break;
+ case '7':
+ binary += "0111";
+ break;
+ case '8':
+ binary += "1000";
+ break;
+ case '9':
+ binary += "1001";
+ break;
+ case 'a':
+ binary += "1010";
+ break;
+ case 'b':
+ binary += "1011";
+ break;
+ case 'c':
+ binary += "1100";
+ break;
+ case 'd':
+ binary += "1101";
+ break;
+ case 'e':
+ binary += "1110";
+ break;
+ case 'f':
+ binary += "1111";
+ break;
+ default:
+ throw std::invalid_argument("invalid hex character in string " + str);
+ }
+ }
+ }
+ // now convert the value
+ result.resize(binary.size());
+ for (unsigned j = 0; j < binary.size(); j++)
+ result.preset(binary.size() - j - 1, binary[j] == '1');
+ }
+ else
+ {
+ // now scan for a sign and find whether this is a negative number
+ bool negative = false;
+ if (i < str.size())
+ {
+ switch (str[i])
+ {
+ case '-':
+ negative = true;
+ i++;
+ break;
+ case '+':
+ i++;
+ break;
+ }
+ }
+ for (; i < str.size(); i++)
+ {
+ result *= inf(radix);
+ int ch = from_char[(unsigned char)str[i]] ;
+ if (ch == -1)
+ throw std::invalid_argument("invalid character in string " + str + " for radix " + unsigned_to_string(radix));
+ result += inf(ch);
+ }
+ if (negative)
+ result.negate();
+ }
+ return result;
+ }
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
+
+#endif